From b4e70d9101df4ded16c7c95ee2067c0ee4ba373c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 25 Mar 2016 21:16:53 -0700 Subject: [PATCH 001/115] WIP: checkpoint * bug fix in AABox::operator+= * added AABox::emiggen * Avatar now has a default bound for it's skinned mesh. * WIP: AABox tests; NEED MORE * Model: split collision and model mesh render items. Because ModelMeshRenderItems need special handling to update bounds for animated joints. * Model: dynamically update the bound for rigidly bound animated meshes * Rig: added access to geometryToRigTransform * RenderableModelEntityItem: try to update bounds for skinned mesh to be the entity dimentions (this doesn't seem to be working) * Geometry.cpp: removed unused bounds parameter in evalPartBounds * ModelMeshPartPayload: bounds updating * non-animated: use existing _localBound * rigid bound mesh: use _localBound transformed by clusterMatrix joint transform * fully skinned mesh: use _skinnedMeshBound provided by the application. --- interface/src/avatar/Avatar.cpp | 3 + libraries/animation/src/Rig.h | 2 + .../src/RenderableModelEntityItem.cpp | 4 + libraries/model/src/model/Geometry.cpp | 2 +- libraries/model/src/model/Geometry.h | 4 +- .../render-utils/src/MeshPartPayload.cpp | 64 ++++++--- libraries/render-utils/src/MeshPartPayload.h | 20 ++- libraries/render-utils/src/Model.cpp | 125 ++++++++++++++---- libraries/render-utils/src/Model.h | 15 ++- libraries/shared/src/AABox.cpp | 31 ++++- libraries/shared/src/AABox.h | 5 +- tests/shared/src/AABoxTests.cpp | 12 ++ tests/shared/src/AABoxTests.h | 1 + 13 files changed, 229 insertions(+), 59 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f722210a8e..24e786caa2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -56,6 +56,8 @@ const float DISPLAYNAME_ALPHA = 1.0f; const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); +const AABox DEFAULT_AVATAR_SKINNED_MESH_BOUND(glm::vec3(-1.0, -1.0, -1.0), glm::vec3(2.0f)); + namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { return ItemKey::Builder::opaqueShape(); @@ -101,6 +103,7 @@ Avatar::Avatar(RigPointer rig) : _headData = static_cast(new Head(this)); _skeletonModel = std::make_shared(this, nullptr, rig); + _skeletonModel->setSkinnedMeshBound(DEFAULT_AVATAR_SKINNED_MESH_BOUND); } Avatar::~Avatar() { diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 1f9a02d8ab..3a27b9304b 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -221,6 +221,8 @@ public: void setEnableInverseKinematics(bool enable); + const glm::mat4& getGeometryToRigTransform() const { return _geometryToRigTransform; } + protected: bool isIndexValid(int index) const { return _animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints(); } void updateAnimationStateHandlers(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 312e1fcea5..e0d6c90758 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -54,6 +54,8 @@ void RenderableModelEntityItem::setModelURL(const QString& url) { // Here we reset those guards. This doesn't cause the entity values to change -- it just allows the model to match once it comes in. _model->setScaleToFit(false, getDimensions()); _model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); + AABox skinnedMeshBound(getPosition() - getDimensions() * getRegistrationPoint(), getDimensions()); + _model->setSkinnedMeshBound(skinnedMeshBound); } ModelEntityItem::setModelURL(url); @@ -76,6 +78,8 @@ void RenderableModelEntityItem::loader() { if (_model) { _model->setURL(getParsedModelURL()); _model->setCollisionModelURL(QUrl(getCompoundShapeURL())); + AABox skinnedMeshBound(getPosition() - getDimensions() * getRegistrationPoint(), getDimensions()); + _model->setSkinnedMeshBound(skinnedMeshBound); } } diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index df86ba2a8f..1c4072b6f3 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -111,7 +111,7 @@ Box Mesh::evalPartBound(int partNum) const { return box; } -Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const { +Box Mesh::evalPartBounds(int partStart, int partEnd) const { Box totalBound; auto part = _partBuffer.cbegin() + partStart; auto partItEnd = _partBuffer.cbegin() + partEnd; diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index f9d9b0eeb4..b8873dba17 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -108,9 +108,9 @@ public: // evaluate the bounding box of A part Box evalPartBound(int partNum) const; - // evaluate the bounding boxes of the parts in the range [start, end[ and fill the bounds parameter + // evaluate the bounding boxes of the parts in the range [start, end] // the returned box is the bounding box of ALL the evaluated part bounds. - Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const; + Box evalPartBounds(int partStart, int partEnd) const; static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast(topo); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 363def05a1..482d630cdb 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -52,17 +52,6 @@ MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model:: updateTransform(transform, offsetTransform); } -void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) { - _drawMesh = drawMesh; - if (_drawMesh) { - auto vertexFormat = _drawMesh->getVertexFormat(); - _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); - _drawPart = _drawMesh->getPartBuffer().get(partIndex); - - _localBound = _drawMesh->evalPartBound(partIndex); - } -} - void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) { _transform = transform; _offsetTransform = offsetTransform; @@ -71,6 +60,16 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor _worldBound.transform(_drawTransform); } +void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) { + _drawMesh = drawMesh; + if (_drawMesh) { + auto vertexFormat = _drawMesh->getVertexFormat(); + _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); + _drawPart = _drawMesh->getPartBuffer().get(partIndex); + _localBound = _drawMesh->evalPartBound(partIndex); + } +} + void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; } @@ -316,10 +315,13 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } } -ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : +ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, + const Transform& offsetTransform, const AABox& skinnedMeshBound) : _model(model), _meshIndex(_meshIndex), - _shapeID(shapeIndex) { + _shapeID(shapeIndex), + _skinnedMeshBound(skinnedMeshBound) { + auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh; updateMeshPart(modelMesh, partIndex); @@ -351,6 +353,36 @@ void ModelMeshPartPayload::notifyLocationChanged() { _model->_needsUpdateClusterMatrices = true; } +void ModelMeshPartPayload::updateTransformForRigidlyBoundMesh(const Transform& transform, const Transform& clusterTransform, const Transform& offsetTransform) { + ModelMeshPartPayload::updateTransform(transform, offsetTransform); + + // clusterMatrix has world rotation but not world translation. + Transform worldTranslation, geomToWorld; + worldTranslation.setTranslation(transform.getTranslation()); + Transform::mult(geomToWorld, worldTranslation, clusterTransform); + + // transform the localBound into world space + _worldBound = _localBound; + _worldBound.transform(geomToWorld); +} + +void ModelMeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) { + _drawMesh = drawMesh; + if (_drawMesh) { + auto vertexFormat = _drawMesh->getVertexFormat(); + _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); + _drawPart = _drawMesh->getPartBuffer().get(partIndex); + + // this is a skinned mesh.. + if (vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX)) { + // use the specified skinned bounding box. + _localBound = _skinnedMeshBound; + } else { + _localBound = _drawMesh->evalPartBound(partIndex); + } + } +} + ItemKey ModelMeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -373,12 +405,6 @@ ItemKey ModelMeshPartPayload::getKey() const { return builder.build(); } -Item::Bound ModelMeshPartPayload::getBound() const { - // NOTE: we can't cache this bounds because we need to handle the case of a moving - // entity or mesh part. - return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation()); -} - ShapeKey ModelMeshPartPayload::getShapeKey() const { const FBXGeometry& geometry = _model->_geometry->getFBXGeometry(); const std::vector>& networkMeshes = _model->_geometry->getMeshes(); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index feccf7ee64..0aadf9baf8 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -64,6 +64,7 @@ public: bool _hasColorAttrib = false; }; + namespace render { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); @@ -73,16 +74,18 @@ namespace render { class ModelMeshPartPayload : public MeshPartPayload { public: - ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); - + ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, + const Transform& offsetTransform, const AABox& skinnedMeshBound); + typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - void notifyLocationChanged() override; + virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex) override; + virtual void notifyLocationChanged() override; + void updateTransformForRigidlyBoundMesh(const Transform& transform, const Transform& jointTransform, const Transform& offsetTransform); // Render Item interface render::ItemKey getKey() const override; - render::Item::Bound getBound() const override; render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) const override; @@ -99,6 +102,15 @@ public: bool _isSkinned{ false }; bool _isBlendShaped{ false }; + + AABox _skinnedMeshBound; }; +namespace render { + template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload); + template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload); + template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); + template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); +} + #endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0a483914df..e47f8caf65 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -102,6 +102,7 @@ void Model::setRotation(const glm::quat& rotation) { void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); + // if anyone sets scale manually, then we are no longer scaled to fit _scaleToFit = false; _scaledToFit = false; @@ -130,22 +131,46 @@ void Model::setOffset(const glm::vec3& offset) { void Model::enqueueLocationChange() { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - Transform transform; - transform.setTranslation(_translation); - transform.setRotation(_rotation); + Transform modelTransform; + modelTransform.setScale(_scale); + modelTransform.setTranslation(_translation); + modelTransform.setRotation(_rotation); Transform offset; - offset.setScale(_scale); - offset.postTranslate(_offset); + if (_geometry && _geometry->isLoaded()) { + offset = Transform(_rig->getGeometryToRigTransform()); + } else { + offset.postTranslate(_offset); + } render::PendingChanges pendingChanges; - foreach (auto itemID, _renderItems.keys()) { - pendingChanges.updateItem(itemID, [transform, offset](MeshPartPayload& data) { - data.updateTransform(transform, offset); + foreach (auto itemID, _modelMeshRenderItems.keys()) { + pendingChanges.updateItem(itemID, [modelTransform, offset](ModelMeshPartPayload& data) { + //data._model->updateClusterMatrices(data._transform.getTranslation(), data._transform.getRotation()); + const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); + if (state.clusterBuffer) { + data.updateTransform(modelTransform, offset); + } else { + // HACK: check for bugs... + AnimPose clusterMat(state.clusterMatrices[0]); + + Transform xform; + xform.setScale(clusterMat.scale); + xform.setRotation(clusterMat.rot); + xform.setTranslation(clusterMat.trans); + data.updateTransformForRigidlyBoundMesh(modelTransform, xform, offset); + } data.notifyLocationChanged(); }); } + foreach (auto itemID, _collisionRenderItems.keys()) { + pendingChanges.updateItem(itemID, [modelTransform, offset](MeshPartPayload& data) { + data.updateTransform(modelTransform, offset); + data.notifyLocationChanged(); + }); + } + scene->enqueuePendingChanges(pendingChanges); } @@ -497,8 +522,11 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen _isVisible = newValue; render::PendingChanges pendingChanges; - foreach (auto item, _renderItems.keys()) { - pendingChanges.resetItem(item, _renderItems[item]); + foreach (auto item, _modelMeshRenderItems.keys()) { + pendingChanges.resetItem(item, _modelMeshRenderItems[item]); + } + foreach (auto item, _collisionRenderItems.keys()) { + pendingChanges.resetItem(item, _modelMeshRenderItems[item]); } scene->enqueuePendingChanges(pendingChanges); } @@ -514,14 +542,25 @@ bool Model::addToScene(std::shared_ptr scene, render::PendingChan bool somethingAdded = false; - foreach (auto renderItem, _renderItemsSet) { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + pendingChanges.resetItem(item, renderPayload); + pendingChanges.updateItem(item, [](ModelMeshPartPayload& data) { + data.notifyLocationChanged(); + }); + _modelMeshRenderItems.insert(item, renderPayload); + somethingAdded = true; + } + + foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); pendingChanges.resetItem(item, renderPayload); pendingChanges.updateItem(item, [](MeshPartPayload& data) { data.notifyLocationChanged(); }); - _renderItems.insert(item, renderPayload); + _collisionRenderItems.insert(item, renderPayload); somethingAdded = true; } @@ -541,7 +580,19 @@ bool Model::addToScene(std::shared_ptr scene, bool somethingAdded = false; - foreach (auto renderItem, _renderItemsSet) { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + renderPayload->addStatusGetters(statusGetters); + pendingChanges.resetItem(item, renderPayload); + pendingChanges.updateItem(item, [](ModelMeshPartPayload& data) { + data.notifyLocationChanged(); + }); + _modelMeshRenderItems.insert(item, renderPayload); + somethingAdded = true; + } + + foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); renderPayload->addStatusGetters(statusGetters); @@ -549,7 +600,7 @@ bool Model::addToScene(std::shared_ptr scene, pendingChanges.updateItem(item, [](MeshPartPayload& data) { data.notifyLocationChanged(); }); - _renderItems.insert(item, renderPayload); + _collisionRenderItems.insert(item, renderPayload); somethingAdded = true; } @@ -559,11 +610,16 @@ bool Model::addToScene(std::shared_ptr scene, } void Model::removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges) { - foreach (auto item, _renderItems.keys()) { + foreach (auto item, _modelMeshRenderItems.keys()) { pendingChanges.removeItem(item); } - _renderItems.clear(); - _renderItemsSet.clear(); + _modelMeshRenderItems.clear(); + _modelMeshRenderItemsSet.clear(); + foreach (auto item, _collisionRenderItems.keys()) { + pendingChanges.removeItem(item); + } + _collisionRenderItems.clear(); + _collisionRenderItemsSet.clear(); _meshGroupsKnown = false; _readyWhenAdded = false; } @@ -1191,10 +1247,14 @@ void Model::segregateMeshGroups() { return; } - Q_ASSERT(_renderItems.isEmpty()); // We should not have any existing renderItems if we enter this section of code - Q_ASSERT(_renderItemsSet.isEmpty()); // We should not have any existing renderItemsSet if we enter this section of code + // We should not have any existing renderItems if we enter this section of code + Q_ASSERT(_modelMeshRenderItems.isEmpty()); + Q_ASSERT(_modelMeshRenderItemsSet.isEmpty()); + Q_ASSERT(_collisionRenderItems.isEmpty()); + Q_ASSERT(_collisionRenderItemsSet.isEmpty()); - _renderItemsSet.clear(); + _modelMeshRenderItemsSet.clear(); + _collisionRenderItemsSet.clear(); Transform transform; transform.setTranslation(_translation); @@ -1220,9 +1280,14 @@ void Model::segregateMeshGroups() { _collisionHullMaterial->setMetallic(0.02f); _collisionHullMaterial->setRoughness(0.5f); } - _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); + _collisionRenderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); } else { - _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); + AABox geometrySkinnedMeshBound = _skinnedMeshBound; + + // transform bound from model into geometry space. + geometrySkinnedMeshBound.transform(Transform(glm::inverse(_rig->getGeometryToRigTransform()))); + + _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset, geometrySkinnedMeshBound); } shapeID++; @@ -1245,13 +1310,21 @@ bool Model::initWhenReady(render::ScenePointer scene) { offset.setScale(_scale); offset.postTranslate(_offset); - foreach (auto renderItem, _renderItemsSet) { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + _modelMeshRenderItems.insert(item, renderPayload); + pendingChanges.resetItem(item, renderPayload); + pendingChanges.updateItem(item, [transform, offset](MeshPartPayload& data) { + data.notifyLocationChanged(); + }); + } + foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - _renderItems.insert(item, renderPayload); + _collisionRenderItems.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); - pendingChanges.updateItem(item, [transform,offset](MeshPartPayload& data) { - data.updateTransform(transform, offset); + pendingChanges.updateItem(item, [transform, offset](MeshPartPayload& data) { data.notifyLocationChanged(); }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4e51dc4f33..019795f116 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -44,6 +44,7 @@ namespace render { typedef unsigned int ItemID; } class MeshPartPayload; +class ModelMeshPartPayload; class ModelRenderLocations; inline uint qHash(const std::shared_ptr& a, uint seed) { @@ -222,6 +223,9 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } + // bounding box used for mesh that is influnced by multiple animated bones. + void setSkinnedMeshBound(const AABox& skinnedMeshBound) { _skinnedMeshBound = skinnedMeshBound; } + protected: void setPupilDilation(float dilation) { _pupilDilation = dilation; } @@ -371,8 +375,12 @@ protected: bool _renderCollisionHull; - QSet> _renderItemsSet; - QMap _renderItems; + QSet> _collisionRenderItemsSet; + QMap _collisionRenderItems; + + QSet> _modelMeshRenderItemsSet; + QMap _modelMeshRenderItems; + bool _readyWhenAdded { false }; bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; @@ -382,6 +390,9 @@ protected: friend class ModelMeshPartPayload; RigPointer _rig; + + // 2 meter^3 box + AABox _skinnedMeshBound { glm::vec3(-1.0, -1.0, -1.0), glm::vec3(2.0f) }; }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index 0b453e6f36..786ef40257 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -17,6 +17,8 @@ #include "GeometryUtil.h" #include "NumericalConstants.h" +const glm::vec3 INFINITY_VECTOR(std::numeric_limits::infinity()); + AABox::AABox(const AACube& other) : _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) { } @@ -34,7 +36,7 @@ AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) : _corner(corner), _scale(dimensions) { }; -AABox::AABox() : _corner(std::numeric_limits::infinity()), _scale(0.0f) { +AABox::AABox() : _corner(INFINITY_VECTOR), _scale(0.0f) { }; glm::vec3 AABox::calcCenter() const { @@ -475,8 +477,15 @@ AABox AABox::clamp(float min, float max) const { } AABox& AABox::operator += (const glm::vec3& point) { - _corner = glm::min(_corner, point); - _scale = glm::max(_scale, point - _corner); + + if (_corner == INFINITY_VECTOR) { + _corner = glm::min(_corner, point); + } else { + glm::vec3 maximum(_corner + _scale); + _corner = glm::min(_corner, point); + maximum = glm::max(maximum, point); + _scale = maximum - _corner; + } return (*this); } @@ -489,11 +498,25 @@ AABox& AABox::operator += (const AABox& box) { return (*this); } -void AABox::scale(const glm::vec3& scale) { +void AABox::embiggen(float scale) { + _corner += scale * (-0.5f * _scale); + _scale *= scale; +} + +void AABox::embiggen(const glm::vec3& scale) { + _corner += scale * (-0.5f * _scale); + _scale *= scale; +} + +void AABox::scale(float scale) { _corner *= scale; _scale *= scale; } +void AABox::scale(const glm::vec3& scale) { + _corner *= scale; + _scale *= scale; +} void AABox::rotate(const glm::quat& rotation) { auto minimum = _corner; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index ec06c60121..000d4be734 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -58,7 +58,6 @@ public: const glm::vec3& getMinimumPoint() const { return _corner; } glm::vec3 getMaximumPoint() const { return calcTopFarLeft(); } - bool contains(const glm::vec3& point) const; bool contains(const AABox& otherBox) const; bool touches(const AABox& otherBox) const; @@ -93,6 +92,10 @@ public: void scale(float scale); void scale(const glm::vec3& scale); + /// make the AABox bigger (scale about it's center) + void embiggen(float scale); + void embiggen(const glm::vec3& scale); + // Transform the extents with transform void transform(const Transform& transform); diff --git a/tests/shared/src/AABoxTests.cpp b/tests/shared/src/AABoxTests.cpp index fd709a488c..41f05616c4 100644 --- a/tests/shared/src/AABoxTests.cpp +++ b/tests/shared/src/AABoxTests.cpp @@ -151,3 +151,15 @@ void AABoxTests::testTouchesSphere() { } } +void AABoxTests::testScale() { + AABox box(glm::vec3(2.0f), glm::vec3(1.0f)); + QCOMPARE(box.contains(glm::vec3(0.0f)), false); + box.scale(glm::vec3(10.0f)); + QCOMPARE(box.contains(glm::vec3(0.0f)), false); + QCOMPARE(box.contains(glm::vec3(2.0f * 10.0f)), true); + + AABox box(glm::vec3(2.0f), glm::vec3(1.0f)); + QCOMPARE(box.contains(glm::vec3(0.0f)), false); + box.embiggen(glm::vec3(10.0f)); + QCOMPARE(box.contains(glm::vec3(0.0f)), false); +} diff --git a/tests/shared/src/AABoxTests.h b/tests/shared/src/AABoxTests.h index fe7afede57..c777f8e94f 100644 --- a/tests/shared/src/AABoxTests.h +++ b/tests/shared/src/AABoxTests.h @@ -23,6 +23,7 @@ private slots: void testCtorsAndSetters(); void testContainsPoint(); void testTouchesSphere(); + void testScale(); }; #endif // hifi_AABoxTests_h From bf433487fadac3b94187ac54ff9432d8ef689a49 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sat, 26 Mar 2016 12:09:36 -0700 Subject: [PATCH 002/115] Dynamic bound update for skinned mesh * Use all cluster matrices to compute bound for skinned mesh. This is far less expensive then doing per-vertex work, but it's not free, for avatars especially. * Remove skinnedMeshBound, compute it instead. * Compute clusterMatrices in render update, because we need them to update bounds. --- interface/src/avatar/Avatar.cpp | 1 - .../src/RenderableModelEntityItem.cpp | 4 -- .../render-utils/src/MeshPartPayload.cpp | 38 +++++--------- libraries/render-utils/src/MeshPartPayload.h | 7 +-- libraries/render-utils/src/Model.cpp | 25 +++------- libraries/render-utils/src/Model.h | 6 --- libraries/shared/src/AABox.cpp | 50 +++++++++++++++++-- libraries/shared/src/AABox.h | 7 ++- 8 files changed, 73 insertions(+), 65 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 24e786caa2..07227d2f68 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -103,7 +103,6 @@ Avatar::Avatar(RigPointer rig) : _headData = static_cast(new Head(this)); _skeletonModel = std::make_shared(this, nullptr, rig); - _skeletonModel->setSkinnedMeshBound(DEFAULT_AVATAR_SKINNED_MESH_BOUND); } Avatar::~Avatar() { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e0d6c90758..312e1fcea5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -54,8 +54,6 @@ void RenderableModelEntityItem::setModelURL(const QString& url) { // Here we reset those guards. This doesn't cause the entity values to change -- it just allows the model to match once it comes in. _model->setScaleToFit(false, getDimensions()); _model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); - AABox skinnedMeshBound(getPosition() - getDimensions() * getRegistrationPoint(), getDimensions()); - _model->setSkinnedMeshBound(skinnedMeshBound); } ModelEntityItem::setModelURL(url); @@ -78,8 +76,6 @@ void RenderableModelEntityItem::loader() { if (_model) { _model->setURL(getParsedModelURL()); _model->setCollisionModelURL(QUrl(getCompoundShapeURL())); - AABox skinnedMeshBound(getPosition() - getDimensions() * getRegistrationPoint(), getDimensions()); - _model->setSkinnedMeshBound(skinnedMeshBound); } } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 482d630cdb..bfa6c48857 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -316,11 +316,10 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, - const Transform& offsetTransform, const AABox& skinnedMeshBound) : + const Transform& offsetTransform) : _model(model), _meshIndex(_meshIndex), - _shapeID(shapeIndex), - _skinnedMeshBound(skinnedMeshBound) { + _shapeID(shapeIndex) { auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh; updateMeshPart(modelMesh, partIndex); @@ -353,33 +352,20 @@ void ModelMeshPartPayload::notifyLocationChanged() { _model->_needsUpdateClusterMatrices = true; } -void ModelMeshPartPayload::updateTransformForRigidlyBoundMesh(const Transform& transform, const Transform& clusterTransform, const Transform& offsetTransform) { +void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const glm::mat4* clusterMatrices, size_t numClusterMatrices) { ModelMeshPartPayload::updateTransform(transform, offsetTransform); - // clusterMatrix has world rotation but not world translation. - Transform worldTranslation, geomToWorld; - worldTranslation.setTranslation(transform.getTranslation()); - Transform::mult(geomToWorld, worldTranslation, clusterTransform); + if (numClusterMatrices > 0) { - // transform the localBound into world space - _worldBound = _localBound; - _worldBound.transform(geomToWorld); -} - -void ModelMeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) { - _drawMesh = drawMesh; - if (_drawMesh) { - auto vertexFormat = _drawMesh->getVertexFormat(); - _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); - _drawPart = _drawMesh->getPartBuffer().get(partIndex); - - // this is a skinned mesh.. - if (vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX)) { - // use the specified skinned bounding box. - _localBound = _skinnedMeshBound; - } else { - _localBound = _drawMesh->evalPartBound(partIndex); + _worldBound = AABox(); + for (size_t i = 0; i < numClusterMatrices; i++) { + AABox clusterBound = _localBound; + clusterBound.transform(clusterMatrices[i]); + _worldBound += clusterBound; } + + // clusterMatrix has world rotation but not world translation. + _worldBound.translate(transform.getTranslation()); } } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 0aadf9baf8..7b059afadd 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -75,14 +75,13 @@ namespace render { class ModelMeshPartPayload : public MeshPartPayload { public: ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, - const Transform& offsetTransform, const AABox& skinnedMeshBound); + const Transform& offsetTransform); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex) override; virtual void notifyLocationChanged() override; - void updateTransformForRigidlyBoundMesh(const Transform& transform, const Transform& jointTransform, const Transform& offsetTransform); + void updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const glm::mat4* clusterMatrices, size_t numClusterMatrices); // Render Item interface render::ItemKey getKey() const override; @@ -102,8 +101,6 @@ public: bool _isSkinned{ false }; bool _isBlendShaped{ false }; - - AABox _skinnedMeshBound; }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index e47f8caf65..b463a80403 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -146,20 +146,12 @@ void Model::enqueueLocationChange() { render::PendingChanges pendingChanges; foreach (auto itemID, _modelMeshRenderItems.keys()) { pendingChanges.updateItem(itemID, [modelTransform, offset](ModelMeshPartPayload& data) { - //data._model->updateClusterMatrices(data._transform.getTranslation(), data._transform.getRotation()); - const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - if (state.clusterBuffer) { - data.updateTransform(modelTransform, offset); - } else { - // HACK: check for bugs... - AnimPose clusterMat(state.clusterMatrices[0]); - Transform xform; - xform.setScale(clusterMat.scale); - xform.setRotation(clusterMat.rot); - xform.setTranslation(clusterMat.trans); - data.updateTransformForRigidlyBoundMesh(modelTransform, xform, offset); - } + data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); + const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); + size_t numClusterMatrices = data._model->getGeometry()->getFBXGeometry().meshes.at(data._meshIndex).clusters.size(); + + data.updateTransformForSkinnedMesh(modelTransform, offset, &state.clusterMatrices[0], numClusterMatrices); data.notifyLocationChanged(); }); } @@ -1282,12 +1274,7 @@ void Model::segregateMeshGroups() { } _collisionRenderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); } else { - AABox geometrySkinnedMeshBound = _skinnedMeshBound; - - // transform bound from model into geometry space. - geometrySkinnedMeshBound.transform(Transform(glm::inverse(_rig->getGeometryToRigTransform()))); - - _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset, geometrySkinnedMeshBound); + _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); } shapeID++; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 019795f116..d9eb20cb32 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -223,9 +223,6 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } - // bounding box used for mesh that is influnced by multiple animated bones. - void setSkinnedMeshBound(const AABox& skinnedMeshBound) { _skinnedMeshBound = skinnedMeshBound; } - protected: void setPupilDilation(float dilation) { _pupilDilation = dilation; } @@ -390,9 +387,6 @@ protected: friend class ModelMeshPartPayload; RigPointer _rig; - - // 2 meter^3 box - AABox _skinnedMeshBound { glm::vec3(-1.0, -1.0, -1.0), glm::vec3(2.0f) }; }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index 786ef40257..a3afa220c9 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -17,7 +17,7 @@ #include "GeometryUtil.h" #include "NumericalConstants.h" -const glm::vec3 INFINITY_VECTOR(std::numeric_limits::infinity()); +const glm::vec3 AABox::INFINITY_VECTOR(std::numeric_limits::infinity()); AABox::AABox(const AACube& other) : _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) { @@ -478,7 +478,7 @@ AABox AABox::clamp(float min, float max) const { AABox& AABox::operator += (const glm::vec3& point) { - if (_corner == INFINITY_VECTOR) { + if (isInvalid()) { _corner = glm::min(_corner, point); } else { glm::vec3 maximum(_corner + _scale); @@ -493,7 +493,7 @@ AABox& AABox::operator += (const glm::vec3& point) { AABox& AABox::operator += (const AABox& box) { if (!box.isInvalid()) { (*this) += box._corner; - _scale = glm::max(_scale, box.calcTopFarLeft() - _corner); + (*this) += box.calcTopFarLeft(); } return (*this); } @@ -567,3 +567,47 @@ void AABox::transform(const Transform& transform) { rotate(transform.getRotation()); translate(transform.getTranslation()); } + +void AABox::transform(const glm::mat4& matrix) { + auto minimum = _corner; + auto maximum = _corner + _scale; + + glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z); + glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z); + glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z); + glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z); + glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z); + glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z); + glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z); + glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z); + + glm::vec3 bottomLeftNearTransformed = transformPoint(matrix, bottomLeftNear); + glm::vec3 bottomRightNearTransformed = transformPoint(matrix, bottomRightNear); + glm::vec3 bottomLeftFarTransformed = transformPoint(matrix, bottomLeftFar); + glm::vec3 bottomRightFarTransformed = transformPoint(matrix, bottomRightFar); + glm::vec3 topLeftNearTransformed = transformPoint(matrix, topLeftNear); + glm::vec3 topRightNearTransformed = transformPoint(matrix, topRightNear); + glm::vec3 topLeftFarTransformed = transformPoint(matrix, topLeftFar); + glm::vec3 topRightFarTransformed = transformPoint(matrix, topRightFar); + + minimum = glm::min(bottomLeftNearTransformed, + glm::min(bottomRightNearTransformed, + glm::min(bottomLeftFarTransformed, + glm::min(bottomRightFarTransformed, + glm::min(topLeftNearTransformed, + glm::min(topRightNearTransformed, + glm::min(topLeftFarTransformed, + topRightFarTransformed))))))); + + maximum = glm::max(bottomLeftNearTransformed, + glm::max(bottomRightNearTransformed, + glm::max(bottomLeftFarTransformed, + glm::max(bottomRightFarTransformed, + glm::max(topLeftNearTransformed, + glm::max(topRightNearTransformed, + glm::max(topLeftFarTransformed, + topRightFarTransformed))))))); + + _corner = minimum; + _scale = maximum - minimum; +} diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 000d4be734..30bde2d717 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -99,7 +99,12 @@ public: // Transform the extents with transform void transform(const Transform& transform); - bool isInvalid() const { return _corner == glm::vec3(std::numeric_limits::infinity()); } + // Transform the extents with matrix + void transform(const glm::mat4& matrix); + + static const glm::vec3 INFINITY_VECTOR; + + bool isInvalid() const { return _corner == INFINITY_VECTOR; } private: glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; From 49a4d104a69a316f9ed2cbc5954e61e4c2612f8d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sat, 26 Mar 2016 13:27:05 -0700 Subject: [PATCH 003/115] Minimize diff with master --- interface/src/avatar/Avatar.cpp | 2 -- .../render-utils/src/MeshPartPayload.cpp | 20 +++++++++---------- libraries/render-utils/src/MeshPartPayload.h | 6 ++---- libraries/render-utils/src/Model.cpp | 1 - 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 07227d2f68..f722210a8e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -56,8 +56,6 @@ const float DISPLAYNAME_ALPHA = 1.0f; const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); -const AABox DEFAULT_AVATAR_SKINNED_MESH_BOUND(glm::vec3(-1.0, -1.0, -1.0), glm::vec3(2.0f)); - namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { return ItemKey::Builder::opaqueShape(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index bfa6c48857..8d738e44d8 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -52,14 +52,6 @@ MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model:: updateTransform(transform, offsetTransform); } -void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) { - _transform = transform; - _offsetTransform = offsetTransform; - Transform::mult(_drawTransform, _transform, _offsetTransform); - _worldBound = _localBound; - _worldBound.transform(_drawTransform); -} - void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) { _drawMesh = drawMesh; if (_drawMesh) { @@ -70,6 +62,14 @@ void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) } } +void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) { + _transform = transform; + _offsetTransform = offsetTransform; + Transform::mult(_drawTransform, _transform, _offsetTransform); + _worldBound = _localBound; + _worldBound.transform(_drawTransform); +} + void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; } @@ -315,12 +315,10 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } } -ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, - const Transform& offsetTransform) : +ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : _model(model), _meshIndex(_meshIndex), _shapeID(shapeIndex) { - auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh; updateMeshPart(modelMesh, partIndex); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 7b059afadd..546c0938fa 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -64,7 +64,6 @@ public: bool _hasColorAttrib = false; }; - namespace render { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); @@ -74,13 +73,12 @@ namespace render { class ModelMeshPartPayload : public MeshPartPayload { public: - ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, - const Transform& offsetTransform); + ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void notifyLocationChanged() override; + void notifyLocationChanged() override; void updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const glm::mat4* clusterMatrices, size_t numClusterMatrices); // Render Item interface diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b463a80403..38b7aa2e89 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -102,7 +102,6 @@ void Model::setRotation(const glm::quat& rotation) { void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); - // if anyone sets scale manually, then we are no longer scaled to fit _scaleToFit = false; _scaledToFit = false; From c671fe796694dc216a88dc71e222ff2534021444 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Sat, 26 Mar 2016 13:36:56 -0700 Subject: [PATCH 004/115] Updated AABox tests --- tests/shared/src/AABoxTests.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/shared/src/AABoxTests.cpp b/tests/shared/src/AABoxTests.cpp index 41f05616c4..b9ab95bb09 100644 --- a/tests/shared/src/AABoxTests.cpp +++ b/tests/shared/src/AABoxTests.cpp @@ -152,14 +152,20 @@ void AABoxTests::testTouchesSphere() { } void AABoxTests::testScale() { - AABox box(glm::vec3(2.0f), glm::vec3(1.0f)); - QCOMPARE(box.contains(glm::vec3(0.0f)), false); - box.scale(glm::vec3(10.0f)); - QCOMPARE(box.contains(glm::vec3(0.0f)), false); - QCOMPARE(box.contains(glm::vec3(2.0f * 10.0f)), true); + AABox box1(glm::vec3(2.0f), glm::vec3(1.0f)); + QCOMPARE(box1.contains(glm::vec3(0.0f)), false); + box1.scale(glm::vec3(10.0f)); + QCOMPARE(box1.contains(glm::vec3(0.0f)), false); + QCOMPARE(box1.contains(glm::vec3(2.0f * 10.0f)), true); - AABox box(glm::vec3(2.0f), glm::vec3(1.0f)); - QCOMPARE(box.contains(glm::vec3(0.0f)), false); - box.embiggen(glm::vec3(10.0f)); - QCOMPARE(box.contains(glm::vec3(0.0f)), false); + AABox box2(glm::vec3(2.0f), glm::vec3(1.0f)); + QCOMPARE(box2.contains(glm::vec3(0.0f)), false); + box2.embiggen(glm::vec3(10.0f)); + QCOMPARE(box2.contains(glm::vec3(0.0f)), true); + + AABox box3; + box3 += glm::vec3(0.0f, 0.0f, 0.0f); + box3 += glm::vec3(1.0f, 1.0f, 1.0f); + box3 += glm::vec3(-1.0f, -1.0f, -1.0f); + QCOMPARE(box3.contains(glm::vec3(0.5f, 0.5f, 0.5f)), true); } From 5ac0640cbec29b4a4979360ddfe6e7e3c416de96 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 27 Mar 2016 16:33:53 -0700 Subject: [PATCH 005/115] check for time machine --- libraries/entities/src/ParticleEffectEntityItem.cpp | 6 ++++++ libraries/script-engine/src/ScriptEngine.cpp | 11 +++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 4b798cbcd9..02a86ab952 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -561,6 +561,12 @@ bool ParticleEffectEntityItem::needsToCallUpdate() const { void ParticleEffectEntityItem::update(const quint64& now) { + // we check for 'now' in the past in case users set their clock backward + if (now < _lastSimulated) { + _lastSimulated = now; + return; + } + float deltaTime = (float)(now - _lastSimulated) / (float)USECS_PER_SECOND; _lastSimulated = now; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 3f403b3677..a6541dc031 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -673,11 +673,14 @@ void ScriptEngine::run() { } qint64 now = usecTimestampNow(); - float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; - if (!_isFinished) { - if (_wantSignals) { - emit update(deltaTime); + // we check for 'now' in the past in case people set their clock back + if (lastUpdate < now) { + float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; + if (!_isFinished) { + if (_wantSignals) { + emit update(deltaTime); + } } } lastUpdate = now; From f5a86666a14a93667be7f21ed64c982240c341d5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 28 Mar 2016 09:56:15 -0700 Subject: [PATCH 006/115] Model: fix for collision mesh rendering --- libraries/render-utils/src/Model.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 38b7aa2e89..55aa000ef4 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -135,29 +135,33 @@ void Model::enqueueLocationChange() { modelTransform.setTranslation(_translation); modelTransform.setRotation(_rotation); - Transform offset; + Transform modelMeshOffset; if (_geometry && _geometry->isLoaded()) { - offset = Transform(_rig->getGeometryToRigTransform()); + modelMeshOffset = Transform(_rig->getGeometryToRigTransform()); } else { - offset.postTranslate(_offset); + modelMeshOffset.postTranslate(_offset); } + Transform collisionMeshOffset; + collisionMeshOffset.postTranslate(_offset); + + render::PendingChanges pendingChanges; foreach (auto itemID, _modelMeshRenderItems.keys()) { - pendingChanges.updateItem(itemID, [modelTransform, offset](ModelMeshPartPayload& data) { + pendingChanges.updateItem(itemID, [modelTransform, modelMeshOffset](ModelMeshPartPayload& data) { data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); size_t numClusterMatrices = data._model->getGeometry()->getFBXGeometry().meshes.at(data._meshIndex).clusters.size(); - data.updateTransformForSkinnedMesh(modelTransform, offset, &state.clusterMatrices[0], numClusterMatrices); + data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, &state.clusterMatrices[0], numClusterMatrices); data.notifyLocationChanged(); }); } foreach (auto itemID, _collisionRenderItems.keys()) { - pendingChanges.updateItem(itemID, [modelTransform, offset](MeshPartPayload& data) { - data.updateTransform(modelTransform, offset); + pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { + data.updateTransform(modelTransform, collisionMeshOffset); data.notifyLocationChanged(); }); } From de8153bd750fd447b5541638a61fc634f5d54d8f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 28 Mar 2016 12:23:23 -0700 Subject: [PATCH 007/115] on windows and osx use default scripts bundled with interface --- libraries/script-engine/src/ScriptEngines.cpp | 6 +++--- libraries/script-engine/src/ScriptsModel.cpp | 2 +- libraries/shared/src/PathUtils.cpp | 11 +++++++++++ libraries/shared/src/PathUtils.h | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index f95209d880..f005368dc4 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -13,13 +13,14 @@ #include #include +#include #include "ScriptEngine.h" #include "ScriptEngineLogging.h" #define __STR2__(x) #x #define __STR1__(x) __STR2__(x) -#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: " +#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: " #ifndef __APPLE__ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); @@ -213,10 +214,9 @@ QVariantList ScriptEngines::getRunning() { static const QString SETTINGS_KEY = "Settings"; -static const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; void ScriptEngines::loadDefaultScripts() { - loadScript(DEFAULT_SCRIPTS_JS_URL); + loadScript(defaultScriptsFileName()); } void ScriptEngines::loadOneScript(const QString& scriptFilename) { diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 37b2551f39..8b01c9fbed 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -21,7 +21,7 @@ #include "ScriptEngineLogging.h" #define __STR2__(x) #x #define __STR1__(x) __STR2__(x) -#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: " +#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: " static const QString S3_URL = "http://s3.amazonaws.com/hifi-public"; diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 79e83e9b40..94af26db6c 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -53,3 +53,14 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); +QString defaultScriptsFileName(); + #endif // hifi_PathUtils_h From e77cf544830713c26027275b8890deb2124b28fc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 28 Mar 2016 13:29:28 -0700 Subject: [PATCH 008/115] Geometry.cpp: rename method --- libraries/model/src/model/Geometry.cpp | 2 +- libraries/model/src/model/Geometry.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 1c4072b6f3..2bb6cfa436 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -111,7 +111,7 @@ Box Mesh::evalPartBound(int partNum) const { return box; } -Box Mesh::evalPartBounds(int partStart, int partEnd) const { +Box Mesh::evalPartsBound(int partStart, int partEnd) const { Box totalBound; auto part = _partBuffer.cbegin() + partStart; auto partItEnd = _partBuffer.cbegin() + partEnd; diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index b8873dba17..a3e95c68c0 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -109,8 +109,8 @@ public: // evaluate the bounding box of A part Box evalPartBound(int partNum) const; // evaluate the bounding boxes of the parts in the range [start, end] - // the returned box is the bounding box of ALL the evaluated part bounds. - Box evalPartBounds(int partStart, int partEnd) const; + // the returned box is the bounding box of ALL the evaluated parts bound. + Box evalPartsBound(int partStart, int partEnd) const; static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast(topo); } From c6347eb92a5950f4b8663993ef69cd92b62d4e91 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 28 Mar 2016 13:39:43 -0700 Subject: [PATCH 009/115] checkpoint for debugging/comparing edit.js --- .../src/entities/AssignmentParentFinder.cpp | 8 ++- .../src/entities/AssignmentParentFinder.h | 2 +- interface/src/Application.cpp | 62 +++++++++++++++---- interface/src/InterfaceParentFinder.cpp | 12 ++-- interface/src/InterfaceParentFinder.h | 2 +- libraries/entities/src/EntityTree.cpp | 11 +++- libraries/entities/src/EntityTree.h | 4 +- libraries/shared/src/SpatialParentFinder.h | 6 +- libraries/shared/src/SpatiallyNestable.cpp | 4 +- libraries/shared/src/SpatiallyNestable.h | 4 +- 10 files changed, 86 insertions(+), 29 deletions(-) diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp index 294556383e..a0232daff4 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.cpp +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -11,7 +11,7 @@ #include "AssignmentParentFinder.h" -SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID, bool& success) const { +SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID, bool& success, SpatialParentTree* entityTree) const { SpatiallyNestableWeakPointer parent; if (parentID.isNull()) { @@ -20,7 +20,11 @@ SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID, bool& } // search entities - parent = _tree->findEntityByEntityItemID(parentID); + if (entityTree) { + parent = entityTree->findByID(parentID); + } else { + parent = _tree->findEntityByEntityItemID(parentID); + } if (parent.expired()) { success = false; } else { diff --git a/assignment-client/src/entities/AssignmentParentFinder.h b/assignment-client/src/entities/AssignmentParentFinder.h index 9a776bc7dd..0c16143143 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.h +++ b/assignment-client/src/entities/AssignmentParentFinder.h @@ -25,7 +25,7 @@ class AssignmentParentFinder : public SpatialParentFinder { public: AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { } virtual ~AssignmentParentFinder() { } - virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success) const; + virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const; protected: EntityTreePointer _tree; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9bef698167..df08afcf64 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -270,7 +270,7 @@ public: void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); - +/* fixme uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us uint64_t now = usecTimestampNow(); auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; @@ -319,6 +319,7 @@ public: deadlockDetectionCrash(); } #endif + */ } } @@ -2790,43 +2791,78 @@ void Application::calibrateEyeTracker5Points() { } #endif +class EntityDatum { // For parent-first sorting and mapping. +public: + EntityItemPointer item; + EntityItemProperties properties; + EntityItemID originalParentID; + EntityItemID mappedID; + EntityDatum() {}; + EntityDatum(EntityItemPointer itemArg, EntityItemProperties propertiesArg, EntityItemID parentID) : + item(itemArg), properties(propertiesArg), originalParentID(parentID) { + }; +}; bool Application::exportEntities(const QString& filename, const QVector& entityIDs) { - QVector entities; + QHash entities; auto entityTree = getEntities()->getTree(); auto exportTree = std::make_shared(); exportTree->createRootElement(); glm::vec3 root(TREE_SCALE, TREE_SCALE, TREE_SCALE); - for (auto entityID : entityIDs) { + for (auto entityID : entityIDs) { // Gather entities and properties. auto entityItem = entityTree->findEntityByEntityItemID(entityID); if (!entityItem) { + qCDebug(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; continue; } auto properties = entityItem->getProperties(); - auto position = properties.getPosition(); - + auto position = properties.getPosition(); // see setPosition, below. root.x = glm::min(root.x, position.x); root.y = glm::min(root.y, position.y); root.z = glm::min(root.z, position.z); - entities << entityItem; + qCDebug(interfaceapp) << "Exporting" << entityItem->getEntityItemID() << entityItem->getName(); + entities[entityID] = EntityDatum(entityItem, properties, properties.getParentID()); } if (entities.size() == 0) { return false; } - for (auto entityItem : entities) { - auto properties = entityItem->getProperties(); + for (EntityDatum& entityDatum : entities) { + // Recursively add the parents of entities to the exportTree, mapping their new identifiers as we go. + std::function getMapped = [&](EntityDatum& datum) { + auto originalID = datum.item->getEntityItemID(); + if (!datum.mappedID.isInvalidID()) { + qCDebug(interfaceapp) << "already mapped" << datum.properties.getName() << originalID << "=>" << datum.mappedID; + return datum.mappedID; // We are a parent that has already been added/mapped. + } + auto properties = datum.properties; + auto parentID = datum.originalParentID; + if (!datum.originalParentID.isInvalidID()) { // Recurse over ancestors, updating properties. + qCDebug(interfaceapp) << "FIXME recursing" << datum.originalParentID << "parent of" << datum.item->getEntityItemID(); + // Warning: this is not a tail-call, so exporting a REALLY deep parent hierarchy will blow the call stack. + parentID = getMapped(entities[parentID]); + properties.setParentID(parentID); + } + // The so-called root offset (which isn't) is confusing and not what content developers want. And why would queryAACube not then be offset? + // But leaving it in for bug-compatibility right now. -HRS + properties.setPosition(properties.getPosition() - root); + datum.mappedID = originalID; //EntityItemID(QUuid::createUuid()); + auto newEntity = exportTree->addEntity(datum.mappedID, properties); + qCDebug(interfaceapp) << "mapped" << properties.getName(); + qCDebug(interfaceapp) << " " << originalID << "p:" << datum.originalParentID; + qCDebug(interfaceapp) << " =>" << datum.mappedID << "p:" << parentID; - properties.setPosition(properties.getPosition() - root); - exportTree->addEntity(entityItem->getEntityItemID(), properties); + return datum.mappedID; + }; + + getMapped(entityDatum); } - // remap IDs on export so that we aren't publishing the IDs of entities in our domain - exportTree->remapIDs(); + //exportTree->remapIDs(); exportTree->writeToJSONFile(filename.toLocal8Bit().constData()); @@ -2902,7 +2938,7 @@ bool Application::importEntities(const QString& urlOrFilename) { bool success = _entityClipboard->readFromURL(url.toString()); if (success) { - _entityClipboard->remapIDs(); + // FIXME _entityClipboard->remapIDs(); _entityClipboard->reaverageOctreeElements(); } return success; diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp index de4b0ce38c..b1db63debd 100644 --- a/interface/src/InterfaceParentFinder.cpp +++ b/interface/src/InterfaceParentFinder.cpp @@ -16,7 +16,7 @@ #include "InterfaceParentFinder.h" -SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success) const { +SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success, SpatialParentTree* entityTree) const { SpatiallyNestableWeakPointer parent; if (parentID.isNull()) { @@ -25,9 +25,13 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& s } // search entities - EntityTreeRenderer* treeRenderer = qApp->getEntities(); - EntityTreePointer tree = treeRenderer ? treeRenderer->getTree() : nullptr; - parent = tree ? tree->findEntityByEntityItemID(parentID) : nullptr; + if (entityTree) { + parent = entityTree->findByID(parentID); + } else { + EntityTreeRenderer* treeRenderer = qApp->getEntities(); + EntityTreePointer tree = treeRenderer ? treeRenderer->getTree() : nullptr; + parent = tree ? tree->findEntityByEntityItemID(parentID) : nullptr; + } if (!parent.expired()) { success = true; return parent; diff --git a/interface/src/InterfaceParentFinder.h b/interface/src/InterfaceParentFinder.h index db579c2144..a2e9fb50e4 100644 --- a/interface/src/InterfaceParentFinder.h +++ b/interface/src/InterfaceParentFinder.h @@ -21,7 +21,7 @@ class InterfaceParentFinder : public SpatialParentFinder { public: InterfaceParentFinder() { } virtual ~InterfaceParentFinder() { } - virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success) const; + virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const; }; #endif // hifi_InterfaceParentFinder_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index af1c2e71aa..ef7af3da86 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1009,6 +1009,7 @@ void EntityTree::entityChanged(EntityItemPointer entity) { void EntityTree::fixupMissingParents() { MovingEntitiesOperator moveOperator(getThisPointer()); + if (!_missingParent.empty()) qCDebug(entities) << "HRS fixme fixupMissingParents" << _missingParent.count() << "entities"; QMutableVectorIterator iter(_missingParent); while (iter.hasNext()) { EntityItemWeakPointer entityWP = iter.next(); @@ -1027,6 +1028,7 @@ void EntityTree::fixupMissingParents() { bool doMove = false; if (entity->isParentIDValid()) { + qCDebug(entities) << "HRS fixme valid parent" << entity->getEntityItemID() << queryAACubeSuccess; // this entity's parent was previously not known, and now is. Update its location in the EntityTree... doMove = true; } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { @@ -1038,6 +1040,7 @@ void EntityTree::fixupMissingParents() { _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; } + else qCDebug(entities) << "HRS fixme failed parent" << entity->getEntityItemID() << queryAACubeSuccess; if (queryAACubeSuccess && doMove) { moveOperator.addEntityToMoveList(entity, newCube); @@ -1328,19 +1331,22 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen } bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) { + qCDebug(entities) << "sendEntitiesOperation"; SendEntitiesOperationArgs* args = static_cast(extraData); EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - EntityItemID newID(QUuid::createUuid()); + EntityItemID newID = entityItem->getEntityItemID(); // FIXME (QUuid::createUuid()); args->newEntityIDs->append(newID); EntityItemProperties properties = entityItem->getProperties(); properties.setPosition(properties.getPosition() + args->root); properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity + qCDebug(entities) << "sending" << newID << properties.getName() << "parent:" << properties.getParentID(); // queue the packet to send to the server args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, newID, properties); // also update the local tree instantly (note: this is not our tree, but an alternate tree) + // [Sure looks like the global application's tree to me. See callers. -HRS] if (args->localTree) { args->localTree->withWriteLock([&] { args->localTree->addEntity(newID, properties); @@ -1389,11 +1395,12 @@ bool EntityTree::readFromMap(QVariantMap& map) { } EntityItemPointer entity = addEntity(entityItemID, properties); + qCDebug(entities) << "HRS FIXME added" << entityItemID << properties.getName(); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); } } - + qCDebug(entities) << "HRS FIXME end of readFromMap"; return true; } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 0b85c5f32f..8cf6a7e45b 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -16,6 +16,7 @@ #include #include +#include class EntityTree; typedef std::shared_ptr EntityTreePointer; @@ -52,7 +53,7 @@ public: }; -class EntityTree : public Octree { +class EntityTree : public Octree, public SpatialParentTree { Q_OBJECT public: EntityTree(bool shouldReaverage = false); @@ -125,6 +126,7 @@ public: EntityItemPointer findClosestEntity(glm::vec3 position, float targetRadius); EntityItemPointer findEntityByID(const QUuid& id); EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID); + SpatiallyNestablePointer EntityTree::findByID(const QUuid& id) { return findEntityByID(id); } EntityItemID assignEntityID(const EntityItemID& entityItemID); /// Assigns a known ID for a creator token ID diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h index 9b49490fa5..ff2593c621 100644 --- a/libraries/shared/src/SpatialParentFinder.h +++ b/libraries/shared/src/SpatialParentFinder.h @@ -19,6 +19,10 @@ class SpatiallyNestable; using SpatiallyNestableWeakPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; +class SpatialParentTree { +public: + SpatiallyNestablePointer findByID(const QUuid& id) { return nullptr; } +}; class SpatialParentFinder : public Dependency { @@ -31,7 +35,7 @@ public: SpatialParentFinder() { } virtual ~SpatialParentFinder() { } - virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success) const = 0; + virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const = 0; }; #endif // hifi_SpatialParentFinder_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 55da4822ef..4e091694de 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -70,7 +70,7 @@ Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const return result; } -SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) const { +SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success, SpatialParentTree* entityTree) const { SpatiallyNestablePointer parent = _parent.lock(); QUuid parentID = getParentID(); // used for its locking @@ -105,7 +105,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons success = false; return nullptr; } - _parent = parentFinder->find(parentID, success); + _parent = parentFinder->find(parentID, success, entityTree); if (!success) { return nullptr; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index a65c7c7f2c..8800fc5ed7 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -139,14 +139,14 @@ public: void die() { _isDead = true; } bool isDead() const { return _isDead; } - bool isParentIDValid() const { bool success = false; getParentPointer(success); return success; } + bool isParentIDValid(SpatialParentTree* entityTree = nullptr) const { bool success = false; getParentPointer(success, entityTree); return success; } protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? - SpatiallyNestablePointer getParentPointer(bool& success) const; + SpatiallyNestablePointer getParentPointer(bool& success, SpatialParentTree* entityTree = nullptr) const; mutable SpatiallyNestableWeakPointer _parent; From b273d5efd329cf2a898930eedf9680927748d260 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 28 Mar 2016 13:48:19 -0700 Subject: [PATCH 010/115] fix defaultScripts filename --- libraries/shared/src/PathUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 94af26db6c..bdaf467ce9 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -56,9 +56,9 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector Date: Mon, 28 Mar 2016 14:25:51 -0700 Subject: [PATCH 011/115] Checkpoint for freakin edit.js again. --- libraries/entities/src/EntityTree.cpp | 8 ++++---- libraries/entities/src/RecurseOctreeToMapOperator.cpp | 8 +++++--- libraries/entities/src/RecurseOctreeToMapOperator.h | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ef7af3da86..f331d50893 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -90,7 +90,7 @@ void EntityTree::postAddEntity(EntityItemPointer entity) { _simulation->addEntity(entity); } - if (!entity->isParentIDValid()) { + if (!entity->isParentIDValid(this)) { _missingParent.append(entity); } @@ -260,7 +260,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI _missingParent.append(childEntity); continue; } - if (!childEntity->isParentIDValid()) { + if (!childEntity->isParentIDValid(this)) { _missingParent.append(childEntity); } @@ -1027,7 +1027,7 @@ void EntityTree::fixupMissingParents() { } bool doMove = false; - if (entity->isParentIDValid()) { + if (entity->isParentIDValid(this)) { qCDebug(entities) << "HRS fixme valid parent" << entity->getEntityItemID() << queryAACubeSuccess; // this entity's parent was previously not known, and now is. Update its location in the EntityTree... doMove = true; @@ -1367,7 +1367,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer entityDescription["Entities"] = QVariantList(); } QScriptEngine scriptEngine; - RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, skipThoseWithBadParents); + RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, skipThoseWithBadParents, this); recurseTreeWithOperator(&theOperator); return true; } diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index e930d5ef5f..06a7ce3f27 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -17,13 +17,15 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues, - bool skipThoseWithBadParents) : + bool skipThoseWithBadParents, + EntityTree* tree) : RecurseOctreeOperator(), _map(map), _top(top), _engine(engine), _skipDefaultValues(skipDefaultValues), - _skipThoseWithBadParents(skipThoseWithBadParents) + _skipThoseWithBadParents(skipThoseWithBadParents), + _entityTree(tree) { // if some element "top" was given, only save information for that element and its children. if (_top) { @@ -49,7 +51,7 @@ bool RecurseOctreeToMapOperator::postRecursion(OctreeElementPointer element) { QVariantList entitiesQList = qvariant_cast(_map["Entities"]); entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - if (_skipThoseWithBadParents && !entityItem->isParentIDValid()) { + if (_skipThoseWithBadParents && !entityItem->isParentIDValid(_entityTree)) { return; // we weren't able to resolve a parent from _parentID, so don't save this entity. } diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.h b/libraries/entities/src/RecurseOctreeToMapOperator.h index c64cf91b61..a774f0f7dd 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.h +++ b/libraries/entities/src/RecurseOctreeToMapOperator.h @@ -14,7 +14,7 @@ class RecurseOctreeToMapOperator : public RecurseOctreeOperator { public: RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues, - bool skipThoseWithBadParents); + bool skipThoseWithBadParents, EntityTree* tree); bool preRecursion(OctreeElementPointer element); bool postRecursion(OctreeElementPointer element); private: @@ -24,4 +24,5 @@ public: bool _withinTop; bool _skipDefaultValues; bool _skipThoseWithBadParents; + EntityTree* _entityTree; }; From 92ef8cafb144f5b7e0b4343ae03502dc5b5ce3fd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 28 Mar 2016 12:08:51 -0700 Subject: [PATCH 012/115] Make sure pos/rot getters don't crash --- interface/src/Application.cpp | 14 ++++++++++++-- libraries/audio-client/src/AudioClient.cpp | 7 ++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7eb19557e5..13b8a565b4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -598,8 +598,18 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : audioThread->setObjectName("Audio Thread"); auto audioIO = DependencyManager::get(); - audioIO->setPositionGetter([this]{ return getMyAvatar()->getPositionForAudio(); }); - audioIO->setOrientationGetter([this]{ return getMyAvatar()->getOrientationForAudio(); }); + audioIO->setPositionGetter([]{ + auto audioIO = DependencyManager::get(); + auto myAvatar = audioIO ? audioIO->getMyAvatar() : nullptr; + + return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; + }); + audioIO->setOrientationGetter([]{ + auto audioIO = DependencyManager::get(); + auto myAvatar = audioIO ? audioIO->getMyAvatar() : nullptr; + + return myAvatar ? myAvatar->getOrientationForAudio() : Quaternions::IDENTITY; + }); audioIO->moveToThread(audioThread); recording::Frame::registerFrameHandler(AudioConstants::getAudioFrameName(), [=](recording::Frame::ConstPointer frame) { diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 7e01196dc7..50e5b7591f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -50,6 +50,9 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100; +static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; }; +static const auto DEFAULT_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; }; + Setting::Handle dynamicJitterBuffers("dynamicJitterBuffers", DEFAULT_DYNAMIC_JITTER_BUFFERS); Setting::Handle maxFramesOverDesired("maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED); Setting::Handle staticDesiredJitterBufferFrames("staticDesiredJitterBufferFrames", @@ -103,7 +106,9 @@ AudioClient::AudioClient() : _outgoingAvatarAudioSequenceNumber(0), _audioOutputIODevice(_receivedAudioStream, this), _stats(&_receivedAudioStream), - _inputGate() + _inputGate(), + _positionGetter(DEFAULT_POSITION_GETTER), + _orientationGetter(DEFAULT_ORIENTATION_GETTER) { // clear the array of locally injected samples memset(_localProceduralSamples, 0, AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL); From 238131014bdd800fc87f7186689a455f9e65fae4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 28 Mar 2016 14:36:08 -0700 Subject: [PATCH 013/115] Fix avatar manager naming --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 13b8a565b4..1d152ef9d9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -599,14 +599,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : auto audioIO = DependencyManager::get(); audioIO->setPositionGetter([]{ - auto audioIO = DependencyManager::get(); - auto myAvatar = audioIO ? audioIO->getMyAvatar() : nullptr; + auto avatarManager = DependencyManager::get(); + auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); audioIO->setOrientationGetter([]{ - auto audioIO = DependencyManager::get(); - auto myAvatar = audioIO ? audioIO->getMyAvatar() : nullptr; + auto avatarManager = DependencyManager::get(); + auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; return myAvatar ? myAvatar->getOrientationForAudio() : Quaternions::IDENTITY; }); From a51cc9d12abb4d0415e2d139ef86dc47a1912c45 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 28 Mar 2016 16:04:45 -0700 Subject: [PATCH 014/115] make self-reverb depend on wetDryMix --- libraries/audio-client/src/AudioClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 7e01196dc7..ce2b30d261 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -550,7 +550,7 @@ void AudioClient::configureReverb() { p.wetDryMix = 100.0f; p.preDelay = 0.0f; p.earlyGain = -96.0f; // disable ER - p.lateGain -= 12.0f; // quieter than listener reverb + p.lateGain += _reverbOptions->getWetDryMix() * (24.0f/100.0f) - 24.0f; // -0dB to -24dB, based on wetDryMix p.lateMixLeft = 0.0f; p.lateMixRight = 0.0f; From b09b9a4a0a434cf550d0e8e98b85c69bbc9c3870 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 28 Mar 2016 16:58:20 -0700 Subject: [PATCH 015/115] snapshot after using tree from entity item. --- libraries/entities/src/EntityItem.cpp | 4 ++++ libraries/entities/src/EntityItem.h | 1 + libraries/entities/src/EntityTree.cpp | 8 ++++---- libraries/entities/src/EntityTree.h | 2 +- libraries/entities/src/RecurseOctreeToMapOperator.cpp | 2 +- libraries/shared/src/SpatialParentFinder.h | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 4 ++-- libraries/shared/src/SpatiallyNestable.h | 5 +++-- 8 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index bbc94e9910..c953ed819e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1010,6 +1010,10 @@ EntityTreePointer EntityItem::getTree() const { return tree; } +SpatialParentTree* EntityItem::getParentTree() const { + return getTree().get(); +} + bool EntityItem::wantTerseEditLogging() const { EntityTreePointer tree = getTree(); return tree ? tree->wantTerseEditLogging() : false; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 577bb406bc..535f2b747d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -359,6 +359,7 @@ public: void setPhysicsInfo(void* data) { _physicsInfo = data; } EntityTreeElementPointer getElement() const { return _element; } EntityTreePointer getTree() const; + virtual SpatialParentTree* getParentTree() const; bool wantTerseEditLogging() const; glm::mat4 getEntityToWorldMatrix() const; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f331d50893..91700d0e80 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -90,7 +90,7 @@ void EntityTree::postAddEntity(EntityItemPointer entity) { _simulation->addEntity(entity); } - if (!entity->isParentIDValid(this)) { + if (!entity->isParentIDValid()) { _missingParent.append(entity); } @@ -260,7 +260,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI _missingParent.append(childEntity); continue; } - if (!childEntity->isParentIDValid(this)) { + if (!childEntity->isParentIDValid()) { _missingParent.append(childEntity); } @@ -1027,7 +1027,7 @@ void EntityTree::fixupMissingParents() { } bool doMove = false; - if (entity->isParentIDValid(this)) { + if (entity->isParentIDValid()) { qCDebug(entities) << "HRS fixme valid parent" << entity->getEntityItemID() << queryAACubeSuccess; // this entity's parent was previously not known, and now is. Update its location in the EntityTree... doMove = true; @@ -1040,7 +1040,7 @@ void EntityTree::fixupMissingParents() { _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; } - else qCDebug(entities) << "HRS fixme failed parent" << entity->getEntityItemID() << queryAACubeSuccess; + else qCDebug(entities) << "HRS fixme failed parent" << entity->getEntityItemID() << queryAACubeSuccess << "parent:" << entity->getParentID() << !!findEntityByID(entity->getParentID()); if (queryAACubeSuccess && doMove) { moveOperator.addEntityToMoveList(entity, newCube); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8cf6a7e45b..892cd86427 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -126,7 +126,7 @@ public: EntityItemPointer findClosestEntity(glm::vec3 position, float targetRadius); EntityItemPointer findEntityByID(const QUuid& id); EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID); - SpatiallyNestablePointer EntityTree::findByID(const QUuid& id) { return findEntityByID(id); } + virtual SpatiallyNestablePointer findByID(const QUuid& id) { return findEntityByID(id); } EntityItemID assignEntityID(const EntityItemID& entityItemID); /// Assigns a known ID for a creator token ID diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index 06a7ce3f27..24b530db03 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -51,7 +51,7 @@ bool RecurseOctreeToMapOperator::postRecursion(OctreeElementPointer element) { QVariantList entitiesQList = qvariant_cast(_map["Entities"]); entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - if (_skipThoseWithBadParents && !entityItem->isParentIDValid(_entityTree)) { + if (_skipThoseWithBadParents && !entityItem->isParentIDValid()) { return; // we weren't able to resolve a parent from _parentID, so don't save this entity. } diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h index ff2593c621..aae7d9f040 100644 --- a/libraries/shared/src/SpatialParentFinder.h +++ b/libraries/shared/src/SpatialParentFinder.h @@ -21,7 +21,7 @@ using SpatiallyNestableWeakPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; class SpatialParentTree { public: - SpatiallyNestablePointer findByID(const QUuid& id) { return nullptr; } + virtual SpatiallyNestablePointer findByID(const QUuid& id) { return nullptr; } }; class SpatialParentFinder : public Dependency { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 4e091694de..13bf5d9054 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -70,7 +70,7 @@ Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const return result; } -SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success, SpatialParentTree* entityTree) const { +SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) const { SpatiallyNestablePointer parent = _parent.lock(); QUuid parentID = getParentID(); // used for its locking @@ -105,7 +105,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success, Spat success = false; return nullptr; } - _parent = parentFinder->find(parentID, success, entityTree); + _parent = parentFinder->find(parentID, success, getParentTree()); if (!success) { return nullptr; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 8800fc5ed7..379f2facd7 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -139,14 +139,15 @@ public: void die() { _isDead = true; } bool isDead() const { return _isDead; } - bool isParentIDValid(SpatialParentTree* entityTree = nullptr) const { bool success = false; getParentPointer(success, entityTree); return success; } + bool isParentIDValid() const { bool success = false; getParentPointer(success); return success; } + virtual SpatialParentTree* getParentTree() const { return nullptr; } protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? - SpatiallyNestablePointer getParentPointer(bool& success, SpatialParentTree* entityTree = nullptr) const; + SpatiallyNestablePointer getParentPointer(bool& success) const; mutable SpatiallyNestableWeakPointer _parent; From b134f22cfaf11f59ba77571b876f9d0f2513a9c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Mar 2016 18:51:34 -0700 Subject: [PATCH 016/115] fix an overflow in portable high resolution clock on windows --- libraries/shared/src/PortableHighResolutionClock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/PortableHighResolutionClock.cpp b/libraries/shared/src/PortableHighResolutionClock.cpp index 6e096a7ce1..9980e51805 100644 --- a/libraries/shared/src/PortableHighResolutionClock.cpp +++ b/libraries/shared/src/PortableHighResolutionClock.cpp @@ -24,7 +24,7 @@ namespace { win_high_resolution_clock::time_point win_high_resolution_clock::now() { LARGE_INTEGER count; QueryPerformanceCounter(&count); - return time_point(duration(count.QuadPart * static_cast(period::den) / g_Frequency)); + return time_point(duration(static_cast(double(count.QuadPart) * static_cast(period::den) / g_Frequency))); } #endif From 115fd607a0912d8c48e2a82e60271607378c3be3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 28 Mar 2016 19:47:30 -0700 Subject: [PATCH 017/115] Address performance issues introduced with this PR. * Prevent clusterMatrices from being invalidated and re-computed in each updateItem lambda. We do this by not setting _model->_needsUpdateClusterMatrices = true; * Prevent redundant work if Model::enqueueLocationChange is called multiple times per frame. We do this by introducing a preRenderLambdas map in the Application class. Instead of adding work directly to the scene PendingChanges queue Model::enqueueLocationChange adds a lambda to the Application preRenderLambdas map. The Application ensures that only one lambda will be invoked for each model per frame. --- interface/src/Application.cpp | 15 ++++ interface/src/Application.h | 5 ++ .../src/AbstractViewStateInterface.h | 2 + .../render-utils/src/MeshPartPayload.cpp | 2 +- libraries/render-utils/src/Model.cpp | 76 +++++++++++-------- 5 files changed, 69 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 381816e81f..84794f7c31 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2985,6 +2985,11 @@ void Application::updateLOD() { } } +void Application::pushPreRenderLambda(void* key, std::function func) { + std::unique_lock guard(_preRenderLambdasLock); + _preRenderLambdas[key] = func; +} + // Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone. // (Maybe this code should be moved there?) // The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition(). @@ -3461,6 +3466,16 @@ void Application::update(float deltaTime) { QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection); } } + + { + PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0); + + std::unique_lock guard(_preRenderLambdasLock); + for (auto& iter : _preRenderLambdas) { + iter.second(); + } + _preRenderLambdas.clear(); + } } diff --git a/interface/src/Application.h b/interface/src/Application.h index d21e647bc7..9124755011 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -211,6 +211,8 @@ public: render::EnginePointer getRenderEngine() override { return _renderEngine; } gpu::ContextPointer getGPUContext() const { return _gpuContext; } + virtual void pushPreRenderLambda(void* key, std::function func) override; + const QRect& getMirrorViewRect() const { return _mirrorViewRect; } void updateMyAvatarLookAtPosition(); @@ -510,6 +512,9 @@ private: bool _cursorNeedsChanging { false }; QThread* _deadlockWatchdogThread; + + std::map> _preRenderLambdas; + std::mutex _preRenderLambdasLock; }; #endif // hifi_Application_h diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 815cb45423..7c7c263562 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -46,6 +46,8 @@ public: virtual render::ScenePointer getMain3DScene() = 0; virtual render::EnginePointer getRenderEngine() = 0; + virtual void pushPreRenderLambda(void* key, std::function func) = 0; + // FIXME - we shouldn't assume that there's a single instance of an AbstractViewStateInterface static AbstractViewStateInterface* instance(); static void setInstance(AbstractViewStateInterface* instance); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8d738e44d8..41352f1532 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -347,7 +347,7 @@ void ModelMeshPartPayload::initCache() { void ModelMeshPartPayload::notifyLocationChanged() { - _model->_needsUpdateClusterMatrices = true; + } void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const glm::mat4* clusterMatrices, size_t numClusterMatrices) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 55aa000ef4..87534ffac1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -128,45 +128,61 @@ void Model::setOffset(const glm::vec3& offset) { } void Model::enqueueLocationChange() { - render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - Transform modelTransform; - modelTransform.setScale(_scale); - modelTransform.setTranslation(_translation); - modelTransform.setRotation(_rotation); + // queue up this work for later processing, at the end of update and just before rendering. + // the application will ensure only the last lambda is actually invoked. + void* key = (void*)this; + std::weak_ptr weakSelf = shared_from_this(); + AbstractViewStateInterface::instance()->pushPreRenderLambda(key, [weakSelf]() { - Transform modelMeshOffset; - if (_geometry && _geometry->isLoaded()) { - modelMeshOffset = Transform(_rig->getGeometryToRigTransform()); - } else { - modelMeshOffset.postTranslate(_offset); - } + // do nothing, if the model has already been destroyed. + auto self = weakSelf.lock(); + if (!self) { + return; + } - Transform collisionMeshOffset; - collisionMeshOffset.postTranslate(_offset); + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + Transform modelTransform; + modelTransform.setScale(self->_scale); + modelTransform.setTranslation(self->_translation); + modelTransform.setRotation(self->_rotation); - render::PendingChanges pendingChanges; - foreach (auto itemID, _modelMeshRenderItems.keys()) { - pendingChanges.updateItem(itemID, [modelTransform, modelMeshOffset](ModelMeshPartPayload& data) { + Transform modelMeshOffset; + if (self->_geometry && self->_geometry->isLoaded()) { + // includes model offset and unitScale. + modelMeshOffset = Transform(self->_rig->getGeometryToRigTransform()); + } else { + modelMeshOffset.postTranslate(self->_offset); + } - data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); - const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - size_t numClusterMatrices = data._model->getGeometry()->getFBXGeometry().meshes.at(data._meshIndex).clusters.size(); + // only apply offset only, collision mesh does not share the same unit scale as the FBX file's mesh. + Transform collisionMeshOffset; + collisionMeshOffset.postTranslate(self->_offset); - data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, &state.clusterMatrices[0], numClusterMatrices); - data.notifyLocationChanged(); - }); - } + render::PendingChanges pendingChanges; + foreach (auto itemID, self->_modelMeshRenderItems.keys()) { + pendingChanges.updateItem(itemID, [modelTransform, modelMeshOffset](ModelMeshPartPayload& data) { - foreach (auto itemID, _collisionRenderItems.keys()) { - pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { - data.updateTransform(modelTransform, collisionMeshOffset); - data.notifyLocationChanged(); - }); - } + // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. + data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); - scene->enqueuePendingChanges(pendingChanges); + // update the model transform and bounding box for this render item. + const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); + size_t numClusterMatrices = data._model->getGeometry()->getFBXGeometry().meshes.at(data._meshIndex).clusters.size(); + data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, &state.clusterMatrices[0], numClusterMatrices); + }); + } + + foreach (auto itemID, self->_collisionRenderItems.keys()) { + pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { + // update the model transform for this render item. + data.updateTransform(modelTransform, collisionMeshOffset); + }); + } + + scene->enqueuePendingChanges(pendingChanges); + }); } void Model::initJointTransforms() { From 24ca5b3d60a7fe0919d88e74578fe71f71ede623 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 28 Mar 2016 20:29:02 -0700 Subject: [PATCH 018/115] Update after merge changes to NetworkGeometry. Also cleaned up API for ModelMeshPartPayload::updateTransformForSkinnedMesh() to pass a QVector const ref, instead of a raw pointer and a size. --- libraries/render-utils/src/MeshPartPayload.cpp | 9 ++++----- libraries/render-utils/src/MeshPartPayload.h | 2 +- libraries/render-utils/src/Model.cpp | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8a498e99e3..d295b07caf 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -354,15 +354,14 @@ void ModelMeshPartPayload::notifyLocationChanged() { } -void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const glm::mat4* clusterMatrices, size_t numClusterMatrices) { +void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const QVector& clusterMatrices) { ModelMeshPartPayload::updateTransform(transform, offsetTransform); - if (numClusterMatrices > 0) { - + if (clusterMatrices.size() > 0) { _worldBound = AABox(); - for (size_t i = 0; i < numClusterMatrices; i++) { + for (auto& clusterMatrix : clusterMatrices) { AABox clusterBound = _localBound; - clusterBound.transform(clusterMatrices[i]); + clusterBound.transform(clusterMatrix); _worldBound += clusterBound; } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 08c606271c..41869ec7e3 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -79,7 +79,7 @@ public: typedef Payload::DataPointer Pointer; void notifyLocationChanged() override; - void updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const glm::mat4* clusterMatrices, size_t numClusterMatrices); + void updateTransformForSkinnedMesh(const Transform& transform, const Transform& offsetTransform, const QVector& clusterMatrices); // Render Item interface render::ItemKey getKey() const override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a29c090bfc..8d59d5f736 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -151,7 +151,7 @@ void Model::enqueueLocationChange() { modelTransform.setRotation(self->_rotation); Transform modelMeshOffset; - if (self->_geometry && self->_geometry->isLoaded()) { + if (self->isLoaded()) { // includes model offset and unitScale. modelMeshOffset = Transform(self->_rig->getGeometryToRigTransform()); } else { @@ -171,8 +171,7 @@ void Model::enqueueLocationChange() { // update the model transform and bounding box for this render item. const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - size_t numClusterMatrices = data._model->getGeometry()->getFBXGeometry().meshes.at(data._meshIndex).clusters.size(); - data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, &state.clusterMatrices[0], numClusterMatrices); + data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, state.clusterMatrices); }); } From 5db1c33e4dbf6e6edeb76f7b206d0f5a81d93a97 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Tue, 29 Mar 2016 09:18:29 -0700 Subject: [PATCH 019/115] kill offsets --- interface/src/Application.cpp | 5 +++-- libraries/entities/src/EntityTree.cpp | 11 ++++++----- libraries/entities/src/RecurseOctreeToMapOperator.cpp | 6 ++---- libraries/entities/src/RecurseOctreeToMapOperator.h | 3 +-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bc2bbc11e0..e5ecd9ce92 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2849,13 +2849,14 @@ bool Application::exportEntities(const QString& filename, const QVectoraddEntity(datum.mappedID, properties); qCDebug(interfaceapp) << "mapped" << properties.getName(); qCDebug(interfaceapp) << " " << originalID << "p:" << datum.originalParentID; qCDebug(interfaceapp) << " =>" << datum.mappedID << "p:" << parentID; - + qCDebug(interfaceapp) << " @" << properties.getPosition() << "/" << properties.getLocalPosition(); + return datum.mappedID; }; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 91700d0e80..76e1f618ee 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1335,12 +1335,13 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra SendEntitiesOperationArgs* args = static_cast(extraData); EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - EntityItemID newID = entityItem->getEntityItemID(); // FIXME (QUuid::createUuid()); + EntityItemID newID = /*entityItem->getEntityItemID(); // FIXME*/ (QUuid::createUuid()); + // FIXME: add map to SendEntitiesOperationArgs, and recurse through parent using the map args->newEntityIDs->append(newID); EntityItemProperties properties = entityItem->getProperties(); - properties.setPosition(properties.getPosition() + args->root); + //FIXME properties.setPosition(properties.getPosition() + args->root); properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity - qCDebug(entities) << "sending" << newID << properties.getName() << "parent:" << properties.getParentID(); + qCDebug(entities) << "sending" << newID << properties.getName() << "parent:" << properties.getParentID() << "pos:" << properties.getPosition(); // queue the packet to send to the server args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, newID, properties); @@ -1367,7 +1368,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer entityDescription["Entities"] = QVariantList(); } QScriptEngine scriptEngine; - RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, skipThoseWithBadParents, this); + RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, skipThoseWithBadParents); recurseTreeWithOperator(&theOperator); return true; } @@ -1395,7 +1396,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { } EntityItemPointer entity = addEntity(entityItemID, properties); - qCDebug(entities) << "HRS FIXME added" << entityItemID << properties.getName(); + qCDebug(entities) << "HRS FIXME added" << entityItemID << properties.getName() << "@" << properties.getPosition(); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); } diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index 24b530db03..e930d5ef5f 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -17,15 +17,13 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues, - bool skipThoseWithBadParents, - EntityTree* tree) : + bool skipThoseWithBadParents) : RecurseOctreeOperator(), _map(map), _top(top), _engine(engine), _skipDefaultValues(skipDefaultValues), - _skipThoseWithBadParents(skipThoseWithBadParents), - _entityTree(tree) + _skipThoseWithBadParents(skipThoseWithBadParents) { // if some element "top" was given, only save information for that element and its children. if (_top) { diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.h b/libraries/entities/src/RecurseOctreeToMapOperator.h index a774f0f7dd..c64cf91b61 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.h +++ b/libraries/entities/src/RecurseOctreeToMapOperator.h @@ -14,7 +14,7 @@ class RecurseOctreeToMapOperator : public RecurseOctreeOperator { public: RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues, - bool skipThoseWithBadParents, EntityTree* tree); + bool skipThoseWithBadParents); bool preRecursion(OctreeElementPointer element); bool postRecursion(OctreeElementPointer element); private: @@ -24,5 +24,4 @@ public: bool _withinTop; bool _skipDefaultValues; bool _skipThoseWithBadParents; - EntityTree* _entityTree; }; From 80dfed77d75fa3fe2b13ce34d9e310ee1b38eebf Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 29 Mar 2016 10:01:10 -0700 Subject: [PATCH 020/115] Fix for flickering eyeballs Calling glm::axis() on an identity quaternion does not result in a normalized vector. This vector was used within Rig::updateEyeJoint() to limit the rotation of the eye balls, to prevent the eyes from rolling back into the avatar's head. If the avatar was looking straight ahead, this could result in bad quaternions in the eye ball joint matrices, which in turn would cause the eye ball mesh or any mesh influenced by the eyeball joints not to render. --- libraries/animation/src/Rig.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index a2b664d064..6a8f190808 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1056,7 +1056,9 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm // limit rotation const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat)); + if (fabsf(glm::angle(deltaQuat)) > MAX_ANGLE) { + deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat)); + } // directly set absolutePose rotation _internalPoseSet._absolutePoses[index].rot = deltaQuat * headQuat; From b88770228e0b91ec14fd6e12805a8297a7f94fc3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 10:40:56 -0700 Subject: [PATCH 021/115] convert running-scripts window to use local script files --- interface/src/Application.cpp | 1 - libraries/script-engine/src/ScriptEngines.cpp | 2 +- libraries/script-engine/src/ScriptsModel.cpp | 23 +++++++++---------- libraries/script-engine/src/ScriptsModel.h | 6 ++--- libraries/shared/src/PathUtils.cpp | 8 +++---- libraries/shared/src/PathUtils.h | 2 +- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c6669303a8..901963e343 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -224,7 +224,6 @@ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStanda static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/script.js"); #endif -const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); const QHash Application::_acceptedExtensions { diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index f005368dc4..2c3f7308fa 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -216,7 +216,7 @@ QVariantList ScriptEngines::getRunning() { static const QString SETTINGS_KEY = "Settings"; void ScriptEngines::loadDefaultScripts() { - loadScript(defaultScriptsFileName()); + loadScript(defaultScriptsLocation() + "/defaultScripts.js"); } void ScriptEngines::loadOneScript(const QString& scriptFilename) { diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 8b01c9fbed..70f0f7fa68 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "ScriptEngine.h" #include "ScriptEngines.h" @@ -23,11 +24,7 @@ #define __STR1__(x) __STR2__(x) #define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: " - -static const QString S3_URL = "http://s3.amazonaws.com/hifi-public"; -static const QString PUBLIC_URL = "http://public.highfidelity.io"; static const QString MODELS_LOCATION = "scripts/"; - static const QString PREFIX_PARAMETER_NAME = "prefix"; static const QString MARKER_PARAMETER_NAME = "marker"; static const QString IS_TRUNCATED_NAME = "IsTruncated"; @@ -63,7 +60,7 @@ ScriptsModel::ScriptsModel(QObject* parent) : connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles); reloadLocalFiles(); - reloadRemoteFiles(); + reloadDefaultFiles(); } ScriptsModel::~ScriptsModel() { @@ -140,24 +137,24 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) { reloadLocalFiles(); } -void ScriptsModel::reloadRemoteFiles() { +void ScriptsModel::reloadDefaultFiles() { if (!_loadingScripts) { _loadingScripts = true; for (int i = _treeNodes.size() - 1; i >= 0; i--) { TreeNodeBase* node = _treeNodes.at(i); if (node->getType() == TREE_NODE_TYPE_SCRIPT && - static_cast(node)->getOrigin() == SCRIPT_ORIGIN_REMOTE) + static_cast(node)->getOrigin() == SCRIPT_ORIGIN_DEFAULT) { delete node; _treeNodes.removeAt(i); } } - requestRemoteFiles(); + requestDefaultFiles(); } } -void ScriptsModel::requestRemoteFiles(QString marker) { - QUrl url(S3_URL); +void ScriptsModel::requestDefaultFiles(QString marker) { + QUrl url(defaultScriptsLocation()); QUrlQuery query; query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION); if (!marker.isEmpty()) { @@ -218,7 +215,9 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { xml.readNext(); lastKey = xml.text().toString(); if (jsRegex.exactMatch(xml.text().toString())) { - _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey, SCRIPT_ORIGIN_REMOTE)); + _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), + defaultScriptsLocation() + "/" + lastKey, + SCRIPT_ORIGIN_DEFAULT)); } } xml.readNext(); @@ -236,7 +235,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { } if (truncated) { - requestRemoteFiles(lastKey); + requestDefaultFiles(lastKey); } // If this request was not truncated, we are done. diff --git a/libraries/script-engine/src/ScriptsModel.h b/libraries/script-engine/src/ScriptsModel.h index df9716d43b..e1902f4b23 100644 --- a/libraries/script-engine/src/ScriptsModel.h +++ b/libraries/script-engine/src/ScriptsModel.h @@ -21,7 +21,7 @@ class TreeNodeFolder; enum ScriptOrigin { SCRIPT_ORIGIN_LOCAL, - SCRIPT_ORIGIN_REMOTE + SCRIPT_ORIGIN_DEFAULT }; enum TreeNodeType { @@ -84,10 +84,10 @@ protected slots: void updateScriptsLocation(const QString& newPath); void downloadFinished(); void reloadLocalFiles(); - void reloadRemoteFiles(); + void reloadDefaultFiles(); protected: - void requestRemoteFiles(QString marker = QString()); + void requestDefaultFiles(QString marker = QString()); bool parseXML(QByteArray xmlFile); void rebuildTree(); diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index bdaf467ce9..ebaae27eb1 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -54,13 +54,13 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); -QString defaultScriptsFileName(); +QString defaultScriptsLocation(); #endif // hifi_PathUtils_h From a2c520a74a7b0ad982c95e8dcb1f0c948d8306e4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 29 Mar 2016 10:47:26 -0700 Subject: [PATCH 022/115] ModelOverlay: use a shared_ptr not a model member This is necessary for shared_ptr and weak_ptr to work for Models contained within a ModelOverlay. --- interface/src/ui/overlays/ModelOverlay.cpp | 44 +++++++++++----------- interface/src/ui/overlays/ModelOverlay.h | 4 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 010698800b..adf08934f0 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -18,22 +18,22 @@ QString const ModelOverlay::TYPE = "model"; ModelOverlay::ModelOverlay() - : _model(std::make_shared()), + : _model(std::make_shared(std::make_shared())), _modelTextures(QVariantMap()), _updateModel(false) { - _model.init(); + _model->init(); _isLoaded = false; } ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) : Volume3DOverlay(modelOverlay), - _model(std::make_shared()), + _model(std::make_shared(std::make_shared())), _modelTextures(QVariantMap()), _url(modelOverlay->_url), _updateModel(false) { - _model.init(); + _model->init(); if (_url.isValid()) { _updateModel = true; _isLoaded = false; @@ -44,27 +44,27 @@ void ModelOverlay::update(float deltatime) { if (_updateModel) { _updateModel = false; - _model.setSnapModelToCenter(true); - _model.setScale(getDimensions()); - _model.setRotation(getRotation()); - _model.setTranslation(getPosition()); - _model.setURL(_url); - _model.simulate(deltatime, true); + _model->setSnapModelToCenter(true); + _model->setScale(getDimensions()); + _model->setRotation(getRotation()); + _model->setTranslation(getPosition()); + _model->setURL(_url); + _model->simulate(deltatime, true); } else { - _model.simulate(deltatime); + _model->simulate(deltatime); } - _isLoaded = _model.isActive(); + _isLoaded = _model->isActive(); } bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { Volume3DOverlay::addToScene(overlay, scene, pendingChanges); - _model.addToScene(scene, pendingChanges); + _model->addToScene(scene, pendingChanges); return true; } void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { Volume3DOverlay::removeFromScene(overlay, scene, pendingChanges); - _model.removeFromScene(scene, pendingChanges); + _model->removeFromScene(scene, pendingChanges); } void ModelOverlay::render(RenderArgs* args) { @@ -73,9 +73,9 @@ void ModelOverlay::render(RenderArgs* args) { // fix them up in the scene render::ScenePointer scene = qApp->getMain3DScene(); render::PendingChanges pendingChanges; - if (_model.needsFixupInScene()) { - _model.removeFromScene(scene, pendingChanges); - _model.addToScene(scene, pendingChanges); + if (_model->needsFixupInScene()) { + _model->removeFromScene(scene, pendingChanges); + _model->addToScene(scene, pendingChanges); } scene->enqueuePendingChanges(pendingChanges); @@ -100,7 +100,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) { if (newScale.x <= 0 || newScale.y <= 0 || newScale.z <= 0) { setDimensions(scale); } else { - _model.setScaleToFit(true, getDimensions()); + _model->setScaleToFit(true, getDimensions()); _updateModel = true; } } @@ -120,7 +120,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) { QUrl newTextureURL = textureMap[key].toUrl(); qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; - QMetaObject::invokeMethod(&_model, "setTextureWithNameToURL", Qt::AutoConnection, + QMetaObject::invokeMethod(_model.get(), "setTextureWithNameToURL", Qt::AutoConnection, Q_ARG(const QString&, key), Q_ARG(const QUrl&, newTextureURL)); @@ -134,7 +134,7 @@ QVariant ModelOverlay::getProperty(const QString& property) { return _url.toString(); } if (property == "dimensions" || property == "scale" || property == "size") { - return vec3toVariant(_model.getScaleToFitDimensions()); + return vec3toVariant(_model->getScaleToFitDimensions()); } if (property == "textures") { if (_modelTextures.size() > 0) { @@ -155,13 +155,13 @@ bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& float& distance, BoxFace& face, glm::vec3& surfaceNormal) { QString subMeshNameTemp; - return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, subMeshNameTemp); + return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, subMeshNameTemp); } bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) { - return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo); + return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo); } ModelOverlay* ModelOverlay::createClone() const { diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 0b67f7ed37..36ff75cb6a 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -41,11 +41,11 @@ public: private: - Model _model; + ModelPointer _model; QVariantMap _modelTextures; QUrl _url; bool _updateModel; }; -#endif // hifi_ModelOverlay_h \ No newline at end of file +#endif // hifi_ModelOverlay_h From 848e7703ee665c6541e649190f5add87b32aa6be Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 18:39:53 -0700 Subject: [PATCH 023/115] Test textures emptiness correctly --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ae29d1faf7..5ec4b1bba9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -109,7 +109,7 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) { // If textures are unset, revert to original textures - if (textures == "") { + if (textures.isEmpty()) { return _originalTextures; } From 96a35a8f43dc562fac2376b879daf92880a763a3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 29 Mar 2016 11:33:02 -0700 Subject: [PATCH 024/115] Fix bug where a pending asset request could receive a pending message after deletion --- libraries/networking/src/AssetClient.cpp | 12 +++++++++++- libraries/networking/src/AssetClient.h | 5 +++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 8cb1f31090..446009ac23 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -228,7 +228,8 @@ bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end nodeList->sendPacket(std::move(packet), *assetServer); - _pendingRequests[assetServer][messageID] = { callback, progressCallback }; + _pendingRequests[assetServer][messageID] = { QSharedPointer(), callback, progressCallback }; + return true; } else { @@ -326,6 +327,9 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S if (requestIt != messageCallbackMap.end()) { auto& callbacks = requestIt->second; + // Store message in case we need to disconnect from it later. + callbacks.message = message; + if (message->isComplete()) { callbacks.completeCallback(true, error, message->readAll()); } else { @@ -550,6 +554,12 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { auto messageMapIt = _pendingRequests.find(node); if (messageMapIt != _pendingRequests.end()) { for (const auto& value : messageMapIt->second) { + auto& message = value.second.message; + if (message) { + // Disconnect from all signals emitting from the pending message + disconnect(message.data(), nullptr, this, nullptr); + } + value.second.completeCallback(false, AssetServerError::NoError, QByteArray()); } messageMapIt->second.clear(); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index e46c8c6524..f1890377dc 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -86,14 +86,15 @@ private: ReceivedAssetCallback callback, ProgressCallback progressCallback); bool uploadAsset(const QByteArray& data, UploadResultCallback callback); - struct GetAssetCallbacks { + struct GetAssetRequestData { + QSharedPointer message; ReceivedAssetCallback completeCallback; ProgressCallback progressCallback; }; static MessageID _currentID; std::unordered_map> _pendingMappingRequests; - std::unordered_map> _pendingRequests; + std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; From 3aa1090cedf4ef95a4451963eba792da61085713 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 11:58:21 -0700 Subject: [PATCH 025/115] working toward allowing local files in running-scripts window --- libraries/script-engine/src/ScriptsModel.cpp | 41 +++++++++++++------- libraries/shared/src/PathUtils.cpp | 8 ++-- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 70f0f7fa68..192a1f84e5 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -155,18 +156,29 @@ void ScriptsModel::reloadDefaultFiles() { void ScriptsModel::requestDefaultFiles(QString marker) { QUrl url(defaultScriptsLocation()); - QUrlQuery query; - query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION); - if (!marker.isEmpty()) { - query.addQueryItem(MARKER_PARAMETER_NAME, marker); - } - url.setQuery(query); - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest request(url); - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - QNetworkReply* reply = networkAccessManager.get(request); - connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); + if (url.isLocalFile()) { + // QDirIterator it(url.toLocalFile(), QStringList() << "*.js", QDir::Files, QDirIterator::Subdirectories); + // while (it.hasNext()) { + // QString jsFile = it.next();; + // _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), + // defaultScriptsLocation() + "/" + jsFile, + // SCRIPT_ORIGIN_DEFAULT)); + // } + } else { + QUrlQuery query; + query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION); + if (!marker.isEmpty()) { + query.addQueryItem(MARKER_PARAMETER_NAME, marker); + } + url.setQuery(query); + + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + QNetworkReply* reply = networkAccessManager.get(request); + connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); + } } void ScriptsModel::downloadFinished() { @@ -179,8 +191,10 @@ void ScriptsModel::downloadFinished() { if (!data.isEmpty()) { finished = parseXML(data); } else { - qCDebug(scriptengine) << "Error: Received no data when loading remote scripts"; + qCDebug(scriptengine) << "Error: Received no data when loading default scripts"; } + } else { + qDebug() << "error is" << reply->error(); } reply->deleteLater(); @@ -214,6 +228,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == KEY_NAME) { xml.readNext(); lastKey = xml.text().toString(); + qDebug() << "lastKey = " << lastKey; if (jsRegex.exactMatch(xml.text().toString())) { _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), defaultScriptsLocation() + "/" + lastKey, @@ -230,7 +245,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { // Error handling if (xml.hasError()) { - qCDebug(scriptengine) << "Error loading remote scripts: " << xml.errorString(); + qCDebug(scriptengine) << "Error loading default scripts: " << xml.errorString(); return true; } diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index ebaae27eb1..46eb61ea72 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -56,11 +56,11 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector Date: Tue, 29 Mar 2016 13:13:22 -0700 Subject: [PATCH 026/115] use explicit double casts for win_high_resolution_clock --- libraries/shared/src/PortableHighResolutionClock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/PortableHighResolutionClock.cpp b/libraries/shared/src/PortableHighResolutionClock.cpp index 9980e51805..b12798503e 100644 --- a/libraries/shared/src/PortableHighResolutionClock.cpp +++ b/libraries/shared/src/PortableHighResolutionClock.cpp @@ -24,7 +24,7 @@ namespace { win_high_resolution_clock::time_point win_high_resolution_clock::now() { LARGE_INTEGER count; QueryPerformanceCounter(&count); - return time_point(duration(static_cast(double(count.QuadPart) * static_cast(period::den) / g_Frequency))); + return time_point(duration(static_cast(double(count.QuadPart) * double(period::den) / double(g_Frequency)))); } #endif From b9ce427344afeda52326d4488908981b8cb060b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 29 Mar 2016 13:25:03 -0700 Subject: [PATCH 027/115] use c-style casts to respect the coding standard --- libraries/shared/src/PortableHighResolutionClock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/PortableHighResolutionClock.cpp b/libraries/shared/src/PortableHighResolutionClock.cpp index b12798503e..55dd61707c 100644 --- a/libraries/shared/src/PortableHighResolutionClock.cpp +++ b/libraries/shared/src/PortableHighResolutionClock.cpp @@ -24,7 +24,7 @@ namespace { win_high_resolution_clock::time_point win_high_resolution_clock::now() { LARGE_INTEGER count; QueryPerformanceCounter(&count); - return time_point(duration(static_cast(double(count.QuadPart) * double(period::den) / double(g_Frequency)))); + return time_point(duration(static_cast((double) count.QuadPart * (double) period::den / (double)g_Frequency))); } #endif From 4a28dadae57e8e8332331c9b6b7abc3e8973a3f6 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 29 Mar 2016 13:26:50 -0700 Subject: [PATCH 028/115] Working, but not cleaned up. --- interface/src/Application.cpp | 62 ++++++++++++++---------- libraries/entities/src/EntityTree.cpp | 68 +++++++++++++++++++++------ libraries/entities/src/EntityTree.h | 5 +- 3 files changed, 92 insertions(+), 43 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 83da078ddd..95990d7c63 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2791,18 +2791,18 @@ void Application::calibrateEyeTracker5Points() { } #endif -class EntityDatum { // For parent-first sorting and mapping. -public: - EntityItemPointer item; - EntityItemProperties properties; - EntityItemID originalParentID; - EntityItemID mappedID; - EntityDatum() {}; - EntityDatum(EntityItemPointer itemArg, EntityItemProperties propertiesArg, EntityItemID parentID) : - item(itemArg), properties(propertiesArg), originalParentID(parentID) { - }; -}; bool Application::exportEntities(const QString& filename, const QVector& entityIDs) { + class EntityDatum { // For parent-first sorting and mapping. + public: + EntityItemPointer item; + EntityItemProperties properties; + EntityItemID originalParentID; + EntityItemID mappedID; + EntityDatum() {}; + EntityDatum(EntityItemPointer itemArg, EntityItemProperties propertiesArg, EntityItemID parentID) : + item(itemArg), properties(propertiesArg), originalParentID(parentID) { + }; + }; QHash entities; auto entityTree = getEntities()->getTree(); @@ -2818,13 +2818,15 @@ bool Application::exportEntities(const QString& filename, const QVectorgetProperties(); - auto position = properties.getPosition(); // see setPosition, below. - root.x = glm::min(root.x, position.x); - root.y = glm::min(root.y, position.y); - root.z = glm::min(root.z, position.z); - + EntityItemID parentID = properties.getParentID(); + if (parentID.isInvalidID() || !entityIDs.contains(parentID)) { + auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties. + root.x = glm::min(root.x, position.x); + root.y = glm::min(root.y, position.y); + root.z = glm::min(root.z, position.z); + } qCDebug(interfaceapp) << "Exporting" << entityItem->getEntityItemID() << entityItem->getName(); - entities[entityID] = EntityDatum(entityItem, properties, properties.getParentID()); + entities[entityID] = EntityDatum(entityItem, properties, parentID); } if (entities.size() == 0) { @@ -2833,7 +2835,7 @@ bool Application::exportEntities(const QString& filename, const QVector getMapped = [&](EntityDatum& datum) { + std::function getMapped = [&](EntityDatum& datum) { // FIXME: move definition outside the loop auto originalID = datum.item->getEntityItemID(); if (!datum.mappedID.isInvalidID()) { qCDebug(interfaceapp) << "already mapped" << datum.properties.getName() << originalID << "=>" << datum.mappedID; @@ -2841,16 +2843,26 @@ bool Application::exportEntities(const QString& filename, const QVectorgetPosition(success); + if (success) { + properties.setPosition(globalPosition - root); + if (!parentID.isInvalidID()) { // There's a parent that we won't output. Make the other data global. + properties.setRotation(datum.item->getRotation()); + properties.setDimensions(datum.item->getDimensions()); + // Should we do velocities and accelerations, too? + } + } else { + properties.setPosition(datum.item->getQueryAACube().calcCenter() - root); // best we can do + } + } else {// Recurse over ancestors, updating properties. qCDebug(interfaceapp) << "FIXME recursing" << datum.originalParentID << "parent of" << datum.item->getEntityItemID(); - // Warning: this is not a tail-call, so exporting a REALLY deep parent hierarchy will blow the call stack. + // Warning: could blow the call stack if the parent hierarchy is VERY deep. parentID = getMapped(entities[parentID]); properties.setParentID(parentID); } - // The so-called root offset (which isn't) is confusing and not what content developers want. And why would queryAACube not then be offset? - // But leaving it in for bug-compatibility right now. -HRS - // FIXME properties.setPosition(properties.getPosition() - root); - datum.mappedID = originalID; //EntityItemID(QUuid::createUuid()); + datum.mappedID = originalID; // FIXME: simplify because we don't have to map ids. auto newEntity = exportTree->addEntity(datum.mappedID, properties); qCDebug(interfaceapp) << "mapped" << properties.getName(); qCDebug(interfaceapp) << " " << originalID << "p:" << datum.originalParentID; @@ -2862,8 +2874,6 @@ bool Application::exportEntities(const QString& filename, const QVectorremapIDs(); exportTree->writeToJSONFile(filename.toLocal8Bit().constData()); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 76e1f618ee..2d8e20c69a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1320,26 +1320,62 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen float x, float y, float z) { SendEntitiesOperationArgs args; args.packetSender = packetSender; - args.localTree = localTree; + args.ourTree = this; + args.otherTree = localTree; args.root = glm::vec3(x, y, z); - QVector newEntityIDs; - args.newEntityIDs = &newEntityIDs; + // If this is called repeatedly (e.g., multiple pastes with the same data), the new elements will clash unless we use new identifiers. + // We need to keep a map so that we can map parent identifiers correctly. + QHash map; + args.map = ↦ recurseTreeWithOperation(sendEntitiesOperation, &args); packetSender->releaseQueuedMessages(); - return newEntityIDs; + return map.values().toVector(); } bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) { qCDebug(entities) << "sendEntitiesOperation"; SendEntitiesOperationArgs* args = static_cast(extraData); EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - EntityItemID newID = /*entityItem->getEntityItemID(); // FIXME*/ (QUuid::createUuid()); - // FIXME: add map to SendEntitiesOperationArgs, and recurse through parent using the map - args->newEntityIDs->append(newID); - EntityItemProperties properties = entityItem->getProperties(); - //FIXME properties.setPosition(properties.getPosition() + args->root); + std::function getMapped = [&](EntityItemPointer& item) -> const EntityItemID { + EntityItemID oldID = item->getEntityItemID(); + if (args->map->contains(oldID)) { // Already been handled (e.g., as a parent of somebody that we've processed). + return args->map->value(oldID); + } + EntityItemID newID = QUuid::createUuid(); + args->map->insert(oldID, newID); + EntityItemProperties properties = item->getProperties(); + EntityItemID oldParentID = properties.getParentID(); + if (oldParentID.isInvalidID()) { // no parent + properties.setPosition(properties.getPosition() + args->root); + } else { + EntityItemPointer parentEntity = args->ourTree->findEntityByEntityItemID(oldParentID); + if (parentEntity) { // map the parent + // Warning: could blow the call stack if the parent hierarchy is VERY deep. + properties.setParentID(getMapped(parentEntity)); + // But do not add root offset in this case. + } else { // Should not happen, but let's try to be helpful... + // Log what we can. + QString name = properties.getName(); + if (name.isEmpty()) { + name = EntityTypes::getEntityTypeName(properties.getType()); + } + bool success; + glm::vec3 position = item->getPosition(success); + qCWarning(entities) << "Cannot find" << oldParentID << "parent of" << oldID << name << (success ? "" : "and unable to resolve geometry"); + // Adjust geometry with absolute/global values. + if (success) { + properties.setPosition(position + args->root); + properties.setRotation(item->getRotation()); + properties.setDimensions(item->getDimensions()); + // Should we do velocities and accelerations, too? + } else { + properties.setPosition(item->getQueryAACube().calcCenter() + args->root); // best we can do + } + QUuid empty; + properties.setParentID(empty); + } + } properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity qCDebug(entities) << "sending" << newID << properties.getName() << "parent:" << properties.getParentID() << "pos:" << properties.getPosition(); @@ -1347,13 +1383,15 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, newID, properties); // also update the local tree instantly (note: this is not our tree, but an alternate tree) - // [Sure looks like the global application's tree to me. See callers. -HRS] - if (args->localTree) { - args->localTree->withWriteLock([&] { - args->localTree->addEntity(newID, properties); + if (args->otherTree) { + args->otherTree->withWriteLock([&] { + args->otherTree->addEntity(newID, properties); }); } - }); + return newID; + }; + + entityTreeElement->forEachEntity(getMapped); return true; } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 892cd86427..f3400feb8e 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -47,9 +47,10 @@ public: class SendEntitiesOperationArgs { public: glm::vec3 root; - EntityTreePointer localTree; + EntityTree* ourTree; + EntityTreePointer otherTree; EntityEditPacketSender* packetSender; - QVector* newEntityIDs; + QHash* map; }; From 0c72ca1be30c6c81f9ff2bd16e7f1066ff77a34b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 13:39:35 -0700 Subject: [PATCH 029/115] works on windows now --- libraries/script-engine/src/ScriptEngines.cpp | 2 +- libraries/script-engine/src/ScriptsModel.cpp | 14 +++++++------- libraries/shared/src/PathUtils.cpp | 7 +++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 2c3f7308fa..339953cdb4 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -216,7 +216,7 @@ QVariantList ScriptEngines::getRunning() { static const QString SETTINGS_KEY = "Settings"; void ScriptEngines::loadDefaultScripts() { - loadScript(defaultScriptsLocation() + "/defaultScripts.js"); + loadScript(defaultScriptsLocation() + "/scripts/defaultScripts.js"); } void ScriptEngines::loadOneScript(const QString& scriptFilename) { diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 192a1f84e5..a94ccc9771 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -158,13 +158,13 @@ void ScriptsModel::requestDefaultFiles(QString marker) { QUrl url(defaultScriptsLocation()); if (url.isLocalFile()) { - // QDirIterator it(url.toLocalFile(), QStringList() << "*.js", QDir::Files, QDirIterator::Subdirectories); - // while (it.hasNext()) { - // QString jsFile = it.next();; - // _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), - // defaultScriptsLocation() + "/" + jsFile, - // SCRIPT_ORIGIN_DEFAULT)); - // } + QString localDir = url.toLocalFile() + "/scripts"; + QDirIterator it(localDir, QStringList() << "*.js", QDir::Files, QDirIterator::Subdirectories); + while (it.hasNext()) { + QString jsFullPath = it.next(); + QString jsPartialPath = jsFullPath.mid(localDir.length() + 1); // + 1 to skip a separator + _treeNodes.append(new TreeNodeScript(jsPartialPath, jsFullPath, SCRIPT_ORIGIN_DEFAULT)); + } } else { QUrlQuery query; query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION); diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 46eb61ea72..4b4a9efa9e 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -56,11 +56,10 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector Date: Tue, 29 Mar 2016 13:45:09 -0700 Subject: [PATCH 030/115] cleanups --- libraries/script-engine/src/ScriptsModel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index a94ccc9771..c851f08172 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -194,7 +194,7 @@ void ScriptsModel::downloadFinished() { qCDebug(scriptengine) << "Error: Received no data when loading default scripts"; } } else { - qDebug() << "error is" << reply->error(); + qDebug() << "Error: when loading default scripts --" << reply->error(); } reply->deleteLater(); @@ -228,7 +228,6 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == KEY_NAME) { xml.readNext(); lastKey = xml.text().toString(); - qDebug() << "lastKey = " << lastKey; if (jsRegex.exactMatch(xml.text().toString())) { _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), defaultScriptsLocation() + "/" + lastKey, From 6c7b6cd62e64cb70de408fb8206c041cf4a1aed3 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 29 Mar 2016 14:12:19 -0700 Subject: [PATCH 031/115] Return parsed tex directly as variant --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 5ec4b1bba9..5f5be5ebc8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -124,7 +124,9 @@ QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) { qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << _textures; return _originalTextures; } - return texturesJson.object().toVariantMap(); + + auto parsed = texturesJson.toVariant(); + return parsed.toMap(); } void RenderableModelEntityItem::remapTextures() { From 9d8e01f2a597388779d3771947e21ec848805ae4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 15:01:23 -0700 Subject: [PATCH 032/115] lock entity-tree before moving entity-children of avatars --- interface/src/avatar/MyAvatar.cpp | 50 ++++++++++++++++--------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 38babc4ef0..69b23388b1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -373,32 +373,34 @@ void MyAvatar::simulate(float deltaTime) { EntityTreeRenderer* entityTreeRenderer = qApp->getEntities(); EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr; if (entityTree) { - auto now = usecTimestampNow(); - EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender(); - MovingEntitiesOperator moveOperator(entityTree); - forEachDescendant([&](SpatiallyNestablePointer object) { - // if the queryBox has changed, tell the entity-server - if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) { - EntityItemPointer entity = std::static_pointer_cast(object); - bool success; - AACube newCube = entity->getQueryAACube(success); - if (success) { - moveOperator.addEntityToMoveList(entity, newCube); - } - if (packetSender) { - EntityItemProperties properties = entity->getProperties(); - properties.setQueryAACubeDirty(); - properties.setLastEdited(now); - packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties); - entity->setLastBroadcast(usecTimestampNow()); - } + entityTree->withWriteLock([&] { + auto now = usecTimestampNow(); + EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender(); + MovingEntitiesOperator moveOperator(entityTree); + forEachDescendant([&](SpatiallyNestablePointer object) { + // if the queryBox has changed, tell the entity-server + if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(object); + bool success; + AACube newCube = entity->getQueryAACube(success); + if (success) { + moveOperator.addEntityToMoveList(entity, newCube); + } + if (packetSender) { + EntityItemProperties properties = entity->getProperties(); + properties.setQueryAACubeDirty(); + properties.setLastEdited(now); + packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties); + entity->setLastBroadcast(usecTimestampNow()); + } + } + }); + // also update the position of children in our local octree + if (moveOperator.hasMovingEntities()) { + PerformanceTimer perfTimer("recurseTreeWithOperator"); + entityTree->recurseTreeWithOperator(&moveOperator); } }); - // also update the position of children in our local octree - if (moveOperator.hasMovingEntities()) { - PerformanceTimer perfTimer("recurseTreeWithOperator"); - entityTree->recurseTreeWithOperator(&moveOperator); - } } } From bcb729eac2eaa3b0f5d2b5bcec403d5563304c94 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 29 Mar 2016 15:21:06 -0700 Subject: [PATCH 033/115] Abstract out globalizeProperties. --- interface/src/Application.cpp | 65 +++++++-------------------- libraries/entities/src/EntityItem.cpp | 22 +++++++++ libraries/entities/src/EntityItem.h | 2 + libraries/entities/src/EntityTree.cpp | 26 +---------- 4 files changed, 43 insertions(+), 72 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 95990d7c63..362658360e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2792,7 +2792,7 @@ void Application::calibrateEyeTracker5Points() { #endif bool Application::exportEntities(const QString& filename, const QVector& entityIDs) { - class EntityDatum { // For parent-first sorting and mapping. + /* class EntityDatum { // For parent-first sorting and mapping. public: EntityItemPointer item; EntityItemProperties properties; @@ -2803,7 +2803,8 @@ bool Application::exportEntities(const QString& filename, const QVector entities; + QHash entities;*/ + QHash entities; auto entityTree = getEntities()->getTree(); auto exportTree = std::make_shared(); @@ -2813,66 +2814,34 @@ bool Application::exportEntities(const QString& filename, const QVectorfindEntityByEntityItemID(entityID); if (!entityItem) { - qCDebug(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; + qCWarning(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; continue; } - auto properties = entityItem->getProperties(); - EntityItemID parentID = properties.getParentID(); - if (parentID.isInvalidID() || !entityIDs.contains(parentID)) { + EntityItemID parentID = entityItem->getParentID(); + if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) { auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties. root.x = glm::min(root.x, position.x); root.y = glm::min(root.y, position.y); root.z = glm::min(root.z, position.z); } - qCDebug(interfaceapp) << "Exporting" << entityItem->getEntityItemID() << entityItem->getName(); - entities[entityID] = EntityDatum(entityItem, properties, parentID); + entities[entityID] = entityItem; // EntityDatum(entityItem, entityItem->getProperties(), parentID); } if (entities.size() == 0) { return false; } - for (EntityDatum& entityDatum : entities) { - // Recursively add the parents of entities to the exportTree, mapping their new identifiers as we go. - std::function getMapped = [&](EntityDatum& datum) { // FIXME: move definition outside the loop - auto originalID = datum.item->getEntityItemID(); - if (!datum.mappedID.isInvalidID()) { - qCDebug(interfaceapp) << "already mapped" << datum.properties.getName() << originalID << "=>" << datum.mappedID; - return datum.mappedID; // We are a parent that has already been added/mapped. - } - auto properties = datum.properties; - auto parentID = datum.originalParentID; - if (parentID.isInvalidID() || !entityIDs.contains(parentID)) { - bool success; - auto globalPosition = datum.item->getPosition(success); - if (success) { - properties.setPosition(globalPosition - root); - if (!parentID.isInvalidID()) { // There's a parent that we won't output. Make the other data global. - properties.setRotation(datum.item->getRotation()); - properties.setDimensions(datum.item->getDimensions()); - // Should we do velocities and accelerations, too? - } - } else { - properties.setPosition(datum.item->getQueryAACube().calcCenter() - root); // best we can do - } - } else {// Recurse over ancestors, updating properties. - qCDebug(interfaceapp) << "FIXME recursing" << datum.originalParentID << "parent of" << datum.item->getEntityItemID(); - // Warning: could blow the call stack if the parent hierarchy is VERY deep. - parentID = getMapped(entities[parentID]); - properties.setParentID(parentID); - } - datum.mappedID = originalID; // FIXME: simplify because we don't have to map ids. - auto newEntity = exportTree->addEntity(datum.mappedID, properties); - qCDebug(interfaceapp) << "mapped" << properties.getName(); - qCDebug(interfaceapp) << " " << originalID << "p:" << datum.originalParentID; - qCDebug(interfaceapp) << " =>" << datum.mappedID << "p:" << parentID; - qCDebug(interfaceapp) << " @" << properties.getPosition() << "/" << properties.getLocalPosition(); - - return datum.mappedID; - }; - - getMapped(entityDatum); + //for (EntityDatum& entityDatum : entities) { + for (EntityItemPointer& entityDatum : entities) { + auto properties = entityDatum->getProperties(); + EntityItemID parentID = properties.getParentID(); + if (parentID.isInvalidID()) { + properties.setPosition(properties.getPosition() - root); + } else if (!entities.contains(parentID)) { + entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root); + } // else valid parent -- don't offset + exportTree->addEntity(entityDatum->getEntityItemID(), properties); } exportTree->writeToJSONFile(filename.toLocal8Bit().constData()); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c953ed819e..6a016720d8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1982,3 +1982,25 @@ void EntityItem::dimensionsChanged() { requiresRecalcBoxes(); SpatiallyNestable::dimensionsChanged(); // Do what you have to do } + +void EntityItem::globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate, const glm::vec3& offset) const { + bool success; + auto globalPosition = getPosition(success); + if (success) { + properties.setPosition(globalPosition + offset); + properties.setRotation(getRotation()); + properties.setDimensions(getDimensions()); + // Should we do velocities and accelerations, too? This could end up being quite involved, which is why the method exists. + } else { + properties.setPosition(getQueryAACube().calcCenter() + offset); // best we can do + } + if (!messageTemplate.isEmpty()) { + QString name = properties.getName(); + if (name.isEmpty()) { + name = EntityTypes::getEntityTypeName(properties.getType()); + } + qCWarning(entities) << messageTemplate.arg(getEntityItemID().toString()).arg(name).arg(properties.getParentID().toString()); + } + QUuid empty; + properties.setParentID(empty); +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 535f2b747d..622f78b2d3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -86,6 +86,8 @@ public: /// returns true if something changed virtual bool setProperties(const EntityItemProperties& properties); + // Update properties with empty parent id and globalized/absolute values (applying offset), and apply (non-empty) log template to args id, name-or-type, parent id. + void globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate = QString(), const glm::vec3& offset = glm::vec3(0.0f)) const; /// Override this in your derived class if you'd like to be informed when something about the state of the entity /// has changed. This will be called with properties change or when new data is loaded from a stream diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 2d8e20c69a..0d714eaafb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1334,7 +1334,6 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen } bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) { - qCDebug(entities) << "sendEntitiesOperation"; SendEntitiesOperationArgs* args = static_cast(extraData); EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); std::function getMapped = [&](EntityItemPointer& item) -> const EntityItemID { @@ -1351,33 +1350,14 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra } else { EntityItemPointer parentEntity = args->ourTree->findEntityByEntityItemID(oldParentID); if (parentEntity) { // map the parent - // Warning: could blow the call stack if the parent hierarchy is VERY deep. + // Warning: (non-tail) recursion of getMapped could blow the call stack if the parent hierarchy is VERY deep. properties.setParentID(getMapped(parentEntity)); // But do not add root offset in this case. } else { // Should not happen, but let's try to be helpful... - // Log what we can. - QString name = properties.getName(); - if (name.isEmpty()) { - name = EntityTypes::getEntityTypeName(properties.getType()); - } - bool success; - glm::vec3 position = item->getPosition(success); - qCWarning(entities) << "Cannot find" << oldParentID << "parent of" << oldID << name << (success ? "" : "and unable to resolve geometry"); - // Adjust geometry with absolute/global values. - if (success) { - properties.setPosition(position + args->root); - properties.setRotation(item->getRotation()); - properties.setDimensions(item->getDimensions()); - // Should we do velocities and accelerations, too? - } else { - properties.setPosition(item->getQueryAACube().calcCenter() + args->root); // best we can do - } - QUuid empty; - properties.setParentID(empty); + item->globalizeProperties(properties, "Cannot find %3 parent of %2 %1", args->root); } } properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity - qCDebug(entities) << "sending" << newID << properties.getName() << "parent:" << properties.getParentID() << "pos:" << properties.getPosition(); // queue the packet to send to the server args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, newID, properties); @@ -1434,12 +1414,10 @@ bool EntityTree::readFromMap(QVariantMap& map) { } EntityItemPointer entity = addEntity(entityItemID, properties); - qCDebug(entities) << "HRS FIXME added" << entityItemID << properties.getName() << "@" << properties.getPosition(); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); } } - qCDebug(entities) << "HRS FIXME end of readFromMap"; return true; } From ad9027f9d650bff58b1f4bdd0fd4415b4d9f3cd2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 29 Mar 2016 15:09:27 -0700 Subject: [PATCH 034/115] Log OffscreenQml lifetime --- .../src/RenderableWebEntityItem.cpp | 2 +- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index ce3faeb196..855fd16408 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -55,8 +55,8 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { qWarning() << "Too many concurrent web views to create new view"; return false; } - qDebug() << "Building web surface"; + ++_currentWebCount; // Save the original GL context, because creating a QML surface will create a new context QOpenGLContext * currentContext = QOpenGLContext::currentContext(); diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 818b3c6ca8..1d9e6d0149 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -70,7 +70,7 @@ public: virtual bool event(QEvent *e) override; protected: - class Queue : public QQueue { + class Queue : private QQueue { public: void add(QEvent::Type type); QEvent* take(); @@ -134,12 +134,14 @@ QEvent* OffscreenQmlRenderThread::Queue::take() { } OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) { + qDebug() << "Building QML Renderer: creating context"; if (!_canvas.create(shareContext)) { static const char* error = "Failed to create OffscreenGLCanvas"; qWarning() << error; throw error; }; + qDebug() << "Building QML Renderer: creating render control"; _renderControl = new QMyQuickRenderControl(); QQuickWindow::setDefaultAlphaBuffer(true); // Create a QQuickWindow that is associated with our render control. @@ -147,19 +149,25 @@ OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, // NOTE: Must be created on the main thread so that OffscreenQmlSurface can send it events // NOTE: Must be created on the rendering thread or it will refuse to render, // so we wait until after its ctor to move object/context to this thread. + qDebug() << "Building QML Renderer: creating window"; _quickWindow = new QQuickWindow(_renderControl); _quickWindow->setColor(QColor(255, 255, 255, 0)); _quickWindow->setFlags(_quickWindow->flags() | static_cast(Qt::WA_TranslucentBackground)); // We can prepare, but we must wait to start() the thread until after the ctor + qDebug() << "Building QML Renderer: moving to own thread"; _renderControl->prepareThread(this); _canvas.getContextObject()->moveToThread(this); moveToThread(this); + qDebug() << "Building QML Renderer: complete"; + _queue.add(INIT); } void OffscreenQmlRenderThread::run() { + qDebug() << "Starting QML Renderer thread"; + while (!_quit) { QEvent* e = _queue.take(); event(e); @@ -208,12 +216,14 @@ void OffscreenQmlRenderThread::setupFbo() { } void OffscreenQmlRenderThread::init() { + qDebug() << "Initializing QML Renderer"; + connect(_renderControl, &QQuickRenderControl::renderRequested, _surface, &OffscreenQmlSurface::requestRender); connect(_renderControl, &QQuickRenderControl::sceneChanged, _surface, &OffscreenQmlSurface::requestUpdate); if (!_canvas.makeCurrent()) { - // Failed to make GL context current, this OffscreenQmlSurface is basically dead qWarning("Failed to make context current on QML Renderer Thread"); + _quit = true; return; } @@ -360,6 +370,8 @@ void OffscreenQmlSurface::onAboutToQuit() { } void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { + qDebug() << "Building QML surface"; + _renderer = new OffscreenQmlRenderThread(this, shareContext); _renderer->moveToThread(_renderer); _renderer->setObjectName("QML Renderer Thread"); From 2ad02941e4fbfb3234760981366b73d2ca3afd5d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 15:38:11 -0700 Subject: [PATCH 035/115] lowercase filenames/paths before they go into _treeNodes to avoid scripts being unstoppable --- libraries/script-engine/src/ScriptsModel.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index c851f08172..5a4f1734d8 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -163,6 +163,10 @@ void ScriptsModel::requestDefaultFiles(QString marker) { while (it.hasNext()) { QString jsFullPath = it.next(); QString jsPartialPath = jsFullPath.mid(localDir.length() + 1); // + 1 to skip a separator + #if defined(Q_OS_WIN) || defined(Q_OS_OSX) + jsFullPath = jsFullPath.toLower(); + jsPartialPath = jsPartialPath.toLower(); + #endif _treeNodes.append(new TreeNodeScript(jsPartialPath, jsFullPath, SCRIPT_ORIGIN_DEFAULT)); } } else { @@ -274,7 +278,13 @@ void ScriptsModel::reloadLocalFiles() { const QFileInfoList localFiles = _localDirectory.entryInfoList(); for (int i = 0; i < localFiles.size(); i++) { QFileInfo file = localFiles[i]; - _treeNodes.append(new TreeNodeScript(file.fileName(), file.absoluteFilePath(), SCRIPT_ORIGIN_LOCAL)); + QString fileName = file.fileName(); + QString absPath = file.absoluteFilePath(); + #if defined(Q_OS_WIN) || defined(Q_OS_OSX) + fileName = fileName.toLower(); + absPath = absPath.toLower(); + #endif + _treeNodes.append(new TreeNodeScript(fileName, absPath, SCRIPT_ORIGIN_LOCAL)); } rebuildTree(); endResetModel(); From 537c6fa3c6e4bd680ad3c79310b511c21a96bafa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 15:39:42 -0700 Subject: [PATCH 036/115] fix indentation --- interface/src/avatar/MyAvatar.cpp | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 69b23388b1..6aa6f57e07 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -378,23 +378,23 @@ void MyAvatar::simulate(float deltaTime) { EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender(); MovingEntitiesOperator moveOperator(entityTree); forEachDescendant([&](SpatiallyNestablePointer object) { - // if the queryBox has changed, tell the entity-server - if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) { - EntityItemPointer entity = std::static_pointer_cast(object); - bool success; - AACube newCube = entity->getQueryAACube(success); - if (success) { - moveOperator.addEntityToMoveList(entity, newCube); - } - if (packetSender) { - EntityItemProperties properties = entity->getProperties(); - properties.setQueryAACubeDirty(); - properties.setLastEdited(now); - packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties); - entity->setLastBroadcast(usecTimestampNow()); - } + // if the queryBox has changed, tell the entity-server + if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(object); + bool success; + AACube newCube = entity->getQueryAACube(success); + if (success) { + moveOperator.addEntityToMoveList(entity, newCube); } - }); + if (packetSender) { + EntityItemProperties properties = entity->getProperties(); + properties.setQueryAACubeDirty(); + properties.setLastEdited(now); + packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties); + entity->setLastBroadcast(usecTimestampNow()); + } + } + }); // also update the position of children in our local octree if (moveOperator.hasMovingEntities()) { PerformanceTimer perfTimer("recurseTreeWithOperator"); From 6ae03fe72e0fbb4783a6dc57f4ac2b3bc57fd39f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 29 Mar 2016 15:47:00 -0700 Subject: [PATCH 037/115] Sync ordering of gl fields/reset commands --- libraries/gpu/src/gpu/GLBackend.h | 1 - libraries/gpu/src/gpu/GLBackendState.cpp | 5 +++-- libraries/gpu/src/gpu/State.h | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index d4efe7fe99..f5abacd279 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -158,7 +158,6 @@ public: ~GLState(); // The state commands to reset to default, - // WARNING depending on the order of the State::Field enum static const Commands _resetStateCommands; friend class GLBackend; diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 64bd87c876..36ce1dd555 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -35,6 +35,7 @@ const GLBackend::GLState::Commands makeResetStateCommands(); const GLBackend::GLState::Commands GLBackend::GLState::_resetStateCommands = makeResetStateCommands(); +// NOTE: This must stay in sync with the ordering of the State::Field enum const GLBackend::GLState::Commands makeResetStateCommands() { // Since State::DEFAULT is a static defined in another .cpp the initialisation order is random // and we have a 50/50 chance that State::DEFAULT is not yet initialized. @@ -69,9 +70,9 @@ const GLBackend::GLState::Commands makeResetStateCommands() { CommandPointer(stencilCommand), CommandPointer(stencilCommand), - std::make_shared(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable), - std::make_shared(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask), + + std::make_shared(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable), std::make_shared(&GLBackend::do_setStateBlend, DEFAULT.blendFunction), diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 7e32a7280a..385edec277 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -345,6 +345,7 @@ public: uint8 getColorWriteMask() const { return _values.colorWriteMask; } // All the possible fields + // NOTE: If you change this, you must update GLBackend::GLState::_resetStateCommands enum Field { FILL_MODE, CULL_MODE, @@ -364,6 +365,7 @@ public: STENCIL_TEST_BACK, SAMPLE_MASK, + ALPHA_TO_COVERAGE_ENABLE, BLEND_FUNCTION, From 4ebf81616689e215c7478f234abf2fb0312c1491 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 29 Mar 2016 16:17:19 -0700 Subject: [PATCH 038/115] cleanup --- interface/src/Application.cpp | 66 ++++++++------------------- interface/src/Application.h | 2 +- libraries/entities/src/EntityTree.cpp | 5 +- 3 files changed, 21 insertions(+), 52 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 362658360e..8285d92004 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2791,19 +2791,7 @@ void Application::calibrateEyeTracker5Points() { } #endif -bool Application::exportEntities(const QString& filename, const QVector& entityIDs) { - /* class EntityDatum { // For parent-first sorting and mapping. - public: - EntityItemPointer item; - EntityItemProperties properties; - EntityItemID originalParentID; - EntityItemID mappedID; - EntityDatum() {}; - EntityDatum(EntityItemPointer itemArg, EntityItemProperties propertiesArg, EntityItemID parentID) : - item(itemArg), properties(propertiesArg), originalParentID(parentID) { - }; - }; - QHash entities;*/ +bool Application::exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset) { QHash entities; auto entityTree = getEntities()->getTree(); @@ -2818,21 +2806,25 @@ bool Application::exportEntities(const QString& filename, const QVectorgetParentID(); - if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) { - auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties. - root.x = glm::min(root.x, position.x); - root.y = glm::min(root.y, position.y); - root.z = glm::min(root.z, position.z); + if (!givenOffset) { + EntityItemID parentID = entityItem->getParentID(); + if (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID)) { + auto position = entityItem->getPosition(); // If parent wasn't selected, we want absolute position, which isn't in properties. + root.x = glm::min(root.x, position.x); + root.y = glm::min(root.y, position.y); + root.z = glm::min(root.z, position.z); + } } - entities[entityID] = entityItem; // EntityDatum(entityItem, entityItem->getProperties(), parentID); + entities[entityID] = entityItem; } if (entities.size() == 0) { return false; } - //for (EntityDatum& entityDatum : entities) { + if (givenOffset) { + root = *givenOffset; + } for (EntityItemPointer& entityDatum : entities) { auto properties = entityDatum->getProperties(); EntityItemID parentID = properties.getParentID(); @@ -2852,33 +2844,14 @@ bool Application::exportEntities(const QString& filename, const QVector entities; - getEntities()->getTree()->findEntities(AACube(glm::vec3(x, y, z), scale), entities); - - if (entities.size() > 0) { - glm::vec3 root(x, y, z); - auto exportTree = std::make_shared(); - exportTree->createRootElement(); - - for (int i = 0; i < entities.size(); i++) { - EntityItemProperties properties = entities.at(i)->getProperties(); - EntityItemID id = entities.at(i)->getEntityItemID(); - properties.setPosition(properties.getPosition() - root); - exportTree->addEntity(id, properties); - } - - // remap IDs on export so that we aren't publishing the IDs of entities in our domain - exportTree->remapIDs(); - - exportTree->writeToSVOFile(filename.toLocal8Bit().constData()); - } else { - qCDebug(interfaceapp) << "No models were selected"; - return false; + QVector ids; + getEntities()->getTree()->findEntities(AACube(offset, scale), entities); + foreach(EntityItemPointer entity, entities) { + ids << entity->getEntityItemID(); } - - // restore the main window's active state - _window->activateWindow(); - return true; + return exportEntities(filename, ids, &offset); } void Application::loadSettings() { @@ -2911,7 +2884,6 @@ bool Application::importEntities(const QString& urlOrFilename) { bool success = _entityClipboard->readFromURL(urlOrFilename); if (success) { - // FIXME _entityClipboard->remapIDs(); _entityClipboard->reaverageOctreeElements(); } return success; diff --git a/interface/src/Application.h b/interface/src/Application.h index d21e647bc7..f20d72fcb6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -233,7 +233,7 @@ signals: public slots: QVector pasteEntities(float x, float y, float z); - bool exportEntities(const QString& filename, const QVector& entityIDs); + bool exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset = nullptr); bool exportEntities(const QString& filename, float x, float y, float z, float scale); bool importEntities(const QString& url); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 0d714eaafb..ab5edb88d8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1009,7 +1009,6 @@ void EntityTree::entityChanged(EntityItemPointer entity) { void EntityTree::fixupMissingParents() { MovingEntitiesOperator moveOperator(getThisPointer()); - if (!_missingParent.empty()) qCDebug(entities) << "HRS fixme fixupMissingParents" << _missingParent.count() << "entities"; QMutableVectorIterator iter(_missingParent); while (iter.hasNext()) { EntityItemWeakPointer entityWP = iter.next(); @@ -1028,7 +1027,6 @@ void EntityTree::fixupMissingParents() { bool doMove = false; if (entity->isParentIDValid()) { - qCDebug(entities) << "HRS fixme valid parent" << entity->getEntityItemID() << queryAACubeSuccess; // this entity's parent was previously not known, and now is. Update its location in the EntityTree... doMove = true; } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { @@ -1040,7 +1038,6 @@ void EntityTree::fixupMissingParents() { _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; } - else qCDebug(entities) << "HRS fixme failed parent" << entity->getEntityItemID() << queryAACubeSuccess << "parent:" << entity->getParentID() << !!findEntityByID(entity->getParentID()); if (queryAACubeSuccess && doMove) { moveOperator.addEntityToMoveList(entity, newCube); @@ -1342,7 +1339,6 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra return args->map->value(oldID); } EntityItemID newID = QUuid::createUuid(); - args->map->insert(oldID, newID); EntityItemProperties properties = item->getProperties(); EntityItemID oldParentID = properties.getParentID(); if (oldParentID.isInvalidID()) { // no parent @@ -1368,6 +1364,7 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra args->otherTree->addEntity(newID, properties); }); } + args->map->insert(oldID, newID); return newID; }; From eef9de4d4f8b82755025ba121611afc2821403f5 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 29 Mar 2016 16:28:02 -0700 Subject: [PATCH 039/115] Remove obsolete remapIDs. --- libraries/entities/src/EntityTree.cpp | 5 ---- libraries/entities/src/EntityTree.h | 2 -- libraries/entities/src/RemapIDOperator.cpp | 33 ---------------------- libraries/entities/src/RemapIDOperator.h | 30 -------------------- 4 files changed, 70 deletions(-) delete mode 100644 libraries/entities/src/RemapIDOperator.cpp delete mode 100644 libraries/entities/src/RemapIDOperator.h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ab5edb88d8..458ca90435 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1372,11 +1372,6 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra return true; } -void EntityTree::remapIDs() { - RemapIDOperator theOperator; - recurseTreeWithOperator(&theOperator); -} - bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) { if (! entityDescription.contains("Entities")) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index f3400feb8e..5c5f5b4eb9 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -203,8 +203,6 @@ public: bool wantTerseEditLogging() const { return _wantTerseEditLogging; } void setWantTerseEditLogging(bool value) { _wantTerseEditLogging = value; } - void remapIDs(); - virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) override; virtual bool readFromMap(QVariantMap& entityDescription) override; diff --git a/libraries/entities/src/RemapIDOperator.cpp b/libraries/entities/src/RemapIDOperator.cpp deleted file mode 100644 index eee6e49a1c..0000000000 --- a/libraries/entities/src/RemapIDOperator.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// RemapIDOperator.cpp -// libraries/entities/src -// -// Created by Seth Alves on 2015-12-6. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -#include "EntityTree.h" -#include "RemapIDOperator.h" - -QUuid RemapIDOperator::remap(const QUuid& oldID) { - if (oldID.isNull()) { - return oldID; - } - if (!_oldToNew.contains(oldID)) { - _oldToNew[oldID] = QUuid::createUuid(); - } - return _oldToNew[oldID]; -} - -bool RemapIDOperator::postRecursion(OctreeElementPointer element) { - EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { - entityItem->setID(remap(entityItem->getID())); - entityItem->setParentID(remap(entityItem->getParentID())); - }); - return true; -} diff --git a/libraries/entities/src/RemapIDOperator.h b/libraries/entities/src/RemapIDOperator.h deleted file mode 100644 index 439aec28fc..0000000000 --- a/libraries/entities/src/RemapIDOperator.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// RemapIDOperator.h -// libraries/entities/src -// -// Created by Seth Alves on 2015-12-6. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_RemapIDOperator_h -#define hifi_RemapIDOperator_h - -#include "Octree.h" - -// this will change all the IDs in an EntityTree. Parent/Child relationships are maintained. - -class RemapIDOperator : public RecurseOctreeOperator { -public: - RemapIDOperator() : RecurseOctreeOperator() {} - ~RemapIDOperator() {} - virtual bool preRecursion(OctreeElementPointer element) { return true; } - virtual bool postRecursion(OctreeElementPointer element); -private: - QUuid remap(const QUuid& oldID); - QHash _oldToNew; -}; - -#endif // hifi_RemapIDOperator_h From 86a77d4f55eee99394c59343db34cb8c5552305a Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 29 Mar 2016 16:55:17 -0700 Subject: [PATCH 040/115] Remove unused/non-existent include. --- libraries/entities/src/EntityTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 458ca90435..5292e12ae8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -24,7 +24,6 @@ #include "EntitiesLogging.h" #include "RecurseOctreeToMapOperator.h" #include "LogHandler.h" -#include "RemapIDOperator.h" static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; From 5381be6902b8fd774ba953e87610d9e098c6d7b9 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 29 Mar 2016 17:06:19 -0700 Subject: [PATCH 041/115] Whitespace --- interface/src/Application.cpp | 3 +-- libraries/entities/src/EntityItem.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8285d92004..4f1dfe77f3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -270,7 +270,7 @@ public: void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); -/* fixme + uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us uint64_t now = usecTimestampNow(); auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; @@ -319,7 +319,6 @@ public: deadlockDetectionCrash(); } #endif - */ } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 6a016720d8..431d638063 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2003,4 +2003,4 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt } QUuid empty; properties.setParentID(empty); -} \ No newline at end of file +} From be27eaff24f42781b518e9e05bdb3a0ef586bcaa Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 29 Mar 2016 17:51:24 -0700 Subject: [PATCH 042/115] Moving the scripts for render that where in utilities/tools/render to utilities/render, adding counters for lights --- examples/utilities/{tools => }/render/BG.qml | 0 .../configSlider}/ConfigSlider.qml | 0 examples/utilities/render/configSlider/qmldir | 1 + examples/utilities/render/culling.qml | 114 ++++++++++++++++++ .../utilities/{tools => }/render/debug.js | 0 .../utilities/{tools => }/render/debugBG.js | 0 .../{tools => }/render/debugFramebuffer.js | 0 examples/utilities/render/debugRender.js | 21 ++++ .../{tools => }/render/framebuffer.qml | 0 .../utilities/{tools => }/render/main.qml | 1 + .../{tools => }/render/plotperf/PlotPerf.qml | 2 +- .../{tools => }/render/plotperf/qmldir | 0 .../{tools => }/render/renderStats.js | 0 .../utilities/{tools => }/render/stats.qml | 15 ++- .../utilities/tools/debugRenderCulling.js | 99 --------------- .../src/DeferredLightingEffect.cpp | 2 + .../render-utils/src/RenderDeferredTask.h | 3 +- libraries/render-utils/src/spot_light.slf | 3 + libraries/render/src/render/DrawSceneOctree.h | 28 +++-- libraries/render/src/render/DrawTask.cpp | 15 ++- libraries/render/src/render/DrawTask.h | 26 +++- 21 files changed, 211 insertions(+), 119 deletions(-) rename examples/utilities/{tools => }/render/BG.qml (100%) rename examples/utilities/{tools/render => render/configSlider}/ConfigSlider.qml (100%) create mode 100644 examples/utilities/render/configSlider/qmldir create mode 100644 examples/utilities/render/culling.qml rename examples/utilities/{tools => }/render/debug.js (100%) rename examples/utilities/{tools => }/render/debugBG.js (100%) rename examples/utilities/{tools => }/render/debugFramebuffer.js (100%) create mode 100644 examples/utilities/render/debugRender.js rename examples/utilities/{tools => }/render/framebuffer.qml (100%) rename examples/utilities/{tools => }/render/main.qml (99%) rename examples/utilities/{tools => }/render/plotperf/PlotPerf.qml (99%) rename examples/utilities/{tools => }/render/plotperf/qmldir (100%) rename examples/utilities/{tools => }/render/renderStats.js (100%) rename examples/utilities/{tools => }/render/stats.qml (85%) delete mode 100644 examples/utilities/tools/debugRenderCulling.js diff --git a/examples/utilities/tools/render/BG.qml b/examples/utilities/render/BG.qml similarity index 100% rename from examples/utilities/tools/render/BG.qml rename to examples/utilities/render/BG.qml diff --git a/examples/utilities/tools/render/ConfigSlider.qml b/examples/utilities/render/configSlider/ConfigSlider.qml similarity index 100% rename from examples/utilities/tools/render/ConfigSlider.qml rename to examples/utilities/render/configSlider/ConfigSlider.qml diff --git a/examples/utilities/render/configSlider/qmldir b/examples/utilities/render/configSlider/qmldir new file mode 100644 index 0000000000..6680ec9638 --- /dev/null +++ b/examples/utilities/render/configSlider/qmldir @@ -0,0 +1 @@ +ConfigSlider 1.0 ConfigSlider.qml \ No newline at end of file diff --git a/examples/utilities/render/culling.qml b/examples/utilities/render/culling.qml new file mode 100644 index 0000000000..e3f5e67bbe --- /dev/null +++ b/examples/utilities/render/culling.qml @@ -0,0 +1,114 @@ +// +// culling.qml +// examples/utilities/render +// +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "configSlider" + +Column { + id: root + spacing: 8 + property var sceneOctree: Render.getConfig("DrawSceneOctree"); + property var itemSelection: Render.getConfig("DrawItemSelection"); + + Component.onCompleted: { + sceneOctree.enabled = true; + itemSelection.enabled = true; + sceneOctree.showVisibleCells = false; + sceneOctree.showEmptyCells = false; + itemSelection.showInsideItems = false; + itemSelection.showInsideSubcellItems = false; + itemSelection.showPartialItems = false; + itemSelection.showPartialSubcellItems = false; + } + Component.onDestruction: { + sceneOctree.enabled = false; + itemSelection.enabled = false; + Render.getConfig("FetchSceneSelection").freezeFrustum = false; + Render.getConfig("CullSceneSelection").freezeFrustum = false; + } + + GroupBox { + title: "Culling" + Row { + spacing: 8 + Column { + spacing: 8 + + CheckBox { + text: "Freeze Culling Frustum" + checked: false + onCheckedChanged: { + Render.getConfig("FetchSceneSelection").freezeFrustum = checked; + Render.getConfig("CullSceneSelection").freezeFrustum = checked; + } + } + Label { + text: "Octree" + } + CheckBox { + text: "Visible Cells" + checked: root.sceneOctree.showVisibleCells + onCheckedChanged: { root.sceneOctree.showVisibleCells = checked } + } + CheckBox { + text: "Empty Cells" + checked: false + onCheckedChanged: { root.sceneOctree.showEmptyCells = checked } + } + } + Column { + spacing: 8 + + Label { + text: "Frustum Items" + } + CheckBox { + text: "Inside Items" + checked: false + onCheckedChanged: { root.itemSelection.showInsideItems = checked } + } + CheckBox { + text: "Inside Sub-cell Items" + checked: false + onCheckedChanged: { root.itemSelection.showInsideSubcellItems = checked } + } + CheckBox { + text: "Partial Items" + checked: false + onCheckedChanged: { root.itemSelection.showPartialItems = checked } + } + CheckBox { + text: "Partial Sub-cell Items" + checked: false + onCheckedChanged: { root.itemSelection.showPartialSubcellItems = checked } + } + } + } + } + + GroupBox { + title: "Render Items" + + Column{ + Repeater { + model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred", "Light:DrawLight", + "Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: true + config: Render.getConfig(modelData.split(":")[1]) + property: "maxDrawn" + max: config.numDrawn + min: -1 + } + } + } + } +} diff --git a/examples/utilities/tools/render/debug.js b/examples/utilities/render/debug.js similarity index 100% rename from examples/utilities/tools/render/debug.js rename to examples/utilities/render/debug.js diff --git a/examples/utilities/tools/render/debugBG.js b/examples/utilities/render/debugBG.js similarity index 100% rename from examples/utilities/tools/render/debugBG.js rename to examples/utilities/render/debugBG.js diff --git a/examples/utilities/tools/render/debugFramebuffer.js b/examples/utilities/render/debugFramebuffer.js similarity index 100% rename from examples/utilities/tools/render/debugFramebuffer.js rename to examples/utilities/render/debugFramebuffer.js diff --git a/examples/utilities/render/debugRender.js b/examples/utilities/render/debugRender.js new file mode 100644 index 0000000000..788c7cb4a0 --- /dev/null +++ b/examples/utilities/render/debugRender.js @@ -0,0 +1,21 @@ +// +// debugRender.js +// examples/utilities/render +// +// Sam Gateau, created on 3/22/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Set up the qml ui +var qml = Script.resolvePath('culling.qml'); +var window = new OverlayWindow({ + title: 'Render Draws', + source: qml, + width: 300, + height: 200 +}); +window.setPosition(200, 50); +window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/examples/utilities/tools/render/framebuffer.qml b/examples/utilities/render/framebuffer.qml similarity index 100% rename from examples/utilities/tools/render/framebuffer.qml rename to examples/utilities/render/framebuffer.qml diff --git a/examples/utilities/tools/render/main.qml b/examples/utilities/render/main.qml similarity index 99% rename from examples/utilities/tools/render/main.qml rename to examples/utilities/render/main.qml index 22f263b2d0..aecd566207 100644 --- a/examples/utilities/tools/render/main.qml +++ b/examples/utilities/render/main.qml @@ -10,6 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 +import "configSlider" Column { id: root diff --git a/examples/utilities/tools/render/plotperf/PlotPerf.qml b/examples/utilities/render/plotperf/PlotPerf.qml similarity index 99% rename from examples/utilities/tools/render/plotperf/PlotPerf.qml rename to examples/utilities/render/plotperf/PlotPerf.qml index 0e100e4e72..7141ea77d0 100644 --- a/examples/utilities/tools/render/plotperf/PlotPerf.qml +++ b/examples/utilities/render/plotperf/PlotPerf.qml @@ -1,6 +1,6 @@ // // PlotPerf.qml -// examples/utilities/tools/render +// examples/utilities/render/plotperf // // Created by Sam Gateau on 3//2016 // Copyright 2016 High Fidelity, Inc. diff --git a/examples/utilities/tools/render/plotperf/qmldir b/examples/utilities/render/plotperf/qmldir similarity index 100% rename from examples/utilities/tools/render/plotperf/qmldir rename to examples/utilities/render/plotperf/qmldir diff --git a/examples/utilities/tools/render/renderStats.js b/examples/utilities/render/renderStats.js similarity index 100% rename from examples/utilities/tools/render/renderStats.js rename to examples/utilities/render/renderStats.js diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/render/stats.qml similarity index 85% rename from examples/utilities/tools/render/stats.qml rename to examples/utilities/render/stats.qml index aacc896444..ae5b433678 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -1,6 +1,6 @@ // // stats.qml -// examples/utilities/tools/render +// examples/utilities/render // // Created by Zach Pomerantz on 2/8/2016 // Copyright 2016 High Fidelity, Inc. @@ -22,7 +22,7 @@ Item { anchors.fill:parent property var config: Render.getConfig("Stats") - + function evalEvenHeight() { // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? return (height - spacing * (children.length - 1)) / children.length @@ -65,5 +65,16 @@ Item { height: parent.evalEvenHeight() parameters: "1000:K:0:frameTriangleCount-frame-#E2334D:frameTriangleRate-rate-#1AC567-0.001-MT/s" } + + property var deferredTaskConfig: Render.getConfig("RenderDeferredTask") + property var drawLightConfig: deferredTaskConfig.getConfig("DrawLight") + + PlotPerf { + title: "Lights" + config: parent.drawLightConfig + height: parent.evalEvenHeight() + parameters: "1::0:numDrawn-frame-#E2334D" + } } + } diff --git a/examples/utilities/tools/debugRenderCulling.js b/examples/utilities/tools/debugRenderCulling.js deleted file mode 100644 index dbc5f07e0d..0000000000 --- a/examples/utilities/tools/debugRenderCulling.js +++ /dev/null @@ -1,99 +0,0 @@ -// -// debugRenderOctree.js -// examples/utilities/tools -// -// Sam Gateau -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include("cookies.js"); - -var panel = new Panel(10, 300); -var drawOctree = Render.RenderDeferredTask.DrawSceneOctree; -Render.RenderDeferredTask.DrawSceneOctree.enabled = true; -Render.RenderDeferredTask.DrawItemSelection.enabled = true; - -panel.newCheckbox("Show Octree Cells", - function(value) { Render.RenderDeferredTask.DrawSceneOctree.showVisibleCells = value; }, - function() { return (Render.RenderDeferredTask.DrawSceneOctree.showVisibleCells); }, - function(value) { return (value); } -); -panel.newCheckbox("Show Empty Cells", - function(value) { Render.RenderDeferredTask.DrawSceneOctree.showEmptyCells = value; }, - function() { return (Render.RenderDeferredTask.DrawSceneOctree.showEmptyCells); }, - function(value) { return (value); } -); -panel.newCheckbox("Freeze Frustum", - function(value) { Render.RenderDeferredTask.FetchSceneSelection.freezeFrustum = value; Render.RenderDeferredTask.CullSceneSelection.freezeFrustum = value; }, - function() { return (Render.RenderDeferredTask.FetchSceneSelection.freezeFrustum); }, - function(value) { return (value); } -); -panel.newCheckbox("Show Inside Items", - function(value) { Render.RenderDeferredTask.DrawItemSelection.showInsideItems = value; }, - function() { return (Render.RenderDeferredTask.DrawItemSelection.showInsideItems); }, - function(value) { return (value); } -); - -panel.newCheckbox("Show Inside Subcell Items", - function(value) { Render.RenderDeferredTask.DrawItemSelection.showInsideSubcellItems = value; }, - function() { return (Render.RenderDeferredTask.DrawItemSelection.showInsideSubcellItems); }, - function(value) { return (value); } -); - -panel.newCheckbox("Show Partial Items", - function(value) { Render.RenderDeferredTask.DrawItemSelection.showPartialItems = value; }, - function() { return (Render.RenderDeferredTask.DrawItemSelection.showPartialItems); }, - function(value) { return (value); } -); - -panel.newCheckbox("Show Partial Subcell Items", - function(value) { Render.RenderDeferredTask.DrawItemSelection.showPartialSubcellItems = value; }, - function() { return (Render.RenderDeferredTask.DrawItemSelection.showPartialSubcellItems); }, - function(value) { return (value); } -); - -/* -panel.newSlider('Cells Free / Allocated', -1, 1, - function(value) { value; }, // setter - function() { return Render.RenderDeferredTask.DrawSceneOctree.numFreeCells; }, // getter - function(value) { return value; }); - -this.update = function () { - var numFree = Render.RenderDeferredTask.DrawSceneOctree.numFreeCells; - var numAlloc = Render.RenderDeferredTask.DrawSceneOctree.numAllocatedCells; - var title = [ - ' ' + name, - numFree + ' / ' + numAlloc - ].join('\t'); - - widget.editTitle({ text: title }); - slider.setMaxValue(numAlloc); -}; -*/ -function mouseMoveEvent(event) { - panel.mouseMoveEvent(event); -} - -function mousePressEvent(event) { - panel.mousePressEvent(event); -} - -function mouseReleaseEvent(event) { - panel.mouseReleaseEvent(event); -} - -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - -function scriptEnding() { - panel.destroy(); - Render.RenderDeferredTask.DrawSceneOctree.enabled = false; - Render.RenderDeferredTask.DrawItemSelection.enabled = false; -} -Script.scriptEnding.connect(scriptEnding); - - diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index f3fa4a43b2..74795e6735 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -437,6 +437,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... if ((eyeHalfPlaneDistance > -nearRadius) && (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) { + light->setShowContour(true); coneParam.w = 0.0f; batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); @@ -452,6 +453,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo batch.setProjectionTransform( projMats[side]); batch.setViewTransform(viewTransforms[side]); } else { + light->setShowContour(false); coneParam.w = 1.0f; batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 0125ef79fe..9fb6802992 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -32,9 +32,10 @@ public: class RenderDeferred { public: + using JobModel = render::Job::Model; + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - using JobModel = render::Job::Model; }; class DrawConfig : public render::Job::Config { diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 69f8e836aa..1239628ac6 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -25,6 +25,7 @@ in vec4 _texCoord0; out vec4 _fragColor; void main(void) { + DeferredTransform deferredTransform = getDeferredTransform(); // Grab the fragment data from the uv @@ -36,6 +37,8 @@ void main(void) { // Kill if in front of the light volume float depth = frag.depthVal; if (depth < gl_FragCoord.z) { + _fragColor = vec4(1.0, 0.0, 0.0, 1.0); + return; discard; } diff --git a/libraries/render/src/render/DrawSceneOctree.h b/libraries/render/src/render/DrawSceneOctree.h index 60fc0bb2c4..530b7accac 100644 --- a/libraries/render/src/render/DrawSceneOctree.h +++ b/libraries/render/src/render/DrawSceneOctree.h @@ -20,17 +20,14 @@ namespace render { class DrawSceneOctreeConfig : public Job::Config { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty()) - Q_PROPERTY(bool showVisibleCells MEMBER showVisibleCells WRITE setShowVisibleCells) - Q_PROPERTY(bool showEmptyCells MEMBER showEmptyCells WRITE setShowEmptyCells) + Q_PROPERTY(bool showVisibleCells READ getShowVisibleCells WRITE setShowVisibleCells NOTIFY dirty()) + Q_PROPERTY(bool showEmptyCells READ getShowEmptyCells WRITE setShowEmptyCells NOTIFY dirty()) Q_PROPERTY(int numAllocatedCells READ getNumAllocatedCells) Q_PROPERTY(int numFreeCells READ getNumFreeCells) public: DrawSceneOctreeConfig() : Job::Config(false) {} - - bool showVisibleCells{ true }; - bool showEmptyCells{ false }; int numAllocatedCells{ 0 }; int numFreeCells{ 0 }; @@ -38,6 +35,12 @@ namespace render { int getNumAllocatedCells() const { return numAllocatedCells; } int getNumFreeCells() const { return numFreeCells; } + bool showVisibleCells{ true }; + bool showEmptyCells{ false }; + + bool getShowVisibleCells() { return showVisibleCells; } + bool getShowEmptyCells() { return showEmptyCells; } + public slots: void setShowVisibleCells(bool show) { showVisibleCells = show; emit dirty(); } void setShowEmptyCells(bool show) { showEmptyCells = show; emit dirty(); } @@ -79,10 +82,10 @@ namespace render { class DrawItemSelectionConfig : public Job::Config { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty()) - Q_PROPERTY(bool showInsideItems MEMBER showInsideItems WRITE setShowInsideItems) - Q_PROPERTY(bool showInsideSubcellItems MEMBER showInsideSubcellItems WRITE setShowInsideSubcellItems) - Q_PROPERTY(bool showPartialItems MEMBER showPartialItems WRITE setShowPartialItems) - Q_PROPERTY(bool showPartialSubcellItems MEMBER showPartialSubcellItems WRITE setShowPartialSubcellItems) + Q_PROPERTY(bool showInsideItems READ getShowInsideItems WRITE setShowInsideItems NOTIFY dirty()) + Q_PROPERTY(bool showInsideSubcellItems READ getShowInsideSubcellItems WRITE setShowInsideSubcellItems NOTIFY dirty()) + Q_PROPERTY(bool showPartialItems READ getShowPartialItems WRITE setShowPartialItems NOTIFY dirty()) + Q_PROPERTY(bool showPartialSubcellItems READ getShowPartialSubcellItems WRITE setShowPartialSubcellItems NOTIFY dirty()) public: DrawItemSelectionConfig() : Job::Config(false) {} @@ -92,7 +95,12 @@ namespace render { bool showPartialItems{ true }; bool showPartialSubcellItems{ true }; - public slots: + bool getShowInsideItems() const { return showInsideItems; }; + bool getShowInsideSubcellItems() const { return showInsideSubcellItems; }; + bool getShowPartialItems() const { return showPartialItems; }; + bool getShowPartialSubcellItems() const { return showPartialSubcellItems; }; + + public slots: void setShowInsideItems(bool show) { showInsideItems = show; emit dirty(); } void setShowInsideSubcellItems(bool show) { showInsideSubcellItems = show; emit dirty(); } void setShowPartialItems(bool show) { showPartialItems = show; emit dirty(); } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 733f7d9e9c..08ff97fd17 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -20,12 +20,16 @@ using namespace render; -void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems) { +void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->args; - for (const auto& itemDetails : inItems) { - auto& item = scene->getItem(itemDetails.id); + int numItemsToDraw = (int)inItems.size(); + if (maxDrawnItems != -1) { + numItemsToDraw = glm::min(numItemsToDraw, maxDrawnItems); + } + for (auto i = 0; i < numItemsToDraw; ++i) { + auto& item = scene->getItem(inItems[i].id); item.render(args); } } @@ -69,7 +73,10 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext // render lights gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; - renderItems(sceneContext, renderContext, inLights); + renderItems(sceneContext, renderContext, inLights, _maxDrawn); args->_batch = nullptr; }); + + auto config = std::static_pointer_cast(renderContext->jobConfig); + config->setNumDrawn((int)inLights.size()); } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index fc2ab9682f..8a0f951028 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -16,15 +16,37 @@ namespace render { -void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems); +void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); + + +class DrawLightConfig : public Job::Config { + Q_OBJECT + Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) + Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) +public: + int getNumDrawn() { return numDrawn; } + void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } + + int maxDrawn{ -1 }; +signals: + void numDrawnChanged(); + void dirty(); + +protected: + int numDrawn{ 0 }; +}; + class DrawLight { public: - using JobModel = Job::ModelI; + using Config = DrawLightConfig; + using JobModel = Job::ModelI; + void configure(const Config& config) { _maxDrawn = config.maxDrawn; } void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inLights); protected: + int _maxDrawn; // initialized by Config }; } From 7c0bb72affad37496a437331133a1a3e42948a14 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 29 Mar 2016 18:32:46 -0700 Subject: [PATCH 043/115] started on making ~ mean the application directory in script paths --- libraries/script-engine/src/ScriptEngines.cpp | 39 +++++++++++++++++-- libraries/script-engine/src/ScriptEngines.h | 3 ++ libraries/script-engine/src/ScriptsModel.cpp | 20 +++------- libraries/shared/src/PathUtils.cpp | 4 +- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 339953cdb4..a62deb89bc 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -43,24 +43,55 @@ ScriptEngines::ScriptEngines() } QString normalizeScriptUrl(const QString& rawScriptUrl) { - if (!rawScriptUrl.startsWith("http:") && !rawScriptUrl.startsWith("https:") && !rawScriptUrl.startsWith("atp:")) { + if (!rawScriptUrl.startsWith("http:") && !rawScriptUrl.startsWith("https:") && !rawScriptUrl.startsWith("atp:")) { #ifdef Q_OS_LINUX if (rawScriptUrl.startsWith("file:")) { return rawScriptUrl; } return QUrl::fromLocalFile(rawScriptUrl).toString(); #else + QString fullNormal; if (rawScriptUrl.startsWith("file:")) { - return rawScriptUrl.toLower(); + fullNormal = rawScriptUrl.toLower(); + } else { + // Force lowercase on file scripts because of drive letter weirdness. + fullNormal = QUrl::fromLocalFile(rawScriptUrl).toString().toLower(); } - // Force lowercase on file scripts because of drive letter weirdness. - return QUrl::fromLocalFile(rawScriptUrl).toString().toLower(); + QString defaultScriptLoc = defaultScriptsLocation(); + if (fullNormal.startsWith(defaultScriptLoc)) { + return "~" + fullNormal.mid(defaultScriptLoc.size()); + } + return fullNormal; #endif } return QUrl(rawScriptUrl).toString(); } +QString expandScriptUrl(const QString& normalizedScriptURL) { + if (normalizedScriptURL.startsWith("http:") || + normalizedScriptURL.startsWith("https:") || + normalizedScriptURL.startsWith("atp:")) { + return QUrl(normalizedScriptURL).toString(); + } + + QUrl url; + if (normalizedScriptURL.startsWith("file:")) { + url = QUrl(normalizedScriptURL); + } else { + url = QUrl::fromLocalFile(normalizedScriptURL); + } + + QString path = url.path(); + QStringList splitPath = path.split("/"); + if (splitPath.size() > 0 && splitPath[0] == "~") { + QString defaultScriptLoc = defaultScriptsLocation(); + url.setPath(defaultScriptLoc + splitPath.mid(1).join("/")); + return url.toString(); + } +} + + QObject* scriptsModel(); void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) { diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index df60d6ff63..ab0d17d9f3 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -96,4 +96,7 @@ protected: ScriptsModelFilter _scriptsModelFilter; }; +QString normalizeScriptUrl(const QString& rawScriptUrl); +QString expandScriptUrl(const QString& normalizedScriptURL); + #endif // hifi_ScriptEngine_h diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 5a4f1734d8..5b368095e0 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -161,12 +161,8 @@ void ScriptsModel::requestDefaultFiles(QString marker) { QString localDir = url.toLocalFile() + "/scripts"; QDirIterator it(localDir, QStringList() << "*.js", QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { - QString jsFullPath = it.next(); - QString jsPartialPath = jsFullPath.mid(localDir.length() + 1); // + 1 to skip a separator - #if defined(Q_OS_WIN) || defined(Q_OS_OSX) - jsFullPath = jsFullPath.toLower(); - jsPartialPath = jsPartialPath.toLower(); - #endif + QString jsFullPath = normalizeScriptUrl(it.next()); + QString jsPartialPath = normalizeScriptUrl(jsFullPath.mid(localDir.length() + 1)); // + 1 to skip a separator _treeNodes.append(new TreeNodeScript(jsPartialPath, jsFullPath, SCRIPT_ORIGIN_DEFAULT)); } } else { @@ -231,7 +227,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == CONTAINER_NAME)) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == KEY_NAME) { xml.readNext(); - lastKey = xml.text().toString(); + lastKey = normalizeScriptUrl(xml.text().toString()); if (jsRegex.exactMatch(xml.text().toString())) { _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), defaultScriptsLocation() + "/" + lastKey, @@ -278,12 +274,8 @@ void ScriptsModel::reloadLocalFiles() { const QFileInfoList localFiles = _localDirectory.entryInfoList(); for (int i = 0; i < localFiles.size(); i++) { QFileInfo file = localFiles[i]; - QString fileName = file.fileName(); - QString absPath = file.absoluteFilePath(); - #if defined(Q_OS_WIN) || defined(Q_OS_OSX) - fileName = fileName.toLower(); - absPath = absPath.toLower(); - #endif + QString fileName = normalizeScriptUrl(file.fileName()); + QString absPath = normalizeScriptUrl(file.absoluteFilePath()); _treeNodes.append(new TreeNodeScript(fileName, absPath, SCRIPT_ORIGIN_LOCAL)); } rebuildTree(); @@ -310,7 +302,7 @@ void ScriptsModel::rebuildTree() { for (pathIterator = pathList.constBegin(); pathIterator != pathList.constEnd(); ++pathIterator) { hash.append(*pathIterator + "/"); if (!folders.contains(hash)) { - folders[hash] = new TreeNodeFolder(*pathIterator, parent); + folders[hash] = new TreeNodeFolder(normalizeScriptUrl(*pathIterator), parent); } parent = folders[hash]; } diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 4b4a9efa9e..2e8d4a4e6a 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -56,9 +56,9 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector Date: Wed, 30 Mar 2016 09:32:40 -0700 Subject: [PATCH 044/115] DUmb fix to the flickering issue by overshooting the inside volume of the light and avoid the failing region --- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 ++-- libraries/render-utils/src/spot_light.slf | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 74795e6735..a0b8f0ae84 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -435,9 +435,9 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... + const float OVER_CONSERVATIVE_SCALE = 1.1; if ((eyeHalfPlaneDistance > -nearRadius) && - (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) { - light->setShowContour(true); + (glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) { coneParam.w = 0.0f; batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 1239628ac6..8355dcf91b 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -37,8 +37,6 @@ void main(void) { // Kill if in front of the light volume float depth = frag.depthVal; if (depth < gl_FragCoord.z) { - _fragColor = vec4(1.0, 0.0, 0.0, 1.0); - return; discard; } From d056c41e251d6586f0f0d54e013d487daee2a025 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Mar 2016 13:55:24 -0800 Subject: [PATCH 045/115] Update to latest Oculus SDK, add input device support --- cmake/externals/LibOVR/CMakeLists.txt | 23 +- .../src/controllers/StandardControls.h | 3 + .../oculus/src/OculusBaseDisplayPlugin.cpp | 20 +- plugins/oculus/src/OculusBaseDisplayPlugin.h | 1 - .../oculus/src/OculusControllerManager.cpp | 218 ++++++++++++++++++ plugins/oculus/src/OculusControllerManager.h | 82 +++++++ plugins/oculus/src/OculusDisplayPlugin.cpp | 2 +- plugins/oculus/src/OculusHelpers.cpp | 39 +++- plugins/oculus/src/OculusHelpers.h | 4 +- plugins/oculus/src/OculusProvider.cpp | 4 +- 10 files changed, 354 insertions(+), 42 deletions(-) create mode 100644 plugins/oculus/src/OculusControllerManager.cpp create mode 100644 plugins/oculus/src/OculusControllerManager.h diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index a98745b404..5b8a689a9a 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -12,19 +12,16 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) # 0.5 public # URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip # URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9 -# 0.6 public -# URL http://static.oculus.com/sdk-downloads/0.6.0.1/Public/1435190862/ovr_sdk_win_0.6.0.1.zip -# URL_MD5 4b3ef825f9a1d6d3035c9f6820687da9 -# 0.8 public -# URL http://static.oculus.com/sdk-downloads/0.8.0.0/Public/1445451746/ovr_sdk_win_0.8.0.0.zip -# URL_MD5 54944b03b95149d6010f84eb701b9647 +# 1.3 public +# URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip +# URL_MD5 4d26faba0c1f35ff80bf674c96ed9259 if (WIN32) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://static.oculus.com/sdk-downloads/0.8.0.0/Public/1445451746/ovr_sdk_win_0.8.0.0.zip - URL_MD5 54944b03b95149d6010f84eb701b9647 + URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip + URL_MD5 a2dcf695e0f03a70fdd1ed7480585e82 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" @@ -33,14 +30,16 @@ if (WIN32) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - # FIXME need to account for different architectures - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL) + set(LIBOVR_DIR ${SOURCE_DIR}/OculusSDK/LibOVR) if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/x64/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL) + set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/x64/Release/VS2013 CACHE TYPE INTERNAL) else() - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL) + set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/Win32/Release/VS2013 CACHE TYPE INTERNAL) endif() + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${LIBOVR_DIR}/Include CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${LIBOVR_LIB_DIR}/LibOVR.lib CACHE TYPE INTERNAL) + elseif(APPLE) ExternalProject_Add( diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index 2b0613321e..f101ba6c51 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -81,6 +81,9 @@ namespace controller { // Triggers LT, RT, + // Grips (Oculus touch squeeze) + LG, + RG, NUM_STANDARD_AXES, LZ = LT, RZ = RT diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index e23d8cade6..8f4e8d665d 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -12,7 +12,7 @@ #include "OculusHelpers.h" void OculusBaseDisplayPlugin::resetSensors() { - ovr_RecenterPose(_session); + ovr_RecenterTrackingOrigin(_session); } void OculusBaseDisplayPlugin::updateHeadPose(uint32_t frameIndex) { @@ -42,36 +42,30 @@ bool OculusBaseDisplayPlugin::internalActivate() { _hmdDesc = ovr_GetHmdDesc(_session); - _ipd = ovr_GetFloat(_session, OVR_KEY_IPD, _ipd); - glm::uvec2 eyeSizes[2]; _viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; + _ipd = 0; ovr_for_each_eye([&](ovrEyeType eye) { _eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye]; ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_session, eye, _eyeFovs[eye]); ovrMatrix4f ovrPerspectiveProjection = - ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded); + ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL); _eyeProjections[eye] = toGlm(ovrPerspectiveProjection); - _eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeViewOffset)); + _eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeOffset)); eyeSizes[eye] = toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f)); - _viewScaleDesc.HmdToEyeViewOffset[eye] = erd.HmdToEyeViewOffset; + _viewScaleDesc.HmdToEyeOffset[eye] = erd.HmdToEyeOffset; + _ipd += glm::abs(glm::length(toGlm(erd.HmdToEyeOffset))); }); auto combinedFov = _eyeFovs[0]; combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan); - _cullingProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); + _cullingProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL)); _renderTargetSize = uvec2( eyeSizes[0].x + eyeSizes[1].x, std::max(eyeSizes[0].y, eyeSizes[1].y)); - if (!OVR_SUCCESS(ovr_ConfigureTracking(_session, - ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { - logWarning("Failed to attach to sensor device"); - } - - // Parent class relies on our _session intialization, so it must come after that. memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov)); _sceneLayer.Header.Type = ovrLayerType_EyeFov; _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index d21b0561bc..b5ec0769e0 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -30,7 +30,6 @@ protected: protected: ovrSession _session; ovrGraphicsLuid _luid; - float _ipd{ OVR_DEFAULT_IPD }; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrFovPort _eyeFovs[2]; ovrHmdDesc _hmdDesc; diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp new file mode 100644 index 0000000000..0761dc1655 --- /dev/null +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -0,0 +1,218 @@ +// +// OculusControllerManager.cpp +// input-plugins/src/input-plugins +// +// Created by Bradley Austin Davis 2016/03/04. +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "OculusControllerManager.h" + +#include + +#include +#include +#include + +#include +#include + +#include "OculusHelpers.h" + +Q_DECLARE_LOGGING_CATEGORY(oculus) + + +static const QString MENU_PARENT = "Avatar"; +static const QString MENU_NAME = "Oculus Touch Controllers"; +static const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; + +const QString OculusControllerManager::NAME = "Oculus"; + +bool OculusControllerManager::isSupported() const { + return oculusAvailable(); +} + +void OculusControllerManager::activate() { + InputPlugin::activate(); + if (!_session) { + _session = acquireOculusSession(); + } + Q_ASSERT(_session); + + // register with UserInputMapper + auto userInputMapper = DependencyManager::get(); + if (_remote) { + userInputMapper->registerDevice(_remote); + } + if (_touch) { + userInputMapper->registerDevice(_touch); + } +} + +void OculusControllerManager::deactivate() { + InputPlugin::deactivate(); + + if (_session) { + releaseOculusSession(); + _session = nullptr; + } + + // unregister with UserInputMapper + auto userInputMapper = DependencyManager::get(); + if (_touch) { + userInputMapper->removeDevice(_touch->getDeviceID()); + } + if (_remote) { + userInputMapper->removeDevice(_remote->getDeviceID()); + } +} + +void OculusControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { + PerformanceTimer perfTimer("OculusControllerManager::TouchDevice::update"); + + if (!OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { + qCWarning(oculus) << "Unable to read oculus input state"; + return; + } + + if (_touch) { + _touch->update(deltaTime, inputCalibrationData, jointsCaptured); + } + if (_remote) { + _remote->update(deltaTime, inputCalibrationData, jointsCaptured); + } +} + +void OculusControllerManager::pluginFocusOutEvent() { + if (_touch) { + _touch->focusOutEvent(); + } + if (_remote) { + _remote->focusOutEvent(); + } +} + +using namespace controller; + +static const std::vector> BUTTON_MAP { { + { ovrButton_X, X }, + { ovrButton_Y, Y }, + { ovrButton_A, A }, + { ovrButton_B, B }, + { ovrButton_LThumb, LS }, + { ovrButton_RThumb, RS }, + { ovrButton_LShoulder, LB }, + { ovrButton_RShoulder, RB }, +} }; + +static const std::vector> TOUCH_MAP { { + { ovrTouch_X, LEFT_SECONDARY_THUMB_TOUCH }, + { ovrTouch_Y, LEFT_SECONDARY_THUMB_TOUCH }, + { ovrTouch_A, RIGHT_SECONDARY_THUMB_TOUCH }, + { ovrTouch_B, RIGHT_SECONDARY_THUMB_TOUCH }, + { ovrTouch_LIndexTrigger, LEFT_PRIMARY_INDEX_TOUCH }, + { ovrTouch_RIndexTrigger, RIGHT_PRIMARY_INDEX_TOUCH }, + { ovrTouch_LThumb, LS_TOUCH }, + { ovrTouch_RThumb, RS_TOUCH }, + { ovrTouch_LThumbUp, LEFT_THUMB_UP }, + { ovrTouch_RThumbUp, RIGHT_THUMB_UP }, + { ovrTouch_LIndexPointing, LEFT_INDEX_POINT }, + { ovrTouch_RIndexPointing, RIGHT_INDEX_POINT }, +} }; + +void OculusControllerManager::TouchDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { + _poseStateMap.clear(); + _buttonPressedMap.clear(); + + if (!jointsCaptured) { + int numTrackedControllers = 0; + static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked & ovrStatus_PositionTracked; + auto tracking = ovr_GetTrackingState(_parent._session, 0, false); + ovr_for_each_hand([&](ovrHandType hand) { + ++numTrackedControllers; + if (REQUIRED_HAND_STATUS == (tracking.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) { + handlePose(deltaTime, inputCalibrationData, hand, tracking.HandPoses[hand]); + } + }); + } + using namespace controller; + // Axes + const auto& inputState = _parent._inputState; + _axisStateMap[LX] = inputState.Thumbstick[ovrHand_Left].x; + _axisStateMap[LY] = inputState.Thumbstick[ovrHand_Left].y; + _axisStateMap[LT] = inputState.IndexTrigger[ovrHand_Left]; + _axisStateMap[LG] = inputState.HandTrigger[ovrHand_Left]; + + _axisStateMap[RX] = inputState.Thumbstick[ovrHand_Right].x; + _axisStateMap[RY] = inputState.Thumbstick[ovrHand_Right].y; + _axisStateMap[RT] = inputState.IndexTrigger[ovrHand_Right]; + _axisStateMap[RG] = inputState.HandTrigger[ovrHand_Right]; + + // Buttons + for (const auto& pair : BUTTON_MAP) { + if (inputState.Buttons & pair.first) { + _buttonPressedMap.insert(pair.second); + } + } + // Touches + for (const auto& pair : TOUCH_MAP) { + if (inputState.Touches & pair.first) { + _buttonPressedMap.insert(pair.second); + } + } +} + +void OculusControllerManager::TouchDevice::focusOutEvent() { + _axisStateMap.clear(); + _buttonPressedMap.clear(); +}; + +void OculusControllerManager::TouchDevice::handlePose(float deltaTime, + const controller::InputCalibrationData& inputCalibrationData, ovrHandType hand, + const ovrPoseStatef& handPose) { + auto poseId = hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND; + auto& pose = _poseStateMap[poseId]; + pose.translation = toGlm(handPose.ThePose.Position); + pose.rotation = toGlm(handPose.ThePose.Orientation); + pose.angularVelocity = toGlm(handPose.AngularVelocity); + pose.velocity = toGlm(handPose.LinearVelocity); +} + +controller::Input::NamedVector OculusControllerManager::TouchDevice::getAvailableInputs() const { + using namespace controller; + QVector availableInputs{ + // Trackpad analogs + makePair(LX, "LX"), + makePair(LY, "LY"), + makePair(RX, "RX"), + makePair(RY, "RY"), + // trigger analogs + makePair(LT, "LT"), + makePair(RT, "RT"), + + makePair(LB, "LB"), + makePair(RB, "RB"), + + makePair(LS, "LS"), + makePair(RS, "RS"), + makePair(LEFT_HAND, "LeftHand"), + makePair(RIGHT_HAND, "RightHand"), + + makePair(LEFT_PRIMARY_THUMB, "LeftPrimaryThumb"), + makePair(LEFT_SECONDARY_THUMB, "LeftSecondaryThumb"), + makePair(RIGHT_PRIMARY_THUMB, "RightPrimaryThumb"), + makePair(RIGHT_SECONDARY_THUMB, "RightSecondaryThumb"), + }; + return availableInputs; +} + +QString OculusControllerManager::TouchDevice::getDefaultMappingConfig() const { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/touch.json"; + return MAPPING_JSON; +} + + + diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h new file mode 100644 index 0000000000..7a30b19aa4 --- /dev/null +++ b/plugins/oculus/src/OculusControllerManager.h @@ -0,0 +1,82 @@ +// +// Created by Bradley Austin Davis on 2016/03/04 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi__OculusControllerManager +#define hifi__OculusControllerManager + +#include +#include + +#include + +#include +#include + +#include + +class OculusControllerManager : public InputPlugin { + Q_OBJECT +public: + // Plugin functions + bool isSupported() const override; + bool isJointController() const override { return true; } + const QString& getName() const override { return NAME; } + + void activate() override; + void deactivate() override; + + void pluginFocusOutEvent() override; + void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; + +private: + class OculusInputDevice : public controller::InputDevice { + public: + OculusInputDevice(OculusControllerManager& parent, const QString& name) : controller::InputDevice(name), _parent(parent) {} + + OculusControllerManager& _parent; + friend class OculusControllerManager; + }; + + // Waiting on touch API + class RemoteDevice : public OculusInputDevice { + public: + using Pointer = std::shared_ptr; + RemoteDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "Oculus Remote") {} + + controller::Input::NamedVector getAvailableInputs() const override; + QString getDefaultMappingConfig() const override; + void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; + void focusOutEvent() override; + + friend class OculusControllerManager; + }; + + class TouchDevice : public OculusInputDevice { + public: + using Pointer = std::shared_ptr; + TouchDevice(OculusControllerManager& parent) : OculusInputDevice(parent, "Oculus Touch") {} + + controller::Input::NamedVector getAvailableInputs() const override; + QString getDefaultMappingConfig() const override; + void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; + void focusOutEvent() override; + + private: + void handlePose(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, ovrHandType hand, const ovrPoseStatef& handPose); + int _trackedControllers { 0 }; + friend class OculusControllerManager; + }; + + ovrSession _session { nullptr }; + ovrInputState _inputState {}; + RemoteDevice::Pointer _remote; + TouchDevice::Pointer _touch; + static const QString NAME; +}; + +#endif // hifi__OculusControllerManager diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 8c3a676c61..1a5a32ffb2 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -70,5 +70,5 @@ void OculusDisplayPlugin::hmdPresent() { logWarning("Failed to present"); } } - _sceneFbo->Increment(); + _sceneFbo->Commit(); } diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 170be05952..d38303919e 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -98,9 +98,8 @@ SwapFramebufferWrapper::~SwapFramebufferWrapper() { destroyColor(); } -void SwapFramebufferWrapper::Increment() { - ++color->CurrentIndex; - color->CurrentIndex %= color->TextureCount; +void SwapFramebufferWrapper::Commit() { + ovr_CommitTextureSwapChain(_session, color); } void SwapFramebufferWrapper::Resize(const uvec2 & size) { @@ -114,7 +113,7 @@ void SwapFramebufferWrapper::Resize(const uvec2 & size) { void SwapFramebufferWrapper::destroyColor() { if (color) { - ovr_DestroySwapTextureSet(_session, color); + ovr_DestroyTextureSwapChain(_session, color); color = nullptr; } } @@ -122,13 +121,30 @@ void SwapFramebufferWrapper::destroyColor() { void SwapFramebufferWrapper::initColor() { destroyColor(); - if (!OVR_SUCCESS(ovr_CreateSwapTextureSetGL(_session, GL_SRGB8_ALPHA8, size.x, size.y, &color))) { + ovrTextureSwapChainDesc desc = {}; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Width = size.x; + desc.Height = size.y; + desc.MipLevels = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + desc.SampleCount = 1; + desc.StaticImage = ovrFalse; + + ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &color); + if (!OVR_SUCCESS(result)) { logFatal("Failed to create swap textures"); } - for (int i = 0; i < color->TextureCount; ++i) { - ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i]; - glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId); + int length = 0; + result = ovr_GetTextureSwapChainLength(_session, color, &length); + if (!OVR_SUCCESS(result) || !length) { + qFatal("Unable to count swap chain textures"); + } + for (int i = 0; i < length; ++i) { + GLuint chainTexId; + ovr_GetTextureSwapChainBufferGL(_session, color, i, &chainTexId); + glBindTexture(GL_TEXTURE_2D, chainTexId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -141,8 +157,11 @@ void SwapFramebufferWrapper::initDone() { } void SwapFramebufferWrapper::onBind(oglplus::Framebuffer::Target target) { - ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]); - glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0); + int curIndex; + ovr_GetTextureSwapChainCurrentIndex(_session, color, &curIndex); + GLuint curTexId; + ovr_GetTextureSwapChainBufferGL(_session, color, curIndex, &curTexId); + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0); } void SwapFramebufferWrapper::onUnbind(oglplus::Framebuffer::Target target) { diff --git a/plugins/oculus/src/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h index e10e058ad2..2f13c45466 100644 --- a/plugins/oculus/src/OculusHelpers.h +++ b/plugins/oculus/src/OculusHelpers.h @@ -111,10 +111,10 @@ inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) { // then submit it and increment to the next texture. // The Oculus SDK manages the creation and destruction of // the textures -struct SwapFramebufferWrapper : public FramebufferWrapper { +struct SwapFramebufferWrapper : public FramebufferWrapper { SwapFramebufferWrapper(const ovrSession& session); ~SwapFramebufferWrapper(); - void Increment(); + void Commit(); void Resize(const uvec2 & size); protected: void initColor() override final; diff --git a/plugins/oculus/src/OculusProvider.cpp b/plugins/oculus/src/OculusProvider.cpp index be708db932..e723fa839a 100644 --- a/plugins/oculus/src/OculusProvider.cpp +++ b/plugins/oculus/src/OculusProvider.cpp @@ -18,6 +18,7 @@ #include "OculusDisplayPlugin.h" #include "OculusDebugDisplayPlugin.h" +#include "OculusControllerManager.h" class OculusProvider : public QObject, public DisplayProvider, InputProvider { @@ -51,8 +52,6 @@ public: } virtual InputPluginList getInputPlugins() override { - // FIXME pending full oculus input API and hardware -#if 0 static std::once_flag once; std::call_once(once, [&] { InputPluginPointer plugin(new OculusControllerManager()); @@ -60,7 +59,6 @@ public: _inputPlugins.push_back(plugin); } }); -#endif return _inputPlugins; } From bd9813bbf59c48f69a8767d3ad0d72a1830bb1ae Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 28 Mar 2016 12:00:40 -0700 Subject: [PATCH 046/115] Only enable the Oculus plugin in the presence of the 1.x runtime --- plugins/oculus/src/OculusBaseDisplayPlugin.h | 2 +- plugins/oculus/src/OculusControllerManager.h | 1 - plugins/oculus/src/OculusHelpers.cpp | 16 +++++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index b5ec0769e0..41344335f3 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -28,7 +28,7 @@ protected: void internalDeactivate() override; protected: - ovrSession _session; + ovrSession _session { nullptr }; ovrGraphicsLuid _luid; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrFovPort _eyeFovs[2]; diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h index 7a30b19aa4..fb126ca2a8 100644 --- a/plugins/oculus/src/OculusControllerManager.h +++ b/plugins/oculus/src/OculusControllerManager.h @@ -42,7 +42,6 @@ private: friend class OculusControllerManager; }; - // Waiting on touch API class RemoteDevice : public OculusInputDevice { public: using Pointer = std::shared_ptr; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index d38303919e..fdd35a06fe 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -9,7 +9,9 @@ #include "OculusHelpers.h" #include + #include +#include using Mutex = std::mutex; using Lock = std::unique_lock; @@ -38,9 +40,21 @@ void logFatal(const char* what) { qFatal(error.c_str()); } +static const QString GOOD_OCULUS_RUNTIME_FILE { "C:\\Program Files(x86)\\Oculus\\Support\\oculus - runtime\\LibOVRRT64_1.dll" }; + bool oculusAvailable() { ovrDetectResult detect = ovr_Detect(0); - return (detect.IsOculusServiceRunning && detect.IsOculusHMDConnected); + if (!detect.IsOculusServiceRunning || !detect.IsOculusHMDConnected) { + return false; + } + + // HACK Explicitly check for the presence of the 1.0 runtime DLL, and fail if it + // doesn't exist + if (!QFile(GOOD_OCULUS_RUNTIME_FILE).exists()) { + return false; + } + + return true; } ovrSession acquireOculusSession() { From 78626f793831bd603e4dbdf400cafcb18a631a92 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 28 Mar 2016 13:00:15 -0700 Subject: [PATCH 047/115] Add warning logging if we can't find a 1.x Oculus dll --- plugins/oculus/src/OculusHelpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index fdd35a06fe..cfac175392 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -51,6 +51,7 @@ bool oculusAvailable() { // HACK Explicitly check for the presence of the 1.0 runtime DLL, and fail if it // doesn't exist if (!QFile(GOOD_OCULUS_RUNTIME_FILE).exists()) { + qCWarning(oculus) << "Oculus Runtime detected, but no 1.x DLL present."; return false; } From 80d397555ddb7388d8a60ea054df58b6eb30047c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 28 Mar 2016 14:45:09 -0700 Subject: [PATCH 048/115] Fixing input API, DLL path for Oculus --- plugins/oculus/src/OculusControllerManager.cpp | 3 ++- plugins/oculus/src/OculusControllerManager.h | 2 +- plugins/oculus/src/OculusHelpers.cpp | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp index 0761dc1655..f11ec18b10 100644 --- a/plugins/oculus/src/OculusControllerManager.cpp +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -35,7 +35,7 @@ bool OculusControllerManager::isSupported() const { return oculusAvailable(); } -void OculusControllerManager::activate() { +bool OculusControllerManager::activate() { InputPlugin::activate(); if (!_session) { _session = acquireOculusSession(); @@ -50,6 +50,7 @@ void OculusControllerManager::activate() { if (_touch) { userInputMapper->registerDevice(_touch); } + return true; } void OculusControllerManager::deactivate() { diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h index fb126ca2a8..fc10dcc73d 100644 --- a/plugins/oculus/src/OculusControllerManager.h +++ b/plugins/oculus/src/OculusControllerManager.h @@ -27,7 +27,7 @@ public: bool isJointController() const override { return true; } const QString& getName() const override { return NAME; } - void activate() override; + bool activate() override; void deactivate() override; void pluginFocusOutEvent() override; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index cfac175392..fb49d1d001 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -12,6 +12,7 @@ #include #include +#include using Mutex = std::mutex; using Lock = std::unique_lock; @@ -40,7 +41,8 @@ void logFatal(const char* what) { qFatal(error.c_str()); } -static const QString GOOD_OCULUS_RUNTIME_FILE { "C:\\Program Files(x86)\\Oculus\\Support\\oculus - runtime\\LibOVRRT64_1.dll" }; +static const QString OCULUS_RUNTIME_PATH { "C:\\Program Files (x86)\\Oculus\\Support\\oculus-runtime" }; +static const QString GOOD_OCULUS_RUNTIME_FILE { OCULUS_RUNTIME_PATH + "\\LibOVRRT64_1.dll" }; bool oculusAvailable() { ovrDetectResult detect = ovr_Detect(0); From 8123617fe1e50e695b28368a2b0beb474768f173 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 29 Mar 2016 09:41:38 -0700 Subject: [PATCH 049/115] Improve failure detection logging --- plugins/oculus/src/OculusHelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index fb49d1d001..98dfa43fa2 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -53,7 +53,7 @@ bool oculusAvailable() { // HACK Explicitly check for the presence of the 1.0 runtime DLL, and fail if it // doesn't exist if (!QFile(GOOD_OCULUS_RUNTIME_FILE).exists()) { - qCWarning(oculus) << "Oculus Runtime detected, but no 1.x DLL present."; + qCWarning(oculus) << "Oculus Runtime detected, but no 1.x DLL present: \"" + GOOD_OCULUS_RUNTIME_FILE + "\""; return false; } From f569cbf70ef40c15699acb31ef374e5b31c25cee Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 30 Mar 2016 09:56:26 -0700 Subject: [PATCH 050/115] Add debugging output, fix timewarp --- interface/src/Application.cpp | 25 +++++++++++------ .../display-plugins/OpenGLDisplayPlugin.cpp | 4 +-- .../src/display-plugins/OpenGLDisplayPlugin.h | 2 +- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 28 ++++++++++++++----- .../display-plugins/hmd/HmdDisplayPlugin.h | 18 +++++++++--- libraries/plugins/src/plugins/DisplayPlugin.h | 4 ++- libraries/shared/src/ThreadSafeValueCache.h | 1 + .../oculus/src/OculusBaseDisplayPlugin.cpp | 15 ++++++---- plugins/oculus/src/OculusBaseDisplayPlugin.h | 3 +- plugins/oculus/src/OculusDisplayPlugin.cpp | 28 ++++++++++++++----- plugins/oculus/src/OculusDisplayPlugin.h | 3 +- plugins/oculus/src/OculusHelpers.cpp | 3 +- .../src/OculusLegacyDisplayPlugin.cpp | 10 +++++-- .../src/OculusLegacyDisplayPlugin.h | 2 +- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 22 +++++++++------ plugins/openvr/src/OpenVrDisplayPlugin.h | 2 +- 16 files changed, 117 insertions(+), 53 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index de9b134b83..895f3fd52f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1490,11 +1490,15 @@ void Application::paintGL() { // FIXME not needed anymore? _offscreenContext->makeCurrent(); - displayPlugin->updateHeadPose(_frameCount); + displayPlugin->beginFrameRender(_frameCount); // update the avatar with a fresh HMD pose getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose()); + // update sensorToWorldMatrix for camera and hand controllers + getMyAvatar()->updateSensorToWorldMatrix(); + + auto lodManager = DependencyManager::get(); @@ -2007,6 +2011,12 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; + case Qt::Key_Y: + if (isShifted && isMeta) { + getActiveDisplayPlugin()->cycleDebugOutput(); + } + break; + case Qt::Key_B: if (isMeta) { auto offscreenUi = DependencyManager::get(); @@ -2572,11 +2582,6 @@ void Application::idle(uint64_t now) { return; // bail early, nothing to do here. } - checkChangeCursor(); - - Stats::getInstance()->updateStats(); - AvatarInputs::getInstance()->update(); - // These tasks need to be done on our first idle, because we don't want the showing of // overlay subwindows to do a showDesktop() until after the first time through static bool firstIdle = true; @@ -2625,6 +2630,11 @@ void Application::idle(uint64_t now) { // We're going to execute idle processing, so restart the last idle timer _lastTimeUpdated.start(); + checkChangeCursor(); + + Stats::getInstance()->updateStats(); + AvatarInputs::getInstance()->update(); + { static uint64_t lastIdleStart{ now }; uint64_t idleStartToStartDuration = now - lastIdleStart; @@ -3389,9 +3399,6 @@ void Application::update(float deltaTime) { qApp->updateMyAvatarLookAtPosition(); - // update sensorToWorldMatrix for camera and hand controllers - myAvatar->updateSensorToWorldMatrix(); - { PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount()); avatarManager->updateMyAvatar(deltaTime); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 8049e2d5a5..e5d98d18f7 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -552,9 +552,9 @@ float OpenGLDisplayPlugin::presentRate() { { Lock lock(_mutex); result = _usecsPerFrame.getAverage(); - result = 1.0f / result; - result *= USECS_PER_SECOND; } + result = 1.0f / result; + result *= USECS_PER_SECOND; return result; } diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index b9628deb6c..8c4862ee3d 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -17,9 +17,9 @@ #include #include #include +#include #define THREADED_PRESENT 1 -#include class OpenGLDisplayPlugin : public DisplayPlugin { protected: diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 5be3f0d96a..505fa004ab 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -69,10 +69,11 @@ void HmdDisplayPlugin::compositeOverlay() { // set the alpha Uniform(*_program, _alphaUniform).Set(overlayAlpha); + auto eyePoses = _currentPresentFrameInfo.eyePoses; _sphereSection->Use(); for_each_eye([&](Eye eye) { eyeViewport(eye); - auto modelView = glm::inverse(_currentRenderEyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1)); + auto modelView = glm::inverse(eyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1)); auto mvp = _eyeProjections[eye] * modelView; Uniform(*_program, _mvpUniform).Set(mvp); _sphereSection->Draw(); @@ -95,10 +96,10 @@ void HmdDisplayPlugin::compositePointer() { // Mouse pointer _plane->Use(); // Reconstruct the headpose from the eye poses - auto headPosition = (vec3(_currentRenderEyePoses[Left][3]) + vec3(_currentRenderEyePoses[Right][3])) / 2.0f; + auto headPosition = vec3(_currentPresentFrameInfo.headPose[3]); for_each_eye([&](Eye eye) { eyeViewport(eye); - auto reticleTransform = compositorHelper->getReticleTransform(_currentRenderEyePoses[eye], headPosition); + auto reticleTransform = compositorHelper->getReticleTransform(_currentPresentFrameInfo.eyePoses[eye], headPosition); auto mvp = _eyeProjections[eye] * reticleTransform; Uniform(*_program, _mvpUniform).Set(mvp); _plane->Draw(); @@ -160,15 +161,28 @@ void HmdDisplayPlugin::internalPresent() { void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { Lock lock(_mutex); - _renderEyePoses[frameIndex][eye] = pose; + FrameInfo& frame = _frameInfos[frameIndex]; + frame.eyePoses[eye] = pose; } void HmdDisplayPlugin::updateFrameData() { + // Check if we have old frame data to discard + { + Lock lock(_mutex); + auto itr = _frameInfos.find(_currentRenderFrameIndex); + if (itr != _frameInfos.end()) { + _frameInfos.erase(itr); + } + } + Parent::updateFrameData(); - Lock lock(_mutex); - _currentRenderEyePoses = _renderEyePoses[_currentRenderFrameIndex]; + + { + Lock lock(_mutex); + _currentPresentFrameInfo = _frameInfos[_currentRenderFrameIndex]; + } } glm::mat4 HmdDisplayPlugin::getHeadPose() const { - return _headPoseCache.get(); + return _currentRenderFrameInfo.get().headPose; } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 080a44bc66..899dd6636a 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -28,6 +28,16 @@ public: virtual glm::mat4 getHeadPose() const override; + using EyePoses = std::array; + + struct FrameInfo { + EyePoses eyePoses; + glm::mat4 headPose; + double sensorSampleTime { 0 }; + double predictedDisplayTime { 0 }; + }; + + protected: virtual void hmdPresent() = 0; virtual bool isHmdMounted() const = 0; @@ -46,10 +56,10 @@ protected: glm::mat4 _cullingProjection; glm::uvec2 _renderTargetSize; float _ipd { 0.064f }; - using EyePoses = std::array; - QMap _renderEyePoses; - EyePoses _currentRenderEyePoses; - ThreadSafeValueCache _headPoseCache { glm::mat4() }; + + QMap _frameInfos; + FrameInfo _currentPresentFrameInfo; + ThreadSafeValueCache _currentRenderFrameInfo; private: bool _enablePreview { false }; diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index f4f28176c7..77d984f924 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -122,7 +122,7 @@ public: } // will query the underlying hmd api to compute the most recent head pose - virtual void updateHeadPose(uint32_t frameIndex) {} + virtual void beginFrameRender(uint32_t frameIndex) {} // returns a copy of the most recent head pose, computed via updateHeadPose virtual glm::mat4 getHeadPose() const { @@ -142,6 +142,8 @@ public: virtual float presentRate() { return -1.0f; } uint32_t presentCount() const { return _presentedFrameIndex; } + virtual void cycleDebugOutput() {} + static const QString& MENU_PATH(); signals: diff --git a/libraries/shared/src/ThreadSafeValueCache.h b/libraries/shared/src/ThreadSafeValueCache.h index e4e78ca3d7..37a1258aa1 100644 --- a/libraries/shared/src/ThreadSafeValueCache.h +++ b/libraries/shared/src/ThreadSafeValueCache.h @@ -23,6 +23,7 @@ template class ThreadSafeValueCache { public: + ThreadSafeValueCache() {} ThreadSafeValueCache(const T& v) : _value { v } {} // returns atomic copy of the cached value. diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 8f4e8d665d..52eb70134d 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -15,11 +15,16 @@ void OculusBaseDisplayPlugin::resetSensors() { ovr_RecenterTrackingOrigin(_session); } -void OculusBaseDisplayPlugin::updateHeadPose(uint32_t frameIndex) { - auto displayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); - auto trackingState = ovr_GetTrackingState(_session, displayTime, true); - mat4 headPose = toGlm(trackingState.HeadPose.ThePose); - _headPoseCache.set(headPose); +void OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { + FrameInfo frame; + frame.sensorSampleTime = ovr_GetTimeInSeconds();; + frame.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); + auto trackingState = ovr_GetTrackingState(_session, frame.predictedDisplayTime, ovrTrue); + frame.headPose = toGlm(trackingState.HeadPose.ThePose); + + _currentRenderFrameInfo.set(frame); + Lock lock(_mutex); + _frameInfos[frameIndex] = frame; } bool OculusBaseDisplayPlugin::isSupported() const { diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index 41344335f3..2259a4ca89 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -20,7 +20,8 @@ public: // Stereo specific methods virtual void resetSensors() override final; - virtual void updateHeadPose(uint32_t frameIndex) override; + virtual void beginFrameRender(uint32_t frameIndex) override; + protected: void customizeContext() override; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 1a5a32ffb2..8078e8d6ec 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -10,6 +10,23 @@ #include "OculusHelpers.h" const QString OculusDisplayPlugin::NAME("Oculus Rift"); +static ovrPerfHudMode currentDebugMode = ovrPerfHud_Off; + +bool OculusDisplayPlugin::internalActivate() { + bool result = Parent::internalActivate(); + currentDebugMode = ovrPerfHud_Off; + if (result && _session) { + ovr_SetInt(_session, OVR_PERF_HUD_MODE, currentDebugMode); + } + return result; +} + +void OculusDisplayPlugin::cycleDebugOutput() { + if (_session) { + currentDebugMode = static_cast((currentDebugMode + 1) % ovrPerfHud_Count); + ovr_SetInt(_session, OVR_PERF_HUD_MODE, currentDebugMode); + } +} void OculusDisplayPlugin::customizeContext() { Parent::customizeContext(); @@ -48,12 +65,6 @@ void blit(const SrcFbo& srcFbo, const DstFbo& dstFbo) { }); } -void OculusDisplayPlugin::updateFrameData() { - Parent::updateFrameData(); - _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentRenderEyePoses[Left]); - _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentRenderEyePoses[Right]); -} - void OculusDisplayPlugin::hmdPresent() { PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex) @@ -63,12 +74,15 @@ void OculusDisplayPlugin::hmdPresent() { } blit(_compositeFramebuffer, _sceneFbo); + _sceneFbo->Commit(); { + _sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime; + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.headPose); + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.headPose); ovrLayerHeader* layers = &_sceneLayer.Header; ovrResult result = ovr_SubmitFrame(_session, _currentRenderFrameIndex, &_viewScaleDesc, &layers, 1); if (!OVR_SUCCESS(result)) { logWarning("Failed to present"); } } - _sceneFbo->Commit(); } diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index 9b6b922f69..e7d7791e7f 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -22,12 +22,13 @@ public: float getTargetFrameRate() override { return TARGET_RATE_Oculus; } protected: + bool internalActivate() override; void hmdPresent() override; // FIXME update with Oculus API call once it's available in the SDK bool isHmdMounted() const override { return true; } void customizeContext() override; void uncustomizeContext() override; - void updateFrameData() override; + void cycleDebugOutput() override; private: static const QString NAME; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 98dfa43fa2..c9e702ecd0 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -116,7 +116,8 @@ SwapFramebufferWrapper::~SwapFramebufferWrapper() { } void SwapFramebufferWrapper::Commit() { - ovr_CommitTextureSwapChain(_session, color); + auto result = ovr_CommitTextureSwapChain(_session, color); + Q_ASSERT(OVR_SUCCESS(result)); } void SwapFramebufferWrapper::Resize(const uvec2 & size) { diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 396f55b932..7b9dcc0b7d 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -35,10 +35,14 @@ void OculusLegacyDisplayPlugin::resetSensors() { ovrHmd_RecenterPose(_hmd); } -void OculusLegacyDisplayPlugin::updateHeadPose(uint32_t frameIndex) { +void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) { + FrameInfo frame; + frame.predictedDisplayTime = frame.sensorSampleTime = ovr_GetTimeInSeconds(); + _trackingState = ovrHmd_GetTrackingState(_hmd, frame.predictedDisplayTime); + frame.headPose = toGlm(_trackingState.HeadPose.ThePose); + _currentRenderFrameInfo.set(frame); Lock lock(_mutex); - _trackingState = ovrHmd_GetTrackingState(_hmd, ovr_GetTimeInSeconds()); - _headPoseCache.set(toGlm(_trackingState.HeadPose.ThePose)); + _frameInfos[frameIndex] = frame; } bool OculusLegacyDisplayPlugin::isSupported() const { diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index 187c0681e9..2710ab1335 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -26,7 +26,7 @@ public: // Stereo specific methods virtual void resetSensors() override; - virtual void updateHeadPose(uint32_t frameIndex) override; + virtual void beginFrameRender(uint32_t frameIndex) override; virtual float getTargetFrameRate() override; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index c4d8b252f0..f968ae440e 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -121,22 +121,23 @@ void OpenVrDisplayPlugin::resetSensors() { _sensorResetMat = glm::inverse(cancelOutRollAndPitch(m)); } -void OpenVrDisplayPlugin::updateHeadPose(uint32_t frameIndex) { +void OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { - float displayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float); - float frameDuration = 1.f / displayFrequency; - float vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float); + double displayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float); + double frameDuration = 1.f / displayFrequency; + double vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float); + FrameInfo frame; #if THREADED_PRESENT // 3 frames of prediction + vsyncToPhotons = 44ms total - const float NUM_PREDICTION_FRAMES = 3.0f; - float predictedSecondsFromNow = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons; + const double NUM_PREDICTION_FRAMES = 3.0f; + frame.predictedDisplayTime = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons; #else - float predictedSecondsFromNow = frameDuration + vsyncToPhotons; + frame.predictedDisplayTime = frameDuration + vsyncToPhotons; #endif vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount]; - _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount); + _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, frame.predictedDisplayTime, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount); // copy and process predictedTrackedDevicePoses for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { @@ -145,8 +146,11 @@ void OpenVrDisplayPlugin::updateHeadPose(uint32_t frameIndex) { _trackedDeviceLinearVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vVelocity)); _trackedDeviceAngularVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vAngularVelocity)); } + frame.headPose = _trackedDevicePoseMat4[0]; + _currentRenderFrameInfo.set(frame); - _headPoseCache.set(_trackedDevicePoseMat4[0]); + Lock lock(_mutex); + _frameInfos[frameIndex] = frame; } void OpenVrDisplayPlugin::hmdPresent() { diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 022af5b06d..0e1e7c5267 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -27,7 +27,7 @@ public: // Stereo specific methods virtual void resetSensors() override; - virtual void updateHeadPose(uint32_t frameIndex) override; + virtual void beginFrameRender(uint32_t frameIndex) override; protected: bool internalActivate() override; From 37e6fce30b8b91d5d0fefce2a0ed056cf6df4ef9 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 30 Mar 2016 10:48:54 -0700 Subject: [PATCH 051/115] Disconnect menuItemEvent before setIsOptionChecked, and then reconnect. --- examples/selectAudioDevice.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/selectAudioDevice.js b/examples/selectAudioDevice.js index b1da219eb5..c86d034adb 100644 --- a/examples/selectAudioDevice.js +++ b/examples/selectAudioDevice.js @@ -120,21 +120,25 @@ function menuItemEvent(menuItem) { if (menuItem.endsWith(" for Output")) { var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Output"); print("output audio selection..." + selectedDevice); + Menu.menuItemEvent.disconnect(menuItemEvent); Menu.setIsOptionChecked(selectedOutputMenu, false); selectedOutputMenu = menuItem; Menu.setIsOptionChecked(selectedOutputMenu, true); if (AudioDevice.setOutputDevice(selectedDevice)) { Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice); } + Menu.menuItemEvent.connect(menuItemEvent); } else if (menuItem.endsWith(" for Input")) { var selectedDevice = menuItem.trimStartsWith("Use ").trimEndsWith(" for Input"); print("input audio selection..." + selectedDevice); + Menu.menuItemEvent.disconnect(menuItemEvent); Menu.setIsOptionChecked(selectedInputMenu, false); selectedInputMenu = menuItem; Menu.setIsOptionChecked(selectedInputMenu, true); if (AudioDevice.setInputDevice(selectedDevice)) { Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice); } + Menu.menuItemEvent.connect(menuItemEvent); } } } From 24acf7584a2f336d35d8b8a2316ee8957443d5db Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 11:10:14 -0700 Subject: [PATCH 052/115] don't respond to http other than /status --- ice-server/src/IceServer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index d7fba12f26..2d52f9fc82 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -313,7 +313,10 @@ bool IceServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, b ? 1 : 0; connection->respond(HTTPConnection::StatusCode200, QByteArray::number(statusNumber)); + + return true; } } - return true; + + return false; } From 0ee1f039e9ba0dd52825e3fd3b2809aba8307cf6 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 30 Mar 2016 11:15:10 -0700 Subject: [PATCH 053/115] Telling like it is... --- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a0b8f0ae84..ac24b09c40 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -435,7 +435,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - const float OVER_CONSERVATIVE_SCALE = 1.1; + const float OVER_CONSERVATIVE_SCALE = 1.1f; if ((eyeHalfPlaneDistance > -nearRadius) && (glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) { coneParam.w = 0.0f; From 1234514e8fcabacc85d89d8aa85bdddbb6008ff4 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 30 Mar 2016 11:22:44 -0700 Subject: [PATCH 054/115] Correctly represent light fbo fmt --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 11 ++++++----- libraries/gpu/src/gpu/Texture.cpp | 2 +- libraries/render-utils/src/FramebufferCache.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 09714b5542..3fc7906285 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -225,6 +225,12 @@ public: } break; + case gpu::R11G11B10: + texel.format = GL_RGB; + // the type should be float + texel.internalFormat = GL_R11F_G11F_B10F; + break; + case gpu::DEPTH: texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it texel.internalFormat = GL_DEPTH_COMPONENT; @@ -302,11 +308,6 @@ public: case gpu::SRGBA: texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color break; - case gpu::R11G11B10: { - // the type should be float - texel.internalFormat = GL_R11F_G11F_B10F; - break; - } default: qCDebug(gpulogging) << "Unknown combination of texel format"; } diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index df93cd76a5..af740ddb65 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -285,7 +285,7 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt } // Here the Texture has been fully defined from the gpu point of view (size and format) - _defined = true; + _defined = true; } else { _stamp++; } diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 7948dfcefe..22bfbfd869 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -97,7 +97,7 @@ void FramebufferCache::createPrimaryFramebuffer() { // FIXME: Decide on the proper one, let s stick to R11G11B10 for now //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler)); - _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); + _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler)); //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); From 1771875186873097789cbabdbd376b6925ae974d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 11:31:46 -0700 Subject: [PATCH 055/115] use one QNetworkAccessManager for the ice-server --- ice-server/src/IceServer.cpp | 9 +++++---- ice-server/src/IceServer.h | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 2d52f9fc82..ac5952ce43 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -33,7 +33,8 @@ IceServer::IceServer(int argc, char* argv[]) : _id(QUuid::createUuid()), _serverSocket(), _activePeers(), - _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this) + _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this), + _networkAccessManager(this) { // start the ice-server socket qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; @@ -201,8 +202,8 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla void IceServer::requestDomainPublicKey(const QUuid& domainID) { // send a request to the metaverse API for the public key for this domain - QNetworkAccessManager* manager = new QNetworkAccessManager { this }; - connect(manager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); + + connect(&_networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL }; QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID)); @@ -213,7 +214,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) { qDebug() << "Requesting public key for domain with ID" << domainID; - manager->get(publicKeyRequest); + _networkAccessManager.get(publicKeyRequest); } void IceServer::publicKeyReplyFinished(QNetworkReply* reply) { diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 6cc33fd8fc..2f9ee9c727 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -54,6 +54,8 @@ private: HTTPManager _httpManager; + QNetworkAccessManager _networkAccessManager; + using RSAUniquePtr = std::unique_ptr>; using DomainPublicKeyHash = std::unordered_map; DomainPublicKeyHash _domainPublicKeys; From 92e9e6a3fa35879cd7282920d4a7f6f0f89ef70a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 11:35:41 -0700 Subject: [PATCH 056/115] use the NetworkAccessManager to get a single QNetworkAccessManager --- ice-server/src/IceServer.cpp | 10 +++++----- ice-server/src/IceServer.h | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index ac5952ce43..7bd8306e9b 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -33,8 +34,7 @@ IceServer::IceServer(int argc, char* argv[]) : _id(QUuid::createUuid()), _serverSocket(), _activePeers(), - _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this), - _networkAccessManager(this) + _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this) { // start the ice-server socket qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; @@ -202,8 +202,8 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla void IceServer::requestDomainPublicKey(const QUuid& domainID) { // send a request to the metaverse API for the public key for this domain - - connect(&_networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); + auto& networkAccessManager = NetworkAccessManager::getInstance(); + connect(&networkAccessManager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL }; QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID)); @@ -214,7 +214,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) { qDebug() << "Requesting public key for domain with ID" << domainID; - _networkAccessManager.get(publicKeyRequest); + networkAccessManager.get(publicKeyRequest); } void IceServer::publicKeyReplyFinished(QNetworkReply* reply) { diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 2f9ee9c727..6cc33fd8fc 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -54,8 +54,6 @@ private: HTTPManager _httpManager; - QNetworkAccessManager _networkAccessManager; - using RSAUniquePtr = std::unique_ptr>; using DomainPublicKeyHash = std::unordered_map; DomainPublicKeyHash _domainPublicKeys; From e5adfc40b2a8f02354a851ea49fad316453fd339 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 11:42:41 -0700 Subject: [PATCH 057/115] use the inactivity timer for ice-server lockup check --- ice-server/src/IceServer.cpp | 8 ++++---- ice-server/src/IceServer.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 7bd8306e9b..128c2b27b0 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -69,8 +69,6 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) { void IceServer::processPacket(std::unique_ptr packet) { - _lastPacketTimestamp = QDateTime::currentMSecsSinceEpoch(); - auto nlPacket = NLPacket::fromBase(std::move(packet)); // make sure that this packet at least looks like something we can read @@ -282,6 +280,8 @@ void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSoc void IceServer::clearInactivePeers() { NetworkPeerHash::iterator peerItem = _activePeers.begin(); + _lastInactiveCheckTimestamp = QDateTime::currentMSecsSinceEpoch(); + while (peerItem != _activePeers.end()) { SharedNetworkPeer peer = peerItem.value(); @@ -310,8 +310,8 @@ bool IceServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, b const quint64 MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET = 10 * 1000; - int statusNumber = (QDateTime::currentMSecsSinceEpoch() - _lastPacketTimestamp > MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET) - ? 1 : 0; + auto sinceLastInactiveCheck = QDateTime::currentMSecsSinceEpoch() - _lastInactiveCheckTimestamp; + int statusNumber = (sinceLastInactiveCheck > MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET) ? 1 : 0; connection->respond(HTTPConnection::StatusCode200, QByteArray::number(statusNumber)); diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 6cc33fd8fc..7d1d05324c 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -58,7 +58,7 @@ private: using DomainPublicKeyHash = std::unordered_map; DomainPublicKeyHash _domainPublicKeys; - quint64 _lastPacketTimestamp; + quint64 _lastInactiveCheckTimestamp; }; #endif // hifi_IceServer_h From 4210bc178e1302275a75fd2a7c8f6814e01facb3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 11:44:55 -0700 Subject: [PATCH 058/115] default the inactive timestamp for healthy startup --- ice-server/src/IceServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 128c2b27b0..9d1bb58ddf 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -34,7 +34,8 @@ IceServer::IceServer(int argc, char* argv[]) : _id(QUuid::createUuid()), _serverSocket(), _activePeers(), - _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this) + _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this), + _lastInactiveCheckTimestamp(QDateTime::currentMSecsSinceEpoch()) { // start the ice-server socket qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; From 6bdedeb5cec21b600a88eac5d32abe3cf2fc9373 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 11:59:49 -0700 Subject: [PATCH 059/115] change packaging parameters for Sandbox/Interface --- cmake/macros/GenerateInstallers.cmake | 4 ++-- cmake/macros/SetPackagingParameters.cmake | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index b4744aa172..8d1eca84d7 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -85,8 +85,8 @@ macro(GENERATE_INSTALLERS) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") - cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client") - cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Server") + cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface") + cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox") include(CPack) endmacro() diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 92e3273f67..1886ca36ac 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -53,7 +53,7 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME}) set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME}) - set(CONSOLE_EXEC_NAME "Server Console.app") + set(CONSOLE_EXEC_NAME "Sandbox.app") set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_EXEC_NAME}") set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") @@ -64,7 +64,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns") else () if (WIN32) - set(CONSOLE_INSTALL_DIR "server-console") + set(CONSOLE_INSTALL_DIR "sandbox") else () set(CONSOLE_INSTALL_DIR ".") endif () @@ -77,18 +77,18 @@ macro(SET_PACKAGING_PARAMETERS) set(INTERFACE_EXEC_PREFIX "interface") set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.ico") - set(CONSOLE_EXEC_NAME "server-console.exe") + set(CONSOLE_EXEC_NAME "sandbox.exe") set(DS_EXEC_NAME "domain-server.exe") set(AC_EXEC_NAME "assignment-client.exe") # shortcut names if (PRODUCTION_BUILD) - set(INTERFACE_SHORTCUT_NAME "High Fidelity") - set(CONSOLE_SHORTCUT_NAME "Server Console") + set(INTERFACE_SHORTCUT_NAME "Interface") + set(CONSOLE_SHORTCUT_NAME "Sandbox") else () - set(INTERFACE_SHORTCUT_NAME "High Fidelity - ${BUILD_VERSION}") - set(CONSOLE_SHORTCUT_NAME "Server Console - ${BUILD_VERSION}") + set(INTERFACE_SHORTCUT_NAME "Interface - ${BUILD_VERSION}") + set(CONSOLE_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION}") endif () # check if we need to find signtool if (PRODUCTION_BUILD OR PR_BUILD) From 724c95fbd6bbd363f23ee6871bc314ea28e989a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 12:05:17 -0700 Subject: [PATCH 060/115] leave executable name for server-console --- cmake/macros/SetPackagingParameters.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 1886ca36ac..cdbddf84e5 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -77,7 +77,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INTERFACE_EXEC_PREFIX "interface") set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.ico") - set(CONSOLE_EXEC_NAME "sandbox.exe") + set(CONSOLE_EXEC_NAME "server-console.exe") set(DS_EXEC_NAME "domain-server.exe") set(AC_EXEC_NAME "assignment-client.exe") From 238f9e9298cc6bf7c9c7c2d532f1208752479c17 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 30 Mar 2016 12:07:40 -0700 Subject: [PATCH 061/115] remove the Stack Manager migration section --- server-console/src/splash.html | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/server-console/src/splash.html b/server-console/src/splash.html index 30868ebb6f..b9947bcbaa 100644 --- a/server-console/src/splash.html +++ b/server-console/src/splash.html @@ -23,7 +23,7 @@ High Fidelity is now installed and your Home domain is ready for you to explore.

-You can make your home yours by uploading your own models and scripts, and adding items from the Market. +You can make your home yours by uploading your own models and scripts.

@@ -67,12 +67,6 @@ You can make your home yours by uploading your own models and scripts, and addin -
-

-

Your existing Stack Manager content is safe.

- Server Console comes with demo content but does not overwrite your data. See our guide to importing content previously managed with Stack Manager. -

-