-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tremblp/maya 102361/rename fixes #237
Changes from all commits
27769c4
12889e2
b4d49f4
f53f29c
e508bdb
25bac95
c0277f0
30db4e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,43 @@ | |
// | ||
|
||
#include "UsdStageMap.h" | ||
#include "Utils.h" | ||
|
||
#include <maya/MFnDagNode.h> | ||
|
||
#include <cassert> | ||
|
||
namespace { | ||
|
||
MObjectHandle proxyShapeHandle(const Ufe::Path& path) | ||
{ | ||
// Get the MObjectHandle from the tail of the MDagPath. Remove the leading | ||
// '|world' component. | ||
auto noWorld = path.popHead().string(); | ||
auto dagPath = MayaUsd::ufe::nameToDagPath(noWorld); | ||
MObjectHandle handle(dagPath.node()); | ||
if (!handle.isValid()) { | ||
TF_CODING_ERROR("'%s' is not a path to a proxy shape node.", | ||
noWorld.c_str()); | ||
} | ||
return handle; | ||
} | ||
|
||
// Assuming proxy shape nodes cannot be instanced, simply return the first path. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll admit I'm not sure I fully understand the context here, but is this a safe assumption? In our pipeline, we definitely do instance There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For some additional context, the scene file for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created an issue describing the problem, and some areas that would need to be worked on: |
||
Ufe::Path firstPath(const MObjectHandle& handle) | ||
{ | ||
if (!TF_VERIFY(handle.isValid(), | ||
"Cannot get path from invalid object handle")) { | ||
return Ufe::Path(); | ||
} | ||
|
||
MDagPath dagPath; | ||
auto status = MFnDagNode(handle.object()).getPath(dagPath); | ||
CHECK_MSTATUS(status); | ||
return MayaUsd::ufe::dagPathToUfe(dagPath); | ||
} | ||
|
||
} | ||
|
||
MAYAUSD_NS_DEF { | ||
namespace ufe { | ||
|
@@ -31,32 +68,57 @@ UsdStageMap g_StageMap; | |
|
||
void UsdStageMap::addItem(const Ufe::Path& path, UsdStageWeakPtr stage) | ||
{ | ||
fPathToStage[path] = stage; | ||
fStageToPath[stage] = path; | ||
// We expect a path to the proxy shape node, therefore a single segment. | ||
auto nbSegments = | ||
#ifdef UFE_V0_2_6_FEATURES_AVAILABLE | ||
path.nbSegments(); | ||
#else | ||
path.getSegments().size(); | ||
#endif | ||
if (nbSegments != 1) { | ||
TF_CODING_ERROR("A proxy shape node path can have only one segment, path '%s' has %lu", path.string().c_str(), nbSegments); | ||
return; | ||
} | ||
|
||
// Convert the tail of the UFE path to an MObjectHandle. | ||
auto proxyShape = proxyShapeHandle(path); | ||
if (!proxyShape.isValid()) { | ||
return; | ||
} | ||
|
||
// Could get the stage from the proxy shape object in the stage() method, | ||
// but since it's given here, simply store it. | ||
fObjectToStage[proxyShape] = stage; | ||
fStageToObject[stage] = proxyShape; | ||
} | ||
|
||
UsdStageWeakPtr UsdStageMap::stage(const Ufe::Path& path) const | ||
{ | ||
auto proxyShape = proxyShapeHandle(path); | ||
if (!proxyShape.isValid()) { | ||
return nullptr; | ||
} | ||
|
||
// A stage is bound to a single Dag proxy shape. | ||
auto iter = fPathToStage.find(path); | ||
if (iter != std::end(fPathToStage)) | ||
auto iter = fObjectToStage.find(proxyShape); | ||
if (iter != std::end(fObjectToStage)) | ||
return iter->second; | ||
return nullptr; | ||
} | ||
|
||
Ufe::Path UsdStageMap::path(UsdStageWeakPtr stage) const | ||
{ | ||
// A stage is bound to a single Dag proxy shape. | ||
auto iter = fStageToPath.find(stage); | ||
if (iter != std::end(fStageToPath)) | ||
return iter->second; | ||
auto iter = fStageToObject.find(stage); | ||
if (iter != std::end(fStageToObject)) | ||
return firstPath(iter->second); | ||
return Ufe::Path(); | ||
} | ||
|
||
void UsdStageMap::clear() | ||
{ | ||
fPathToStage.clear(); | ||
fStageToPath.clear(); | ||
fObjectToStage.clear(); | ||
fStageToObject.clear(); | ||
} | ||
|
||
} // namespace ufe | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -22,22 +22,37 @@ | |||
#include <pxr/usd/usd/stage.h> | ||||
#include <pxr/base/tf/hash.h> | ||||
|
||||
#include <maya/MObjectHandle.h> | ||||
|
||||
#include <unordered_map> | ||||
|
||||
// Allow for use of MObjectHandle with std::unordered_map. | ||||
namespace std { | ||||
template <> struct hash<MObjectHandle> { | ||||
std::size_t operator()(const MObjectHandle& handle) const { | ||||
return static_cast<std::size_t>(handle.hashCode()); | ||||
} | ||||
}; | ||||
} | ||||
Comment on lines
+29
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be a great candidate for the kind of Maya-as-the-only-dependency utilities library that Animal Logic has been advocating for. We actually had something for this in usdMaya (now migrated to mayaUsd) as well: Line 105 in 31e6f34
There's nothing USD or UFE related about either implementation. |
||||
|
||||
PXR_NAMESPACE_USING_DIRECTIVE | ||||
|
||||
MAYAUSD_NS_DEF { | ||||
namespace ufe { | ||||
|
||||
//! \brief USD Stage Map | ||||
/*! | ||||
Map of AL_usdmaya_ProxyShape UFE path to corresponding stage. | ||||
|
||||
Map of stage to corresponding AL_usdmaya_ProxyShape UFE path. Ideally, we | ||||
would support dynamically computing the path for the AL_usdmaya_ProxyShape | ||||
node, but we assume here it will not be reparented. We will also assume that | ||||
a USD stage will not be instanced (even though nothing in the data model | ||||
prevents it). | ||||
Two-way map of proxy shape UFE path to corresponding stage. | ||||
|
||||
We will assume that a USD proxy shape will not be instanced (even though | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previous USD stage map was path-based, which was impossible to maintain in the presence of path changes through renaming. Simply use the proxy shape MObject instead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, slightly concerned about the no instancing assumption, but maybe I'm misunderstanding. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, you're not misunderstanding... As per other comment entered as |
||||
nothing in the data model prevents it). To support renaming and repathing, | ||||
we store an MObjectHandle in the maps, which is invariant to renaming and | ||||
repathing, and compute the path on access. This is slower than a scheme | ||||
where we cache using the Ufe::Path, but such a cache must be refreshed on | ||||
rename and repath, which is non-trivial, since there is no guarantee on the | ||||
order of notification of Ufe observers. An earlier implementation with | ||||
rename observation had the Maya Outliner (which observes rename) access the | ||||
UsdStageMap on rename before the UsdStageMap had been updated. | ||||
*/ | ||||
class MAYAUSD_CORE_PUBLIC UsdStageMap | ||||
{ | ||||
|
@@ -64,8 +79,10 @@ class MAYAUSD_CORE_PUBLIC UsdStageMap | |||
|
||||
private: | ||||
// We keep two maps for fast lookup when there are many proxy shapes. | ||||
std::unordered_map<Ufe::Path, UsdStageWeakPtr> fPathToStage; | ||||
TfHashMap<UsdStageWeakPtr, Ufe::Path, TfHash> fStageToPath; | ||||
using ObjectToStage = std::unordered_map<MObjectHandle, UsdStageWeakPtr>; | ||||
using StageToObject = TfHashMap<UsdStageWeakPtr, MObjectHandle, TfHash>; | ||||
ObjectToStage fObjectToStage; | ||||
StageToObject fStageToObject; | ||||
|
||||
}; // UsdStageMap | ||||
|
||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we're actually adding a usage of
Ufe::Rtid
at line 130, so I'm not sure why we're taking this include out? I know it was added to the header, but since there's usage in both files, I'd prefer to see the include in both files.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a huge deal, to be sure, but isn't that violating Don't Repeat Yourself? If maintenance removes the use of Ufe::Rtid, I'd now have two places to remove the include of ufe/rtid.h.