From eff48f93fa38d230f89c185d36b46cc849e1de87 Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Tue, 6 Nov 2018 14:28:10 -0500 Subject: [PATCH] MAYA-95322 update bounding box of AL_MayaUSD proxy shape (#25) * MAYA-95322 update bounding box of AL_MayaUSD proxy shape * MAYA-95322 code review feedback --- lib/AL_USDMaya/AL/usdmaya/Global.cpp | 198 +++++++++++++++++++ lib/AL_USDMaya/AL/usdmaya/Global.h | 7 + lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h | 5 + 3 files changed, 210 insertions(+) diff --git a/lib/AL_USDMaya/AL/usdmaya/Global.cpp b/lib/AL_USDMaya/AL/usdmaya/Global.cpp index 999291e2..f7b4a9db 100644 --- a/lib/AL_USDMaya/AL/usdmaya/Global.cpp +++ b/lib/AL_USDMaya/AL/usdmaya/Global.cpp @@ -16,6 +16,7 @@ #include "AL/usdmaya/Global.h" #include "AL/usdmaya/StageCache.h" #include "AL/usdmaya/DebugCodes.h" +#include "AL/usdmaya/TypeIDs.h" #include "AL/usdmaya/nodes/LayerManager.h" #include "AL/usdmaya/nodes/ProxyShape.h" #include "AL/usdmaya/nodes/Transform.h" @@ -28,9 +29,21 @@ #include #include +#if defined(WANT_UFE_BUILD) +#include "ufe/globalSelection.h" +#include "ufe/observer.h" +#include "ufe/observableSelection.h" +#include "ufe/path.h" +#include "ufe/sceneItemList.h" +#include "ufe/selectionNotification.h" +#include "ufe/transform3d.h" +#include "ufe/transform3dNotification.h" +#endif + #include "maya/MGlobal.h" #include "maya/MFnDependencyNode.h" #include "maya/MItDependencyNodes.h" +#include "maya/MSelectionList.h" #include @@ -45,12 +58,165 @@ namespace { // once per top-level file read operation (ie, once per open, or once // per import, or once per reference). std::atomic readDepth; + +#if defined(WANT_UFE_BUILD) + // The proxy shape has an internal cache which needs to update when any of + // its UFE scene items are selected and transformed. + class UfeTransformObserver : public Ufe::Observer + { + public: + UfeTransformObserver() : Ufe::Observer() + { + } + + ~UfeTransformObserver() override + { + } + + void operator()(const Ufe::Notification& notification) override + { + auto xformChanged = dynamic_cast(¬ification); + if (xformChanged == nullptr) return; + + // Action for USD scene items only. + Ufe::SceneItem::Ptr sceneItem = xformChanged->item(); + if (!sceneItem || (sceneItem->runTimeId() != AL::usdmaya::USD_UFE_RUNTIME_ID)) return; + + std::string mayaPath = sceneItem->path().popSegment().popHead().string(); + + MSelectionList sl; + sl.add(MString(mayaPath.c_str())); + + MObject object; + MStatus status = sl.getDependNode(0, object); + if (!status) return; + + MFnDependencyNode dependNode(object, &status); + if (!status) return; + + if (dependNode.typeId() == AL::usdmaya::nodes::ProxyShape::kTypeId) + { + auto proxyShape = + dynamic_cast(dependNode.userNode()); + if (proxyShape) + { + proxyShape->clearBoundingBoxCache(); + } + } + } + }; +#endif } namespace AL { namespace usdmaya { +//---------------------------------------------------------------------------------------------------------------------- +#if defined(WANT_UFE_BUILD) + // Observe UFE scene items for transformation changed only when they are selected. + class Global::UfeSelectionObserver : public Ufe::Observer + { + public: + UfeSelectionObserver() + : Ufe::Observer() + , m_ufeTransformObserver(std::make_shared()) + , m_openingFile(false) + { + } + + ~UfeSelectionObserver() override + { + clear(); + } + + void clear() + { + for (auto si : m_observedSceneItems) + { + Ufe::Transform3d::removeObserver(si, m_ufeTransformObserver); + } + + m_observedSceneItems.clear(); + } + + void observe(const Ufe::SceneItem::Ptr& si) + { + if (si && + (si->runTimeId() == USD_UFE_RUNTIME_ID) && + Ufe::Transform3d::addObserver(si, m_ufeTransformObserver)) + { + m_observedSceneItems.push_back(si); + } + } + + void openingFile(bool val) + { + m_openingFile = val; + } + + void operator()(const Ufe::Notification& notification) override + { + // During Maya file read, each node will be selected in turn, so we get + // notified for each node in the scene. Prune this out. + if (m_openingFile) + { + return; + } + + auto selectionChanged = dynamic_cast(¬ification); + if (selectionChanged == nullptr) + { + return; + } + + if (dynamic_cast(selectionChanged)) + { + clear(); + } + else if (dynamic_cast(selectionChanged) || + dynamic_cast(selectionChanged)) + { + clear(); + + const Ufe::GlobalSelection::Ptr& ufeSelection = Ufe::GlobalSelection::get(); + if (ufeSelection) + { + for (auto it = ufeSelection->cbegin(); it != ufeSelection->cend(); it++) + { + observe(*it); + } + } + } + else if (auto appended = dynamic_cast(selectionChanged)) + { + observe(appended->item()); + } + else if (auto removed = dynamic_cast(selectionChanged)) + { + Ufe::SceneItem::Ptr si = removed->item(); + if (si && + (si->runTimeId() == USD_UFE_RUNTIME_ID) && + Ufe::Transform3d::removeObserver(si, m_ufeTransformObserver)) + { + m_observedSceneItems.remove(si); + } + } + } + + private: + // Scene items being observed for transformation matrix change. + Ufe::SceneItemList m_observedSceneItems; + + // Transform3d observer for selected scene items. + std::shared_ptr m_ufeTransformObserver; + + bool m_openingFile; + }; + + std::shared_ptr Global::m_ufeSelectionObserver; +#endif + //---------------------------------------------------------------------------------------------------------------------- AL::event::CallbackId Global::m_preSave; AL::event::CallbackId Global::m_postSave; @@ -164,6 +330,8 @@ static void preFileRead(void*) } } } + + Global::openingFile(true); } ++readDepth; @@ -262,6 +430,8 @@ static void postFileRead(void*) } } } + + Global::openingFile(false); } //---------------------------------------------------------------------------------------------------------------------- @@ -358,6 +528,15 @@ void Global::onPluginLoad() std::string pluginLocation(TfStringCatPaths(TfGetenv(AL_USDMAYA_LOCATION_NAME), "share/usd/plugins")); PlugRegistry::GetInstance().RegisterPlugins(pluginLocation); +#if defined(WANT_UFE_BUILD) + const Ufe::GlobalSelection::Ptr& ufeSelection = Ufe::GlobalSelection::get(); + if (ufeSelection) + { + m_ufeSelectionObserver = std::make_shared(); + ufeSelection->addObserver(m_ufeSelectionObserver); + } +#endif + // For callback initialization for stage cache callback, it will be done via proxy node attribute change. } @@ -377,6 +556,25 @@ void Global::onPluginUnload() AL::maya::event::MayaEventManager::freeInstance(); AL::event::EventScheduler::freeScheduler(); + +#if defined(WANT_UFE_BUILD) + const Ufe::GlobalSelection::Ptr& ufeSelection = Ufe::GlobalSelection::get(); + if (ufeSelection) + { + ufeSelection->removeObserver(m_ufeSelectionObserver); + m_ufeSelectionObserver = nullptr; + } +#endif +} + +void Global::openingFile(bool val) +{ +#if defined(WANT_UFE_BUILD) + if (m_ufeSelectionObserver) + { + m_ufeSelectionObserver->openingFile(val); + } +#endif } //---------------------------------------------------------------------------------------------------------------------- diff --git a/lib/AL_USDMaya/AL/usdmaya/Global.h b/lib/AL_USDMaya/AL/usdmaya/Global.h index f737e7c4..774bbb57 100644 --- a/lib/AL_USDMaya/AL/usdmaya/Global.h +++ b/lib/AL_USDMaya/AL/usdmaya/Global.h @@ -61,6 +61,8 @@ class Global static AL::event::CallbackId fileNew() { return m_fileNew; } + static void openingFile(bool val); + private: static AL::event::CallbackId m_preSave; ///< callback prior to saving the scene (so we can store the session layer) static AL::event::CallbackId m_postSave; ///< callback after saving @@ -69,6 +71,11 @@ class Global static AL::event::CallbackId m_fileNew; ///< callback used to flush the USD caches after a file new static AL::event::CallbackId m_preExport; ///< callback prior to exporting the scene (so we can store the session layer) static AL::event::CallbackId m_postExport; ///< callback after exporting + +#if defined(WANT_UFE_BUILD) + class UfeSelectionObserver; + static std::shared_ptr m_ufeSelectionObserver; +#endif }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h b/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h index 81b787c4..d4b06393 100644 --- a/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h +++ b/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h @@ -858,6 +858,11 @@ class ProxyShape AL_USDMAYA_PUBLIC MSelectionMask getShapeSelectionMask() const override; + /// \brief Clears the bounding box cache of the shape + AL_USDMAYA_PUBLIC + void clearBoundingBoxCache() + { m_boundingBoxCache.clear(); } + private: static void onSelectionChanged(void* ptr);