diff --git a/BUILD.md b/BUILD.md index db81ecb30d..eea91e118b 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,6 +1,6 @@ # General Build Information -*Last Updated on June 27, 2020* +*Last Updated on August 26, 2020* ### OS Specific Build Guides @@ -80,12 +80,12 @@ Where /path/to/directory is the path to a directory where you wish the build fil // The type of release. RELEASE_TYPE=PRODUCTION|PR|DEV - // TODO: What do these do? + // Determine the build type PRODUCTION_BUILD=0|1 PR_BUILD=0|1 STABLE_BUILD=0|1 - // TODO: What do these do? + // Determine if to utilize testing or stable Metaverse URLs USE_STABLE_GLOBAL_SERVICES=1 BUILD_GLOBAL_SERVICES=STABLE @@ -141,6 +141,8 @@ The following build options can be used when running CMake * BUILD_SERVER * BUILD_TESTS * BUILD_TOOLS +* CLIENT_ONLY // Will package only the Interface +* SERVER_ONLY // Will package only the Server #### Developer Build Options diff --git a/CMakeLists.txt b/CMakeLists.txt index eac12d5ae7..424fbdc940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,7 @@ else() endif() # Use default time server if none defined in environment -set_from_env(TIMESERVER_URL TIMESERVER_URL "http://sha256timestamp.ws.symantec.com/sha256/timestamp") +set_from_env(TIMESERVER_URL TIMESERVER_URL "http://timestamp.comodoca.com?td=sha256") set(HIFI_USE_OPTIMIZED_IK_OPTION OFF) set(BUILD_CLIENT_OPTION ON) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index fe0d95e8b1..f40141be32 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -199,18 +199,15 @@ !system "$%TEMP%\tempinstaller.exe" = 2 - ; NOTE: We're not code signing right now, so we're going to disable that. - ; TODO: Get a code signing certificate so we can re-enable code signing. - ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. - ; !if @PRODUCTION_BUILD@ == 1 - ; !if @BYPASS_SIGNING@ == 1 - ; !warning "BYPASS_SIGNING set - installer will not be signed" - ; !else - ; !system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 - ; !endif - ; !endif + !if @PRODUCTION_BUILD@ == 1 + !if @BYPASS_SIGNING@ == 1 + !warning "BYPASS_SIGNING set - installer will not be signed" + !else + !system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://timestamp.comodoca.com?td=sha256 /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 + !endif + !endif ; Good. Now we can carry on writing the real installer. diff --git a/domain-server/resources/web/assignment/placeholder.js b/domain-server/resources/web/assignment/placeholder.js index bf64539bea..95c9903e32 100644 --- a/domain-server/resources/web/assignment/placeholder.js +++ b/domain-server/resources/web/assignment/placeholder.js @@ -1,3 +1,3 @@ // Here you can put a script that will be run by an assignment-client (AC) -// For examples, please go to https://github.com/highfidelity/hifi/tree/master/script-archive/acScripts +// For examples, please go to https://github.com/kasenvr/project-athena/tree/master/script-archive/acScripts // The directory named acScripts contains assignment-client specific scripts you can try. diff --git a/interface/resources/qml/+android_interface/Stats.qml b/interface/resources/qml/+android_interface/Stats.qml index 2581e4a82c..913a817cd9 100644 --- a/interface/resources/qml/+android_interface/Stats.qml +++ b/interface/resources/qml/+android_interface/Stats.qml @@ -386,6 +386,10 @@ Item { visible: root.expanded text: "LOD: " + root.lodStatus; } + StatText { + visible: root.expanded + text: "Entity Updates: " + root.numEntityUpdates + " / " + root.numNeededEntityUpdates; + } } } } diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 7ab216d4ff..f18fb06dc3 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -437,6 +437,10 @@ Item { visible: root.expanded text: "LOD: " + root.lodStatus; } + StatText { + visible: root.expanded + text: "Entity Updates: " + root.numEntityUpdates + " / " + root.numNeededEntityUpdates; + } } } } diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index bbf22f9549..b013bbff0d 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -458,6 +458,8 @@ void Stats::updateStats(bool force) { STAT_UPDATE(localLeaves, (int)OctreeElement::getLeafNodeCount()); // LOD Details STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get()->getLODFeedbackText()); + STAT_UPDATE(numEntityUpdates, DependencyManager::get()->getPrevNumEntityUpdates()); + STAT_UPDATE(numNeededEntityUpdates, DependencyManager::get()->getPrevTotalNeededEntityUpdates()); } diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 62ec42ca1d..d4dc4d3307 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -248,6 +248,10 @@ private: \ * Read-only. * @property {string} lodStatus - Description of the current LOD. * Read-only. + * @property {string} numEntityUpdates - The number of entity updates that happened last frame. + * Read-only. + * @property {string} numNeededEntityUpdates - The total number of entity updates scheduled for last frame. + * Read-only. * @property {string} timingStats - Details of the average time (ms) spent in and number of calls made to different parts of * the code. Provided only if timingExpanded is true. Only the top 10 items are provided if * Developer > Timing > Performance Timer > Only Display Top 10 is enabled. @@ -543,6 +547,8 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, lodAngle, 0) STATS_PROPERTY(int, lodTargetFramerate, 0) STATS_PROPERTY(QString, lodStatus, QString()) + STATS_PROPERTY(int, numEntityUpdates, 0) + STATS_PROPERTY(int, numNeededEntityUpdates, 0) STATS_PROPERTY(QString, timingStats, QString()) STATS_PROPERTY(QString, gameUpdateStats, QString()) STATS_PROPERTY(int, serverElements, 0) @@ -1211,6 +1217,20 @@ signals: */ void lodStatusChanged(); + /**jsdoc + * Triggered when the value of the numEntityUpdates property changes. + * @function Stats.numEntityUpdatesChanged + * @returns {Signal} + */ + void numEntityUpdatesChanged(); + + /**jsdoc + * Triggered when the value of the numNeededEntityUpdates property changes. + * @function Stats.numNeededEntityUpdatesChanged + * @returns {Signal} + */ + void numNeededEntityUpdatesChanged(); + /**jsdoc * Triggered when the value of the timingStats property changes. * @function Stats.timingStatsChanged diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index f070c9c2f7..b5ed4b767d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -425,6 +425,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene } float expectedUpdateCost = _avgRenderableUpdateCost * _renderablesToUpdate.size(); + _prevTotalNeededEntityUpdates = _renderablesToUpdate.size(); if (expectedUpdateCost < MAX_UPDATE_RENDERABLES_TIME_BUDGET) { // we expect to update all renderables within available time budget PROFILE_RANGE_EX(simulation_physics, "UpdateRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size()); @@ -433,7 +434,8 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene assert(renderable); // only valid renderables are added to _renderablesToUpdate renderable->updateInScene(scene, transaction); } - size_t numRenderables = _renderablesToUpdate.size() + 1; // add one to avoid divide by zero + _prevNumEntityUpdates = _renderablesToUpdate.size(); + size_t numRenderables = _prevNumEntityUpdates + 1; // add one to avoid divide by zero _renderablesToUpdate.clear(); // compute average per-renderable update cost @@ -494,7 +496,8 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene } // compute average per-renderable update cost - size_t numUpdated = sortedRenderables.size() - _renderablesToUpdate.size() + 1; // add one to avoid divide by zero + _prevNumEntityUpdates = sortedRenderables.size() - _renderablesToUpdate.size(); + size_t numUpdated = _prevNumEntityUpdates + 1; // add one to avoid divide by zero float cost = (float)(usecTimestampNow() - updateStart) / (float)(numUpdated); const float BLEND = 0.1f; _avgRenderableUpdateCost = (1.0f - BLEND) * _avgRenderableUpdateCost + BLEND * cost; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 1deadc254e..149b23702f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -136,6 +136,9 @@ public: static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName); static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName); + int getPrevNumEntityUpdates() const { return _prevNumEntityUpdates; } + int getPrevTotalNeededEntityUpdates() const { return _prevTotalNeededEntityUpdates; } + signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); @@ -249,6 +252,8 @@ private: ReadWriteLockable _changedEntitiesGuard; std::unordered_set _changedEntities; + int _prevNumEntityUpdates { 0 }; + int _prevTotalNeededEntityUpdates { 0 }; std::unordered_set _renderablesToUpdate; std::unordered_map _entitiesInScene; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 9ca958d128..807a240763 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -219,13 +219,6 @@ void EntityRenderer::render(RenderArgs* args) { return; } - if (!_renderUpdateQueued && needsRenderUpdate()) { - // FIXME find a way to spread out the calls to needsRenderUpdate so that only a given subset of the - // items checks every frame, like 1/N of the tree ever N frames - _renderUpdateQueued = true; - emit requestRenderUpdate(); - } - if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { doRender(args); } @@ -344,11 +337,6 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans } _updateTime = usecTimestampNow(); - // FIXME is this excessive? - if (!needsRenderUpdate()) { - return; - } - doRenderUpdateSynchronous(scene, transaction, _entity); transaction.updateItem(_renderItemID, [this](PayloadProxyInterface& self) { if (!isValidRenderItem()) { @@ -356,7 +344,6 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans } // Happens on the render thread. Classes should use doRenderUpdateAsynchronous(_entity); - _renderUpdateQueued = false; }); } @@ -457,7 +444,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa } void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { - QObject::connect(this, &EntityRenderer::requestRenderUpdate, this, [this] { + QObject::connect(this, &EntityRenderer::requestRenderUpdate, this, [this] { auto renderer = DependencyManager::get(); if (renderer) { renderer->onEntityChanged(_entity->getID()); @@ -466,7 +453,10 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { _changeHandlerId = entity->registerChangeHandler([](const EntityItemID& changedEntity) { auto renderer = DependencyManager::get(); if (renderer) { - renderer->onEntityChanged(changedEntity); + auto renderable = renderer->renderableForEntityId(changedEntity); + if (renderable && renderable->needsRenderUpdate()) { + renderer->onEntityChanged(changedEntity); + } } }); } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 9c787d82c2..39c30e5883 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -148,8 +148,6 @@ protected: QVector _renderWithZones; bool _cauterized { false }; bool _moving { false }; - // Only touched on the rendering thread - bool _renderUpdateQueued{ false }; Transform _renderTransform; std::unordered_map _materials; @@ -191,10 +189,7 @@ protected: using Parent::needsRenderUpdateFromEntity; // Returns true if the item in question needs to have updateInScene called because of changes in the entity virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const override final { - if (Parent::needsRenderUpdateFromEntity(entity)) { - return true; - } - return needsRenderUpdateFromTypedEntity(_typedEntity); + return Parent::needsRenderUpdateFromEntity(entity) || needsRenderUpdateFromTypedEntity(_typedEntity); } virtual void doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) override final { diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp index 9081d0727f..7a36ae2707 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp @@ -39,6 +39,16 @@ bool GizmoEntityRenderer::isTransparent() const { return Parent::isTransparent() || ringTransparent; } +void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + void* key = (void*)this; + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { + withWriteLock([&] { + _renderTransform = getModelTransform(); + _renderTransform.postScale(entity->getScaledDimensions()); + }); + }); +} + void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { bool dirty = false; RingGizmoPropertyGroup ringProperties = entity->getRingProperties(); @@ -186,15 +196,6 @@ void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint } } } - - void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() { - withWriteLock([&] { - updateModelTransformAndBound(); - _renderTransform = getModelTransform(); - _renderTransform.postScale(entity->getScaledDimensions()); - }); - }); } Item::Bound GizmoEntityRenderer::getBound() { diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.h b/libraries/entities-renderer/src/RenderableGizmoEntityItem.h index c072f482cd..e3d84a0201 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.h +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.h @@ -29,6 +29,7 @@ protected: bool isTransparent() const override; private: + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity); virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRender(RenderArgs* args) override; diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index 0b074f7a81..52900d0798 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -41,10 +41,9 @@ void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen }); void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { withWriteLock([&] { _dimensions = entity->getScaledDimensions(); - updateModelTransformAndBound(); _renderTransform = getModelTransform(); }); }); diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index acdf5a35de..4d19a83ae6 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -30,11 +30,9 @@ bool ImageEntityRenderer::isTransparent() const { } bool ImageEntityRenderer::needsRenderUpdate() const { - bool textureLoadedChanged = resultWithReadLock([&] { - return (!_textureIsLoaded && _texture && _texture->isLoaded()); - }); - - if (textureLoadedChanged) { + if (resultWithReadLock([&] { + return !_textureIsLoaded; + })) { return true; } @@ -63,15 +61,15 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _pulseProperties = entity->getPulseProperties(); _billboardMode = entity->getBillboardMode(); - if (!_textureIsLoaded && _texture && _texture->isLoaded()) { - _textureIsLoaded = true; + if (!_textureIsLoaded) { + emit requestRenderUpdate(); } + _textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed()); }); void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { withWriteLock([&] { - updateModelTransformAndBound(); _renderTransform = getModelTransform(); _renderTransform.postScale(entity->getScaledDimensions()); }); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index bc56781924..bfa02e6483 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -64,6 +64,16 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint }); } +bool ParticleEffectEntityRenderer::needsRenderUpdate() const { + if (resultWithReadLock([&] { + return !_textureLoaded; + })) { + return true; + } + + return Parent::needsRenderUpdate(); +} + void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { auto newParticleProperties = entity->getParticleProperties(); if (!newParticleProperties.valid()) { @@ -102,6 +112,7 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi } withWriteLock([&] { + _textureLoaded = true; entity->setVisuallyReady(true); }); } else { @@ -111,20 +122,29 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi if (textureNeedsUpdate) { withWriteLock([&] { _networkTexture = DependencyManager::get()->getTexture(_particleProperties.textures); + _textureLoaded = false; + entity->setVisuallyReady(false); }); } - if (_networkTexture) { + if (!_textureLoaded) { + emit requestRenderUpdate(); + } + + bool textureLoaded = resultWithReadLock([&] { + return _networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed()); + }); + if (textureLoaded) { withWriteLock([&] { - entity->setVisuallyReady(_networkTexture->isFailed() || _networkTexture->isLoaded()); + entity->setVisuallyReady(true); + _textureLoaded = true; }); } } void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] () { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] { withWriteLock([&] { - updateModelTransformAndBound(); _renderTransform = getModelTransform(); }); }); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 8a3d8120f5..0811b231d8 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -25,6 +25,7 @@ public: ParticleEffectEntityRenderer(const EntityItemPointer& entity); protected: + virtual bool needsRenderUpdate() const override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; @@ -111,6 +112,7 @@ private: GeometryResource::Pointer _geometryResource; NetworkTexturePointer _networkTexture; + bool _textureLoaded { false }; ScenePointer _scene; }; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index e75f8593d6..a843083831 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -204,9 +204,8 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& bool geometryChanged = uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged; void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, geometryChanged] () { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, geometryChanged] { withWriteLock([&] { - updateModelTransformAndBound(); _renderTransform = getModelTransform(); if (geometryChanged) { diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index d5a0e22199..683cc1359a 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -70,20 +70,18 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce }); void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] () { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { withWriteLock([&] { - auto entity = getEntity(); _position = entity->getWorldPosition(); _dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice _orientation = entity->getWorldOrientation(); - updateModelTransformAndBound(); _renderTransform = getModelTransform(); // contains parent scale, if this entity scales with its parent if (_shape == entity::Sphere) { _renderTransform.postScale(SPHERE_ENTITY_SCALE); } _renderTransform.postScale(_dimensions); - });; + }); }); } @@ -121,11 +119,16 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint materialChanged = true; } - if (materialChanged) { - auto materials = _materials.find("0"); - if (materials != _materials.end()) { + auto materials = _materials.find("0"); + if (materials != _materials.end()) { + if (materialChanged) { materials->second.setNeedsUpdate(true); } + + if (materials->second.shouldUpdate()) { + RenderPipelines::updateMultiMaterial(materials->second); + emit requestRenderUpdate(); + } } }); } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 2ba1acea11..a744fc9a62 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -102,10 +102,9 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] () { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { withWriteLock([&] { _dimensions = entity->getScaledDimensions(); - updateModelTransformAndBound(); _renderTransform = getModelTransform(); _renderTransform.postScale(_dimensions); }); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 1da4999bad..c818eaf237 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -236,11 +236,10 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene } void* key = (void*)this; - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { withWriteLock([&] { glm::vec2 windowSize = getWindowSize(entity); _webSurface->resize(QSize(windowSize.x, windowSize.y)); - updateModelTransformAndBound(); _renderTransform = getModelTransform(); _renderTransform.setScale(1.0f); _renderTransform.postScale(entity->getScaledDimensions()); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 948c6ca762..d3c9225b88 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -262,14 +262,6 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen entity->setVisuallyReady(visuallyReady); } -void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { - if (entity->getShapeType() == SHAPE_TYPE_SPHERE) { - _renderTransform = getModelTransform(); - _renderTransform.postScale(SPHERE_ENTITY_SCALE); - } -} - - ItemKey ZoneEntityRenderer::getKey() { return ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).build(); } @@ -306,8 +298,6 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint return true; } - // FIXME: do we need to trigger an update when shapeType changes? see doRenderUpdateAsynchronousTyped - return false; } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 5fd9b87408..d4e3d16408 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -39,7 +39,6 @@ protected: virtual void doRender(RenderArgs* args) override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; - virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; private: void updateKeyZoneItemFromEntity(const TypedEntityPointer& entity); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3623e5f96a..ddedf0db18 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -617,10 +617,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _lastEdited = lastEditedFromBufferAdjusted; _lastEditedFromRemote = now; _lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer; - - // TODO: only send this notification if something ACTUALLY changed (hint, we haven't yet parsed - // the properties out of the bitstream (see below)) - somethingChangedNotification(); // notify derived classes that something has changed } // last updated is stored as ByteCountCoded delta from lastEdited @@ -1005,6 +1001,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef element->getTree()->trackIncomingEntityLastEdited(lastEditedFromBufferAdjusted, bytesRead); } + if (somethingChanged) { + somethingChangedNotification(); + } return bytesRead; } @@ -1573,14 +1572,14 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { qCDebug(entities) << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed << "now=" << now << " getLastEdited()=" << getLastEdited(); #endif - setLastEdited(now); - somethingChangedNotification(); // notify derived classes that something has changed + setLastEdited(properties._lastEdited); if (getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES)) { // anything that sets the transform or velocity must update _lastSimulated which is used // for kinematic extrapolation (e.g. we want to extrapolate forward from this moment // when position and/or velocity was changed). _lastSimulated = now; } + somethingChangedNotification(); } // timestamps @@ -1832,6 +1831,7 @@ void EntityItem::setPosition(const glm::vec3& value) { void EntityItem::setParentID(const QUuid& value) { QUuid oldParentID = getParentID(); if (oldParentID != value) { + _needsRenderUpdate = true; EntityTreePointer tree = getTree(); if (tree && !oldParentID.isNull()) { tree->removeFromChildrenOfAvatars(getThisPointer()); @@ -3000,10 +3000,15 @@ bool EntityItem::getCauterized() const { } void EntityItem::setCauterized(bool value) { + bool needsRenderUpdate = false; withWriteLock([&] { - _needsRenderUpdate |= _cauterized != value; + needsRenderUpdate = _cauterized != value; + _needsRenderUpdate |= needsRenderUpdate; _cauterized = value; }); + if (needsRenderUpdate) { + somethingChangedNotification(); + } } bool EntityItem::getIgnorePickIntersection() const { @@ -3042,10 +3047,15 @@ bool EntityItem::getCullWithParent() const { } void EntityItem::setCullWithParent(bool value) { + bool needsRenderUpdate = false; withWriteLock([&] { - _needsRenderUpdate |= _cullWithParent != value; + needsRenderUpdate = _cullWithParent != value; + _needsRenderUpdate |= needsRenderUpdate; _cullWithParent = value; }); + if (needsRenderUpdate) { + somethingChangedNotification(); + } } bool EntityItem::isChildOfMyAvatar() const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 2bb5dab16b..2a6952fc0d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -579,8 +579,8 @@ public: bool stillHasMyGrab() const; - bool needsRenderUpdate() const { return resultWithReadLock([&] { return _needsRenderUpdate; }); } - void setNeedsRenderUpdate(bool needsRenderUpdate) { withWriteLock([&] { _needsRenderUpdate = needsRenderUpdate; }); } + bool needsRenderUpdate() const { return _needsRenderUpdate; } + void setNeedsRenderUpdate(bool needsRenderUpdate) { _needsRenderUpdate = needsRenderUpdate; } void setRenderWithZones(const QVector& renderWithZones); QVector getRenderWithZones() const; diff --git a/libraries/entities/src/GizmoEntityItem.cpp b/libraries/entities/src/GizmoEntityItem.cpp index a2fc691387..47c9afd168 100644 --- a/libraries/entities/src/GizmoEntityItem.cpp +++ b/libraries/entities/src/GizmoEntityItem.cpp @@ -39,8 +39,8 @@ EntityItemProperties GizmoEntityItem::getProperties(const EntityPropertyFlags& d return properties; } -bool GizmoEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool GizmoEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(gizmoType, setGizmoType); withWriteLock([&] { @@ -49,16 +49,6 @@ bool GizmoEntityItem::setProperties(const EntityItemProperties& properties) { _needsRenderUpdate |= ringPropertiesChanged; }); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "GizmoEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } diff --git a/libraries/entities/src/GizmoEntityItem.h b/libraries/entities/src/GizmoEntityItem.h index aa338355b8..37a802387d 100644 --- a/libraries/entities/src/GizmoEntityItem.h +++ b/libraries/entities/src/GizmoEntityItem.h @@ -26,7 +26,7 @@ public: // methods for getting/setting all properties of an entity EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setProperties(const EntityItemProperties& properties) override; + bool setSubClassProperties(const EntityItemProperties& properties) override; EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/GridEntityItem.cpp b/libraries/entities/src/GridEntityItem.cpp index e45ab89b69..e635511bfc 100644 --- a/libraries/entities/src/GridEntityItem.cpp +++ b/libraries/entities/src/GridEntityItem.cpp @@ -46,8 +46,8 @@ EntityItemProperties GridEntityItem::getProperties(const EntityPropertyFlags& de return properties; } -bool GridEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool GridEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); @@ -61,16 +61,6 @@ bool GridEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(majorGridEvery, setMajorGridEvery); SET_ENTITY_PROPERTY_FROM_PROPERTIES(minorGridEvery, setMinorGridEvery); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "GridEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } diff --git a/libraries/entities/src/GridEntityItem.h b/libraries/entities/src/GridEntityItem.h index 165d9b50f5..7dc7a475b2 100644 --- a/libraries/entities/src/GridEntityItem.h +++ b/libraries/entities/src/GridEntityItem.h @@ -26,7 +26,7 @@ public: // methods for getting/setting all properties of an entity EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setProperties(const EntityItemProperties& properties) override; + bool setSubClassProperties(const EntityItemProperties& properties) override; EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index 2d942cc25d..6a8c457b0a 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -45,8 +45,8 @@ EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& d return properties; } -bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool ImageEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); @@ -62,16 +62,6 @@ bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); SET_ENTITY_PROPERTY_FROM_PROPERTIES(subImage, setSubImage); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "ImageEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h index a1be5a0554..bca67dc738 100644 --- a/libraries/entities/src/ImageEntityItem.h +++ b/libraries/entities/src/ImageEntityItem.h @@ -26,7 +26,7 @@ public: // methods for getting/setting all properties of an entity EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setProperties(const EntityItemProperties& properties) override; + bool setSubClassProperties(const EntityItemProperties& properties) override; EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 2df2136639..715b457bde 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -55,21 +55,6 @@ void LightEntityItem::setUnscaledDimensions(const glm::vec3& value) { } } -void LightEntityItem::locationChanged(bool tellPhysics, bool tellChildren) { - EntityItem::locationChanged(tellPhysics, tellChildren); - withWriteLock([&] { - _needsRenderUpdate = true; - }); -} - -void LightEntityItem::dimensionsChanged() { - EntityItem::dimensionsChanged(); - withWriteLock([&] { - _needsRenderUpdate = true; - }); -} - - EntityItemProperties LightEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class @@ -134,23 +119,8 @@ void LightEntityItem::setCutoff(float value) { } } -bool LightEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "LightEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } - return somethingChanged; -} - bool LightEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setSubClassProperties(properties); // set the properties in our base class + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); @@ -162,7 +132,6 @@ bool LightEntityItem::setSubClassProperties(const EntityItemProperties& properti return somethingChanged; } - int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 8194ff8308..5245770ec8 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -33,11 +33,9 @@ public: /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately virtual void setUnscaledDimensions(const glm::vec3& value) override; - virtual bool setProperties(const EntityItemProperties& properties) override; - virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; @@ -73,9 +71,6 @@ public: static bool getLightsArePickable() { return _lightsArePickable; } static void setLightsArePickable(bool value) { _lightsArePickable = value; } - - virtual void locationChanged(bool tellPhysics, bool tellChildren) override; - virtual void dimensionsChanged() override; virtual bool supportsDetailedIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 1cd09c1a0c..f3304e716f 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -45,23 +45,12 @@ EntityItemProperties LineEntityItem::getProperties(const EntityPropertyFlags& de return properties; } -bool LineEntityItem::setProperties(const EntityItemProperties& properties) { +bool LineEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "LineEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } return somethingChanged; } diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index ee473225fe..38e526204e 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -24,7 +24,7 @@ class LineEntityItem : public EntityItem { // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 73bebfc403..dcdd80cb48 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -38,8 +38,8 @@ EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags return properties; } -bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool MaterialEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingMode, setMaterialMappingMode); @@ -51,16 +51,6 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialData, setMaterialData); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRepeat, setMaterialRepeat); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "MaterialEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index d8de8c3bc6..76cfbfa9dc 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -24,7 +24,7 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 3808844a6f..38e7ad9c3a 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -79,9 +79,8 @@ EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& d return properties; } -bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { +bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); @@ -105,17 +104,6 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { somethingChanged = somethingChanged || somethingChangedInAnimations; }); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "ModelEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } - return somethingChanged; } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index c331a94adf..795630a72a 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -29,7 +29,7 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index c20ae87276..5ccc209a54 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -696,8 +696,8 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropert return properties; } -bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool ParticleEffectEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); @@ -750,16 +750,6 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinFinish, setSpinFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotateWithEntity, setRotateWithEntity); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "ParticleEffectEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 358e5a6b6d..c96323fc9a 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -214,7 +214,7 @@ public: // methods for getting/setting all properties of this entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index fe14ba6925..909bc132fb 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -53,9 +53,8 @@ EntityItemProperties PolyLineEntityItem::getProperties(const EntityPropertyFlags return properties; } -bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) { +bool PolyLineEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); @@ -68,16 +67,6 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(glow, setGlow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(faceCamera, setFaceCamera); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "PolyLineEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } return somethingChanged; } diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index e68666d75e..8fb7831c6a 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -24,7 +24,7 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index b424ba137f..dd55ca898b 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -106,8 +106,9 @@ EntityItemProperties PolyVoxEntityItem::getProperties(const EntityPropertyFlags& return properties; } -bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool PolyVoxEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelVolumeSize, setVoxelVolumeSize); SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelData, setVoxelData); SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelSurfaceStyle, setVoxelSurfaceStyle); @@ -121,16 +122,6 @@ bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(yPNeighborID, setYPNeighborID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(zPNeighborID, setZPNeighborID); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "PolyVoxEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } return somethingChanged; } diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 9d02cbcdad..f994fcd37c 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -24,7 +24,7 @@ class PolyVoxEntityItem : public EntityItem { // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 882ab26901..5e140665b3 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -165,8 +165,8 @@ entity::Shape ShapeEntityItem::getShape() const { }); } -bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class +bool ShapeEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); @@ -177,16 +177,6 @@ bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) { }); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "ShapeEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 43c2ce2a1f..7320867430 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -55,7 +55,7 @@ public: // methods for getting/setting all properties of an entity EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setProperties(const EntityItemProperties& properties) override; + bool setSubClassProperties(const EntityItemProperties& properties) override; EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index bcc2c0efed..a996319463 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -73,9 +73,8 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de return properties; } -bool TextEntityItem::setProperties(const EntityItemProperties& properties) { +bool TextEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class withWriteLock([&] { bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); @@ -99,17 +98,6 @@ bool TextEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffect, setTextEffect); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffectColor, setTextEffectColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffectThickness, setTextEffectThickness); - - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "TextEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } return somethingChanged; } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 5e3f6d7c02..91496708f6 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -31,7 +31,7 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index a62f599e4c..73e0096e76 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -63,9 +63,8 @@ EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& des return properties; } -bool WebEntityItem::setProperties(const EntityItemProperties& properties) { +bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); @@ -83,17 +82,6 @@ bool WebEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(inputMode, setInputMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(showKeyboardFocusHighlight, setShowKeyboardFocusHighlight); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "WebEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } - return somethingChanged; } diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index b61e2b124f..5ab53d6ef8 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -27,7 +27,7 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 898a6d4b98..88466caff0 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -76,26 +76,8 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de return properties; } -bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "ZoneEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties._lastEdited); - } - - return somethingChanged; -} - bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setSubClassProperties(properties); // set the properties in our base class + bool somethingChanged = false; SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); @@ -121,7 +103,7 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(screenshare, setScreenshare); - somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || + somethingChanged |= _keyLightPropertiesChanged || _ambientLightPropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; return somethingChanged; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 8ec3ea12b4..dda03f9115 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -33,7 +33,6 @@ public: // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; virtual bool setSubClassProperties(const EntityItemProperties& properties) override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 897ac142bf..96f2383181 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -685,8 +685,9 @@ bool Octree::readFromFile(const char* fileName) { QDataStream fileInputStream(&file); QFileInfo fileInfo(qFileName); uint64_t fileLength = fileInfo.size(); + QUrl relativeURL = QUrl::fromLocalFile(qFileName).adjusted(QUrl::RemoveFilename); - bool success = readFromStream(fileLength, fileInputStream); + bool success = readFromStream(fileLength, fileInputStream, "", false, relativeURL); file.close(); @@ -708,7 +709,9 @@ bool Octree::readJSONFromGzippedFile(QString qFileName) { } QDataStream jsonStream(jsonData); - return readJSONFromStream(-1, jsonStream); + QUrl relativeURL = QUrl::fromLocalFile(qFileName).adjusted(QUrl::RemoveFilename); + + return readJSONFromStream(-1, jsonStream, "", false, relativeURL); } // hack to get the marketplace id into the entities. We will create a way to get this from a hash of @@ -761,13 +764,15 @@ bool Octree::readFromURL( QByteArray uncompressedJsonData; bool wasCompressed = gunzip(data, uncompressedJsonData); + QUrl relativeURL = QUrl(urlString).adjusted(QUrl::RemoveFilename); + if (wasCompressed) { QDataStream inputStream(uncompressedJsonData); - return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); + return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, isImport, relativeURL); } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID, isImport); + return readFromStream(data.size(), inputStream, marketplaceID, isImport, relativeURL); } bool Octree::readFromByteArray( @@ -780,20 +785,23 @@ bool Octree::readFromByteArray( QByteArray uncompressedJsonData; bool wasCompressed = gunzip(data, uncompressedJsonData); + QUrl relativeURL = QUrl(urlString).adjusted(QUrl::RemoveFilename); + if (wasCompressed) { QDataStream inputStream(uncompressedJsonData); - return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); + return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, false, relativeURL); } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID); + return readFromStream(data.size(), inputStream, marketplaceID, false, relativeURL); } bool Octree::readFromStream( uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID, - const bool isImport + const bool isImport, + const QUrl& relativeURL ) { // decide if this is binary SVO or JSON-formatted SVO QIODevice *device = inputStream.device(); @@ -806,7 +814,7 @@ bool Octree::readFromStream( return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; - return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport); + return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport, relativeURL); } } @@ -837,7 +845,8 @@ bool Octree::readJSONFromStream( uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID, /*=""*/ - const bool isImport + const bool isImport, + const QUrl& relativeURL ) { // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // we get an eof. Leave streamLength parameter for consistency. @@ -858,7 +867,9 @@ bool Octree::readJSONFromStream( } OctreeEntitiesFileParser octreeParser; + octreeParser.relativeURL = relativeURL; octreeParser.setEntitiesString(jsonBuffer); + QVariantMap asMap; if (!octreeParser.parseEntities(asMap)) { qCritical() << "Couldn't parse Entities JSON:" << octreeParser.getErrorString().c_str(); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index a7885801de..cb46d5151b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -218,8 +218,8 @@ public: bool readFromFile(const char* filename); bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const bool isImport = false); // will support file urls as well... bool readFromByteArray(const QString& url, const QByteArray& byteArray); - bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false); - bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false); + bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl()); + bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl()); bool readJSONFromGzippedFile(QString qFileName); virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0; diff --git a/libraries/octree/src/OctreeEntitiesFileParser.cpp b/libraries/octree/src/OctreeEntitiesFileParser.cpp index e82201adfd..72cfd30ef9 100644 --- a/libraries/octree/src/OctreeEntitiesFileParser.cpp +++ b/libraries/octree/src/OctreeEntitiesFileParser.cpp @@ -237,7 +237,75 @@ bool OctreeEntitiesFileParser::readEntitiesArray(QVariantList& entitiesArray) { return false; } - entitiesArray.append(entity.object()); + QJsonObject entityObject = entity.object(); + + // resolve urls starting with ./ or ../ + if (relativeURL.isEmpty() == false) { + bool isDirty = false; + + const QStringList urlKeys { + // model + "modelURL", + "animation.url", + // image + "imageURL", + // web + "sourceUrl", + "scriptURL", + // zone + "ambientLight.ambientURL", + "skybox.url", + // particles + "textures", + // materials + "materialURL", + // ...shared + "href", + "script", + "serverScripts", + "collisionSoundURL", + "compoundShapeURL", + // TODO: deal with materialData and userData + }; + + for (const QString& key : urlKeys) { + if (key.contains('.')) { + // url is inside another object + const QStringList keyPair = key.split('.'); + const QString entityKey = keyPair[0]; + const QString childKey = keyPair[1]; + + if (entityObject.contains(entityKey) && entityObject[entityKey].isObject()) { + QJsonObject childObject = entityObject[entityKey].toObject(); + + if (childObject.contains(childKey) && childObject[childKey].isString()) { + const QString url = childObject[childKey].toString(); + + if (url.startsWith("./") || url.startsWith("../")) { + childObject[childKey] = relativeURL.resolved(url).toString(); + entityObject[entityKey] = childObject; + isDirty = true; + } + } + } + } else { + if (entityObject.contains(key) && entityObject[key].isString()) { + const QString url = entityObject[key].toString(); + + if (url.startsWith("./") || url.startsWith("../")) { + entityObject[key] = relativeURL.resolved(url).toString(); + isDirty = true; + } + } + } + } + + if (isDirty) { + entity.setObject(entityObject); + } + } + + entitiesArray.append(entityObject); _position = matchingBrace; char c = nextToken(); if (c == ']') { diff --git a/libraries/octree/src/OctreeEntitiesFileParser.h b/libraries/octree/src/OctreeEntitiesFileParser.h index bc51896b18..39560710db 100644 --- a/libraries/octree/src/OctreeEntitiesFileParser.h +++ b/libraries/octree/src/OctreeEntitiesFileParser.h @@ -16,12 +16,14 @@ #include #include +#include class OctreeEntitiesFileParser { public: void setEntitiesString(const QByteArray& entitiesContents); bool parseEntities(QVariantMap& parsedEntities); std::string getErrorString() const; + QUrl relativeURL; private: int nextToken(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6150097f14..182b83762c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -961,7 +961,7 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) { void Model::setPrimitiveMode(PrimitiveMode primitiveMode) { if (_primitiveMode != primitiveMode) { _primitiveMode = primitiveMode; - setRenderItemsNeedUpdate(); + updateRenderItemsKey(nullptr); } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 412a1b7638..4585ad0009 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -118,6 +118,9 @@ public: bool isCauterized() const { return _cauterized; } void setCauterized(bool value, const render::ScenePointer& scene); + void setPrimitiveMode(PrimitiveMode primitiveMode); + PrimitiveMode getPrimitiveMode() const { return _primitiveMode; } + void setCullWithParent(bool value); void setRenderWithZones(const QVector& renderWithZones); @@ -160,9 +163,6 @@ public: bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isHFMModelLoaded(); } bool isAddedToScene() const { return _addedToScene; } - void setPrimitiveMode(PrimitiveMode primitiveMode); - PrimitiveMode getPrimitiveMode() const { return _primitiveMode; } - void reset(); void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); diff --git a/scripts/system/create/assets/data/createAppTooltips.json b/scripts/system/create/assets/data/createAppTooltips.json index 4efd0593fb..c247bc7cae 100644 --- a/scripts/system/create/assets/data/createAppTooltips.json +++ b/scripts/system/create/assets/data/createAppTooltips.json @@ -319,7 +319,7 @@ "tooltip": "The finish color of each particle." }, "colorSpread": { - "tooltip": "The spread in color that each particle is given, resulting in a variety of colors." + "tooltip": "The spread in color that each particle is given, resulting in a variety of colors. The variation range (-/+) on each RGB channel to use around the RGB values of the particle color." }, "particleAlphaTriple": { "tooltip": "The opacity of each particle between 0.0 fully transparent and 1.0 completely opaque.", @@ -531,7 +531,7 @@ "tooltip": "If enabled, grabbed entities will follow the movements of your hand controller instead of your avatar's hand." }, "canCastShadow": { - "tooltip": "If enabled, the geometry of this entity casts shadows when a shadow-casting light source shines on it. Note: Shadows are rendered only on high-profiled computers. This setting will have no effect on computers profiled to medium or low graphics.." + "tooltip": "If enabled, the geometry of this entity casts shadows when a shadow-casting light source shines on it. Note: Shadows are rendered only on high-profiled computers. This setting will have no effect on computers profiled to medium or low graphics." }, "ignorePickIntersection": { "tooltip": "If enabled, this entity will not be considered for ray picks, and will also not occlude other entities when picking." @@ -569,13 +569,13 @@ "tooltip": "The linear velocity vector of the entity. The velocity at which this entity moves forward in space." }, "damping": { - "tooltip": "The linear damping to slow down the linear velocity of an entity over time." + "tooltip": "The linear damping to slow down the linear velocity of an entity over time. A higher damping value slows down the entity more quickly. The default value is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to 1/e = 0.368 of its initial value." }, "localAngularVelocity": { - "tooltip": "The angular velocity of the entity in rad/s with respect to its axes, about its pivot point." + "tooltip": "The angular velocity of the entity in 'deg/s' with respect to its axes, about its pivot point." }, "angularDamping": { - "tooltip": "The angular damping to slow down the angular velocity of an entity over time." + "tooltip": "The angular damping to slow down the angular velocity of an entity over time. A higher damping value slows down the entity more quickly. The default value is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to 1/e = 0.368 of its initial value." }, "restitution": { "tooltip": "If enabled, the entity can bounce against other objects that also have Bounciness." diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index 182dddf817..f6dcf10bc8 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -1133,7 +1133,13 @@ const GROUPS = [ }, { label: "Color Spread", - type: "color", + type: "vec3rgb", + vec3Type: "vec3rgb", + min: 0, + max: 255, + step: 1, + decimals: 0, + subLabels: [ "r", "g", "b" ], propertyID: "colorSpread", }, { @@ -1651,16 +1657,6 @@ const GROUPS = [ decimals: 4, unit: "m/s2", propertyID: "gravity", - }, - { - label: "Acceleration", - type: "vec3", - vec3Type: "xyz", - subLabels: [ "x", "y", "z" ], - step: 0.1, - decimals: 4, - unit: "m/s2", - propertyID: "acceleration", } ] }, @@ -1791,6 +1787,8 @@ function getPropertyInputElement(propertyID) { return { x: property.elNumberX.elInput, y: property.elNumberY.elInput, z: property.elNumberZ.elInput }; case 'color': return { red: property.elNumberR.elInput, green: property.elNumberG.elInput, blue: property.elNumberB.elInput }; + case 'vec3rgb': + return { red: property.elNumberR.elInput, green: property.elNumberG.elInput, blue: property.elNumberB.elInput }; case 'icon': return property.elLabel; case 'dynamic-multiselect': @@ -1889,6 +1887,12 @@ function resetProperties() { property.elNumberB.setValue("", false); break; } + case 'vec3rgb': { + property.elNumberR.setValue("", false); + property.elNumberG.setValue("", false); + property.elNumberB.setValue("", false); + break; + } case 'dropdown': { property.elInput.classList.remove('multi-diff'); property.elInput.value = ""; @@ -1995,7 +1999,7 @@ function isCurrentlyDraggingProperty(propertyName) { return properties[propertyName] && properties[propertyName].dragging === true; } -const SUPPORTED_FALLBACK_TYPES = ['number', 'number-draggable', 'rect', 'vec3', 'vec2', 'color']; +const SUPPORTED_FALLBACK_TYPES = ['number', 'number-draggable', 'rect', 'vec3', 'vec2', 'color', 'vec3rgb']; function getMultiplePropertyValue(originalPropertyName) { // if this is a compound property name (i.e. animation.running) @@ -2051,6 +2055,9 @@ function getMultiplePropertyValue(originalPropertyName) { case 'color': isPropertyNotNumber = isNaN(propertyValue.red) || propertyValue.red === null; break; + case 'vec3rgb': + isPropertyNotNumber = isNaN(propertyValue.red) || propertyValue.red === null; + break; } if (isPropertyNotNumber) { if (fallbackMultiValue === null) { @@ -2662,6 +2669,33 @@ function createVec3Property(property, elProperty) { return elResult; } +function createVec3rgbProperty(property, elProperty) { + let propertyData = property.data; + + elProperty.className = propertyData.vec3Type + " fstuple"; + + let elNumberR = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.X_NUMBER]); + let elNumberG = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.Y_NUMBER]); + let elNumberB = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.Z_NUMBER]); + elProperty.appendChild(elNumberR.elDiv); + elProperty.appendChild(elNumberG.elDiv); + elProperty.appendChild(elNumberB.elDiv); + + elNumberR.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'red')); + elNumberG.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'green')); + elNumberB.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'blue')); + + elNumberR.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'red')); + elNumberG.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'green')); + elNumberB.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'blue')); + + let elResult = []; + elResult[VECTOR_ELEMENTS.X_NUMBER] = elNumberR; + elResult[VECTOR_ELEMENTS.Y_NUMBER] = elNumberG; + elResult[VECTOR_ELEMENTS.Z_NUMBER] = elNumberB; + return elResult; +} + function createVec2Property(property, elProperty) { let propertyData = property.data; @@ -2856,7 +2890,7 @@ function createTextureProperty(property, elProperty) { let imageLoad = function(url) { elDiv.style.display = null; - if (url.slice(0, 5).toLowerCase() === "atp:/") { + if (url.slice(0, 5).toLowerCase() === "atp:/" || url.slice(0, 9).toLowerCase() === "file:///~") { elImage.src = ""; elImage.style.display = "none"; elDiv.classList.remove("with-texture"); @@ -3048,6 +3082,13 @@ function createProperty(propertyData, propertyElementID, propertyName, propertyI property.elNumberB = elColor[COLOR_ELEMENTS.BLUE_NUMBER]; break; } + case 'vec3rgb': { + let elVec3 = createVec3rgbProperty(property, elProperty); + property.elNumberR = elVec3[VECTOR_ELEMENTS.X_NUMBER]; + property.elNumberG = elVec3[VECTOR_ELEMENTS.Y_NUMBER]; + property.elNumberB = elVec3[VECTOR_ELEMENTS.Z_NUMBER]; + break; + } case 'dropdown': { property.elInput = createDropdownProperty(property, propertyID, elProperty); break; @@ -4096,6 +4137,13 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { property.elNumberB.setValue(displayColor.blue); break; } + case 'vec3rgb': { + let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData); + property.elNumberR.setValue(detailedNumberDiff.averagePerPropertyComponent.red, detailedNumberDiff.propertyComponentDiff.red); + property.elNumberG.setValue(detailedNumberDiff.averagePerPropertyComponent.green, detailedNumberDiff.propertyComponentDiff.green); + property.elNumberB.setValue(detailedNumberDiff.averagePerPropertyComponent.blue, detailedNumberDiff.propertyComponentDiff.blue); + break; + } case 'dropdown': { property.elInput.classList.toggle('multi-diff', isMultiDiffValue); property.elInput.value = isMultiDiffValue ? "" : propertyValue; @@ -4350,7 +4398,8 @@ function loaded() { properties[propertyID] = property; } if (propertyData.type === 'number' || propertyData.type === 'number-draggable' || - propertyData.type === 'vec2' || propertyData.type === 'vec3' || propertyData.type === 'rect') { + propertyData.type === 'vec2' || propertyData.type === 'vec3' || + propertyData.type === 'rect' || propertyData.type === 'vec3rgb') { propertyRangeRequests.push(propertyID); } @@ -4435,6 +4484,9 @@ function loaded() { case 'vec2': updateVectorMinMax(properties[property]); break; + case 'vec3rgb': + updateVectorMinMax(properties[property]); + break; case 'rect': updateRectMinMax(properties[property]); break; diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index c72456d414..ada8116a0d 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -1688,17 +1688,17 @@ input.rename-entity { margin-left: 4px; margin-right: 10px; } -.fstuple label.red, .fstuple label.x, .fstuple label.w { +.fstuple label.red, .fstuple label.r, .fstuple label.x, .fstuple label.w { color: #C62147; } -.fstuple label.green, .fstuple label.y, .fstuple label.h { +.fstuple label.green, .fstuple label.g, .fstuple label.y, .fstuple label.h { color: #359D85; } -.fstuple label.blue, .fstuple label.z { +.fstuple label.blue, .fstuple label.b, .fstuple label.z { color: #0093C5; } -.xyz.fstuple, .pyr.fstuple { +.xyz.fstuple, .pyr.fstuple, .vec3rgb.fstuple { position: relative; left: -12px; min-width: 50px;