From 267531cc1a43e0a7cf29182a4a2525d24066fd8c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 10 Jul 2017 15:27:09 +0200 Subject: [PATCH] First working fade --- .../src/avatars-renderer/Avatar.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 17 ++- .../src/RenderableModelEntityItem.h | 11 +- libraries/render-utils/src/FadeEffect.cpp | 104 ++++++++++-------- libraries/render-utils/src/FadeEffect.h | 4 +- .../render-utils/src/RenderPipelines.cpp | 82 ++++++++------ libraries/render/src/render/Scene.cpp | 72 ++++++++++++ libraries/render/src/render/Scene.h | 12 +- libraries/render/src/render/Transition.h | 4 +- 9 files changed, 221 insertions(+), 87 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 9fa40fc60e..44a005194b 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -61,7 +61,7 @@ namespace render { template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) { auto avatarPtr = static_pointer_cast(avatar); if (avatarPtr->getSkeletonModel()) { - auto metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); + auto& metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); return (uint32_t) metaSubItems.size(); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0b6271a6b1..95a8812550 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -217,8 +217,9 @@ namespace render { } template <> uint32_t metaFetchMetaSubItems(const RenderableModelEntityItemMeta::Pointer& payload, ItemIDs& subItems) { auto modelEntity = std::static_pointer_cast(payload->entity); - if (modelEntity->hasModel()) { - auto metaSubItems = modelEntity->getModelNotSafe()->fetchRenderItemIDs(); + auto model = modelEntity->getModelNotSafe(); + if (modelEntity->hasModel() && model) { + auto& metaSubItems = model->fetchRenderItemIDs(); subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); return (uint32_t) metaSubItems.size(); } @@ -489,6 +490,17 @@ ModelPointer RenderableModelEntityItem::getModelNotSafe() { return _model; } +void RenderableModelEntityItem::setModelURLFinished(bool success) { + if (success) { + const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene(); + render::Transaction transaction; + + const auto& item = scene->getItem(_myMetaItem); + transaction.transitionItem(_myMetaItem, render::Transition::ELEMENT_ENTER_LEAVE_DOMAIN); + scene->enqueueTransaction(transaction); + } +} + ModelPointer RenderableModelEntityItem::getModel() { // make sure our renderer is setup if (!_myRenderer) { @@ -506,6 +518,7 @@ ModelPointer RenderableModelEntityItem::getModel() { // If we don't have a model, allocate one *immediately* if (!_model) { _model = _myRenderer->allocateModel(getModelURL(), _myRenderer->getEntityLoadingPriority(*this), this); + QObject::connect(_model.get(), &Model::setURLFinished, this, &RenderableModelEntityItem::setModelURLFinished); _needsInitialSimulation = true; // If we need to change URLs, update it *after rendering* (to avoid access violations) } else if (QUrl(getModelURL()) != _model->getURL()) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 2d240c01a6..6586678906 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -12,16 +12,21 @@ #ifndef hifi_RenderableModelEntityItem_h #define hifi_RenderableModelEntityItem_h +#include #include #include #include #include +#include + +#include "RenderableEntityItem.h" class Model; class EntityTreeRenderer; -class RenderableModelEntityItem : public ModelEntityItem, RenderableEntityInterface { +class RenderableModelEntityItem : public QObject, public ModelEntityItem, RenderableEntityInterface { + Q_OBJECT public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -116,6 +121,10 @@ public: return _animation; } +public slots: + + void setModelURLFinished(bool success); + private: QVariantMap parseTexturesToMap(QString textures); void remapTextures(); diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index ac087dc1c0..c8a9167ed4 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -464,6 +464,7 @@ FadeJob::FadeJob() { auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; _fadeMaskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); + _previousTime = usecTimestampNow(); } void FadeJob::configure(const Config& config) { @@ -493,76 +494,91 @@ void FadeJob::run(const render::RenderContextPointer& renderContext) { auto transitionStage = scene->getStage(render::TransitionStage::getName()); uint64_t now = usecTimestampNow(); const double deltaTime = (int64_t(now) - int64_t(_previousTime)) / double(USECS_PER_SECOND); + render::Transaction transaction; + bool hasTransactions = false; // And now update fade effect for (auto transitionId : *transitionStage) { auto& state = transitionStage->editTransition(transitionId); - update(*jobConfig, scene, state, deltaTime); + if (!update(*jobConfig, scene, state, deltaTime)) { + // Remove transition for this item + transaction.transitionItem(state.itemId, render::Transition::NONE); + hasTransactions = true; + } } + if (hasTransactions) { + scene->enqueueTransaction(transaction); + } _previousTime = now; } -void FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const { +bool FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const { auto& eventConfig = config.events[transition.eventType]; auto& item = scene->getItem(transition.itemId); - auto& aabb = item.getBound(); - auto& dimensions = aabb.getDimensions(); const double eventDuration = (double)eventConfig.duration; const FadeConfig::Timing timing = (FadeConfig::Timing) eventConfig.timing; + bool continueTransition = true; - assert(timing < render::Transition::EVENT_CATEGORY_COUNT); + if (item.exist()) { + auto& aabb = item.getBound(); + auto& dimensions = aabb.getDimensions(); - switch (transition.eventType) { - case render::Transition::ELEMENT_ENTER_LEAVE_DOMAIN: - transition.threshold = 1.f - computeElementEnterThreshold(transition.time, eventConfig.duration, timing); - transition.threshold = (transition.threshold - 0.5f)*_thresholdScale[transition.eventType] + 0.5f; - transition.noiseOffset = aabb.calcCenter(); - transition.baseOffset = transition.noiseOffset - dimensions.y; - transition.baseInvSize.x = 1.f / dimensions.x; - transition.baseInvSize.y = 1.f / dimensions.y; - transition.baseInvSize.z = 1.f / dimensions.z; + assert(timing < render::Transition::EVENT_CATEGORY_COUNT); + + switch (transition.eventType) { + case render::Transition::ELEMENT_ENTER_LEAVE_DOMAIN: + transition.threshold = 1.f - computeElementEnterRatio(transition.time, eventConfig.duration, timing); + transition.threshold = (transition.threshold - 0.5f)*_thresholdScale[transition.eventType] + 0.5f; + transition.noiseOffset = aabb.calcCenter(); + transition.baseOffset = transition.noiseOffset - dimensions.y; + transition.baseInvSize.x = 1.f / dimensions.x; + transition.baseInvSize.y = 1.f / dimensions.y; + transition.baseInvSize.z = 1.f / dimensions.z; + continueTransition = transition.threshold > 0.f; + break; + + case render::Transition::BUBBLE_ISECT_OWNER: + { + /* const glm::vec3 cameraPos = renderContext->args->getViewFrustum().getPosition(); + glm::vec3 delta = itemBounds.bound.calcCenter() - cameraPos; + float distance = glm::length(delta); + + delta = glm::normalize(delta) * std::max(0.f, distance - 0.5f); + + _editBaseOffset = cameraPos + delta*_editThreshold; + _editThreshold = 0.33f;*/ + } break; - case render::Transition::BUBBLE_ISECT_OWNER: - { - /* const glm::vec3 cameraPos = renderContext->args->getViewFrustum().getPosition(); - glm::vec3 delta = itemBounds.bound.calcCenter() - cameraPos; - float distance = glm::length(delta); - - delta = glm::normalize(delta) * std::max(0.f, distance - 0.5f); - - _editBaseOffset = cameraPos + delta*_editThreshold; - _editThreshold = 0.33f;*/ - } - break; - - case render::Transition::BUBBLE_ISECT_TRESPASSER: - { - // _editBaseOffset = glm::vec3{ 0.f, 0.f, 0.f }; - } - break; - - case render::Transition::USER_ENTER_LEAVE_DOMAIN: - { -/* _editBaseOffset = itemBounds.bound.calcCenter(); - _editBaseOffset.y -= itemBounds.bound.getDimensions().y / 2.f;*/ - } - break; - - case render::Transition::AVATAR_CHANGE: + case render::Transition::BUBBLE_ISECT_TRESPASSER: + { + // _editBaseOffset = glm::vec3{ 0.f, 0.f, 0.f }; + } break; - default: - assert(false); + case render::Transition::USER_ENTER_LEAVE_DOMAIN: + { + /* _editBaseOffset = itemBounds.bound.calcCenter(); + _editBaseOffset.y -= itemBounds.bound.getDimensions().y / 2.f;*/ + } + break; + + case render::Transition::AVATAR_CHANGE: + break; + + default: + assert(false); + } } transition.time += deltaTime; // renderContext->jobConfig->setProperty("threshold", threshold); + return continueTransition; } -float FadeJob::computeElementEnterThreshold(double time, const double period, FadeConfig::Timing timing) const { +float FadeJob::computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing) { assert(period > 0.0); float fadeAlpha = 1.0f; const double INV_FADE_PERIOD = 1.0 / period; diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 14f5ef1deb..413d4124ce 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -193,8 +193,8 @@ private: float _thresholdScale[render::Transition::EVENT_CATEGORY_COUNT]; uint64_t _previousTime{ 0 }; - void update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const; - float computeElementEnterThreshold(double time, const double period, FadeConfig::Timing timing) const; + bool update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const; + static float computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing); const render::Item* findNearestItem(const render::RenderContextPointer& renderContext, const render::Varying& input, float& minIsectDistance) const; }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 12c19bc06e..c5949cb336 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -104,7 +104,8 @@ void initDeferredPipelines(ShapePlumber& plumber, const render::ShapePipeline::B void initForwardPipelines(ShapePlumber& plumber); void addPlumberPipeline(ShapePlumber& plumber, - const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel); + const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel, + const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args); void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args); @@ -228,30 +229,30 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip auto simpleTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_unlit_fade_frag)); using Key = render::ShapeKey; - auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); + auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, _4, _5); // TODO: Refactor this to use a filter // Opaques addPipeline( Key::Builder().withMaterial(), - modelVertex, modelPixel); + modelVertex, modelPixel, nullptr, nullptr); addPipeline( Key::Builder(), - simpleVertex, simplePixel); + simpleVertex, simplePixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withUnlit(), - modelVertex, modelUnlitPixel); + modelVertex, modelUnlitPixel, nullptr, nullptr); addPipeline( Key::Builder().withUnlit(), - simpleVertex, simpleUnlitPixel); + simpleVertex, simpleUnlitPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withTangents(), - modelNormalMapVertex, modelNormalMapPixel); + modelNormalMapVertex, modelNormalMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSpecular(), - modelVertex, modelSpecularMapPixel); + modelVertex, modelSpecularMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withTangents().withSpecular(), - modelNormalMapVertex, modelNormalSpecularMapPixel); + modelNormalMapVertex, modelNormalSpecularMapPixel, nullptr, nullptr); // Same thing but with Fade on addPipeline( Key::Builder().withMaterial().withFade(), @@ -278,29 +279,29 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip // Translucents addPipeline( Key::Builder().withMaterial().withTranslucent(), - modelVertex, modelTranslucentPixel); + modelVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withTranslucent(), - simpleVertex, simpleTranslucentPixel); + simpleVertex, simpleTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withTranslucent().withUnlit(), - modelVertex, modelTranslucentUnlitPixel); + modelVertex, modelTranslucentUnlitPixel, nullptr, nullptr); addPipeline( Key::Builder().withTranslucent().withUnlit(), - simpleVertex, simpleTranslucentUnlitPixel); + simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withTranslucent().withTangents(), - modelNormalMapVertex, modelTranslucentPixel); + modelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withTranslucent().withSpecular(), - modelVertex, modelTranslucentPixel); + modelVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(), - modelNormalMapVertex, modelTranslucentPixel); + modelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( // FIXME: Ignore lightmap for translucents meshpart Key::Builder().withMaterial().withTranslucent().withLightmap(), - modelVertex, modelTranslucentPixel); + modelVertex, modelTranslucentPixel, nullptr, nullptr); // Same thing but with Fade on addPipeline( Key::Builder().withMaterial().withTranslucent().withFade(), @@ -331,16 +332,16 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip // Lightmapped addPipeline( Key::Builder().withMaterial().withLightmap(), - modelLightmapVertex, modelLightmapPixel); + modelLightmapVertex, modelLightmapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withLightmap().withTangents(), - modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); + modelLightmapNormalMapVertex, modelLightmapNormalMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withLightmap().withSpecular(), - modelLightmapVertex, modelLightmapSpecularMapPixel); + modelLightmapVertex, modelLightmapSpecularMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withLightmap().withTangents().withSpecular(), - modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel, nullptr, nullptr); // Same thing but with Fade on addPipeline( Key::Builder().withMaterial().withLightmap().withFade(), @@ -358,16 +359,16 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip // Skinned addPipeline( Key::Builder().withMaterial().withSkinned(), - skinModelVertex, modelPixel); + skinModelVertex, modelPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withTangents(), - skinModelNormalMapVertex, modelNormalMapPixel); + skinModelNormalMapVertex, modelNormalMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withSpecular(), - skinModelVertex, modelSpecularMapPixel); + skinModelVertex, modelSpecularMapPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(), - skinModelNormalMapVertex, modelNormalSpecularMapPixel); + skinModelNormalMapVertex, modelNormalSpecularMapPixel, nullptr, nullptr); // Same thing but with Fade on addPipeline( Key::Builder().withMaterial().withSkinned().withFade(), @@ -385,16 +386,16 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip // Skinned and Translucent addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent(), - skinModelVertex, modelTranslucentPixel); + skinModelVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(), - skinModelNormalMapVertex, modelTranslucentPixel); + skinModelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(), - skinModelVertex, modelTranslucentPixel); + skinModelVertex, modelTranslucentPixel, nullptr, nullptr); addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(), - skinModelNormalMapVertex, modelTranslucentPixel); + skinModelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr); // Same thing but with Fade on addPipeline( Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(), @@ -412,10 +413,10 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip // Depth-only addPipeline( Key::Builder().withDepthOnly(), - modelShadowVertex, modelShadowPixel); + modelShadowVertex, modelShadowPixel, nullptr, nullptr); addPipeline( Key::Builder().withSkinned().withDepthOnly(), - skinModelShadowVertex, modelShadowPixel); + skinModelShadowVertex, modelShadowPixel, nullptr, nullptr); // Same thing but with Fade on addPipeline( Key::Builder().withDepthOnly().withFade(), @@ -440,7 +441,7 @@ void initForwardPipelines(render::ShapePlumber& plumber) { auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(forward_model_normal_specular_map_frag)); using Key = render::ShapeKey; - auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); + auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, nullptr, nullptr); // Opaques addPipeline( Key::Builder().withMaterial(), @@ -473,7 +474,8 @@ void initForwardPipelines(render::ShapePlumber& plumber) { } void addPlumberPipeline(ShapePlumber& plumber, - const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel) { + const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel, + const render::ShapePipeline::BatchSetter& extraBatchSetter, const render::ShapePipeline::ItemSetter& itemSetter) { // These key-values' pipelines are added by this functor in addition to the key passed assert(!key.isWireframe()); assert(!key.isDepthBiased()); @@ -510,8 +512,18 @@ void addPlumberPipeline(ShapePlumber& plumber, state->setDepthBiasSlopeScale(1.0f); } - plumber.addPipeline(builder.build(), program, state, - key.isTranslucent() ? &lightBatchSetter : &batchSetter); + auto baseBatchSetter = key.isTranslucent() ? &lightBatchSetter : &batchSetter; + render::ShapePipeline::BatchSetter finalBatchSetter; + if (extraBatchSetter) { + finalBatchSetter = [baseBatchSetter, extraBatchSetter](const ShapePipeline& pipeline, gpu::Batch& batch, render::Args* args) { + baseBatchSetter(pipeline, batch, args); + extraBatchSetter(pipeline, batch, args); + }; + } + else { + finalBatchSetter = baseBatchSetter; + } + plumber.addPipeline(builder.build(), program, state, finalBatchSetter, itemSetter); } } diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index b8f93c52c3..12a04eef7b 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -13,6 +13,7 @@ #include #include #include "Logging.h" +#include "TransitionStage.h" using namespace render; @@ -30,6 +31,11 @@ void Transaction::removeItem(ItemID id) { _removedItems.emplace_back(id); } +void Transaction::transitionItem(ItemID id, Transition::Type transition) { + _transitioningItems.emplace_back(id); + _transitionTypes.emplace_back(transition); +} + void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) { _updatedItems.emplace_back(id); _updateFunctors.emplace_back(functor); @@ -46,6 +52,8 @@ void Transaction::merge(const Transaction& transaction) { _updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end()); _updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end()); _resetSelections.insert(_resetSelections.end(), transaction._resetSelections.begin(), transaction._resetSelections.end()); + _transitioningItems.insert(_transitioningItems.end(), transaction._transitioningItems.begin(), transaction._transitioningItems.end()); + _transitionTypes.insert(_transitionTypes.end(), transaction._transitionTypes.begin(), transaction._transitionTypes.end()); } @@ -115,6 +123,9 @@ void Scene::processTransactionQueue() { // removes removeItems(consolidatedTransaction._removedItems); + // Transitions + transitionItems(consolidatedTransaction._transitioningItems, consolidatedTransaction._transitionTypes); + // Update the numItemsAtomic counter AFTER the pending changes went through _numAllocatedItems.exchange(maxID); } @@ -216,6 +227,67 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) { } } +void Scene::transitionItems(const ItemIDs& ids, const TransitionTypes& types) { + auto transitionType = types.begin(); + auto transitionStage = getStage(TransitionStage::getName()); + + for (auto itemId : ids) { + auto transitionId = INVALID_INDEX; + + if (*transitionType != Transition::NONE) { + transitionId = transitionStage->addTransition(itemId, *transitionType); + } + + setItemTransition(itemId, transitionId); + // next loop + transitionType++; + } +} + +void Scene::collectSubItems(ItemID parentId, ItemIDs& subItems) const { + // Access the true item + auto& item = _items[parentId]; + + if (item.exist()) { + // Recursivelly collect the subitems + auto subItemBeginIndex = subItems.size(); + auto subItemCount = item.fetchMetaSubItems(subItems); + for (auto i = subItemBeginIndex; i < (subItemBeginIndex + subItemCount); i++) { + collectSubItems(subItems[i], subItems); + } + } +} + +void Scene::setItemTransition(ItemID itemId, Index transitionId) { + // Access the true item + auto& item = _items[itemId]; + + if (item.exist()) { + ItemIDs subItems; + + item.setTransitionId(transitionId); + + // Sub-items share the same transition Id + collectSubItems(itemId, subItems); + for (auto subItemId : subItems) { + auto& subItem = _items[subItemId]; + subItem.setTransitionId(transitionId); + } + } + else { + qWarning() << "Collecting sub items on item without payload"; + } +} + +void Scene::resetItemTransition(ItemID itemId) { + // Access the true item + auto& item = _items[itemId]; + auto transitionStage = getStage(TransitionStage::getName()); + + transitionStage->removeTransition(item.getTransitionId()); + setItemTransition(itemId, Transition::NONE); +} + // THis fucntion is thread safe Selection Scene::getSelection(const Selection::Name& name) const { std::unique_lock lock(_selectionsMutex); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 199d9ce224..90255033ce 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -16,6 +16,7 @@ #include "SpatialTree.h" #include "Stage.h" #include "Selection.h" +#include "Transition.h" namespace render { @@ -39,6 +40,8 @@ public: void resetItem(ItemID id, const PayloadPointer& payload); void removeItem(ItemID id); + void transitionItem(ItemID id, Transition::Type transition); + template void updateItem(ItemID id, std::function func) { updateItem(id, std::make_shared>(func)); } @@ -54,10 +57,12 @@ public: // Checkers if there is work to do when processing the transaction bool touchTransactions() const { return !_resetSelections.empty(); } - ItemIDs _resetItems; + ItemIDs _resetItems; Payloads _resetPayloads; ItemIDs _removedItems; ItemIDs _updatedItems; + ItemIDs _transitioningItems; + TransitionTypes _transitionTypes; UpdateFunctors _updateFunctors; Selections _resetSelections; @@ -123,6 +128,8 @@ public: } void resetStage(const Stage::Name& name, const StagePointer& stage); + void setItemTransition(ItemID id, Index transitionId); + void resetItemTransition(ItemID id); protected: // Thread safe elements that can be accessed from anywhere @@ -141,6 +148,9 @@ protected: void resetItems(const ItemIDs& ids, Payloads& payloads); void removeItems(const ItemIDs& ids); void updateItems(const ItemIDs& ids, UpdateFunctors& functors); + void transitionItems(const ItemIDs& ids, const TransitionTypes& types); + + void collectSubItems(ItemID parentId, ItemIDs& subItems) const; // The Selection map mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method diff --git a/libraries/render/src/render/Transition.h b/libraries/render/src/render/Transition.h index 240c5fe339..4e52693efd 100644 --- a/libraries/render/src/render/Transition.h +++ b/libraries/render/src/render/Transition.h @@ -27,7 +27,8 @@ namespace render { AVATAR_CHANGE, // Don't forget to modify Fade.slh to reflect the change in number of categories - EVENT_CATEGORY_COUNT + EVENT_CATEGORY_COUNT, + NONE = EVENT_CATEGORY_COUNT }; Type eventType{ ELEMENT_ENTER_LEAVE_DOMAIN }; @@ -41,6 +42,7 @@ namespace render { }; typedef std::shared_ptr TransitionPointer; + typedef std::vector TransitionTypes; } #endif // hifi_render_Transition_h \ No newline at end of file