From 5ee703f32bca7fa9b2f9cf3a8a19eb3b98d67689 Mon Sep 17 00:00:00 2001 From: Yves Boudreault Date: Mon, 4 Apr 2022 11:47:32 -0400 Subject: [PATCH 1/4] Fix for MAYA-122381 Target Layer moves and stays on Session Layer when Editing As Maya Data Stage is not passed as a parameter instead of trying to find the right one. SessionLayer is only set temporarely asa the edit target instead of premanently. --- lib/mayaUsd/fileio/jobs/jobArgs.cpp | 22 ++++++++++++++++++---- lib/mayaUsd/fileio/jobs/jobArgs.h | 4 ++-- lib/mayaUsd/fileio/jobs/readJob.cpp | 8 ++++---- lib/mayaUsd/fileio/primUpdaterManager.cpp | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/mayaUsd/fileio/jobs/jobArgs.cpp b/lib/mayaUsd/fileio/jobs/jobArgs.cpp index 97856b66fe..afc7c73449 100644 --- a/lib/mayaUsd/fileio/jobs/jobArgs.cpp +++ b/lib/mayaUsd/fileio/jobs/jobArgs.cpp @@ -87,6 +87,19 @@ bool _Boolean(const VtDictionary& userArgs, const TfToken& key) return VtDictionaryGet(userArgs, key); } +/// Extracts a pointer at \p key from \p userArgs, or nullptr if it can't extract. +UsdStageRefPtr _UsdStageRefPtr(const VtDictionary& userArgs, const TfToken& key) +{ + if (!VtDictionaryIsHolding(userArgs, key)) { + TF_CODING_ERROR( + "Dictionary is missing required key '%s' or key is " + "not pointer type", + key.GetText()); + return nullptr; + } + return VtDictionaryGet(userArgs, key); +} + /// Extracts a string at \p key from \p userArgs, or "" if it can't extract. std::string _String(const VtDictionary& userArgs, const TfToken& key) { @@ -1018,7 +1031,7 @@ UsdMayaJobImportArgs::UsdMayaJobImportArgs( , importInstances(_Boolean(userArgs, UsdMayaJobImportArgsTokens->importInstances)) , useAsAnimationCache(_Boolean(userArgs, UsdMayaJobImportArgsTokens->useAsAnimationCache)) , importWithProxyShapes(importWithProxyShapes) - , pullImport(_Boolean(userArgs, UsdMayaJobImportArgsTokens->pullImport)) + , pullImportStage(_UsdStageRefPtr(userArgs, UsdMayaJobImportArgsTokens->pullImportStage)) , timeInterval(timeInterval) , chaserNames(_Vector(userArgs, UsdMayaJobImportArgsTokens->chaser)) , allChaserArgs(_ChaserArgs(userArgs, UsdMayaJobImportArgsTokens->chaserArgs)) @@ -1070,7 +1083,7 @@ const VtDictionary& UsdMayaJobImportArgs::GetDefaultDictionary() d[UsdMayaJobImportArgsTokens->importInstances] = true; d[UsdMayaJobImportArgsTokens->importUSDZTextures] = false; d[UsdMayaJobImportArgsTokens->importUSDZTexturesFilePath] = ""; - d[UsdMayaJobImportArgsTokens->pullImport] = false; + d[UsdMayaJobImportArgsTokens->pullImportStage] = UsdStageRefPtr(); d[UsdMayaJobImportArgsTokens->useAsAnimationCache] = false; d[UsdMayaJobExportArgsTokens->chaser] = std::vector(); d[UsdMayaJobExportArgsTokens->chaserArgs] = std::vector(); @@ -1128,6 +1141,7 @@ const VtDictionary& UsdMayaJobImportArgs::GetGuideDictionary() std::call_once(once, []() { // Common types: const auto _boolean = VtValue(false); + const auto _usdStageRefPtr = VtValue(nullptr); const auto _string = VtValue(std::string()); const auto _stringVector = VtValue(std::vector({ _string })); const auto _stringTuplet = VtValue(std::vector({ _string, _string, _string })); @@ -1146,7 +1160,7 @@ const VtDictionary& UsdMayaJobImportArgs::GetGuideDictionary() d[UsdMayaJobImportArgsTokens->importInstances] = _boolean; d[UsdMayaJobImportArgsTokens->importUSDZTextures] = _boolean; d[UsdMayaJobImportArgsTokens->importUSDZTexturesFilePath] = _string; - d[UsdMayaJobImportArgsTokens->pullImport] = _boolean; + d[UsdMayaJobImportArgsTokens->pullImportStage] = _usdStageRefPtr; d[UsdMayaJobImportArgsTokens->useAsAnimationCache] = _boolean; d[UsdMayaJobExportArgsTokens->chaser] = _stringVector; d[UsdMayaJobExportArgsTokens->chaserArgs] = _stringTripletVector; @@ -1232,7 +1246,7 @@ std::ostream& operator<<(std::ostream& out, const UsdMayaJobImportArgs& importAr << "importInstances: " << TfStringify(importArgs.importInstances) << std::endl << "importUSDZTextures: " << TfStringify(importArgs.importUSDZTextures) << std::endl << "importUSDZTexturesFilePath: " << TfStringify(importArgs.importUSDZTexturesFilePath) - << "pullImport: " << TfStringify(importArgs.pullImport) << std::endl + << "pullImportStage: " << TfStringify(importArgs.pullImportStage) << std::endl << std::endl << "timeInterval: " << importArgs.timeInterval << std::endl << "useAsAnimationCache: " << TfStringify(importArgs.useAsAnimationCache) << std::endl diff --git a/lib/mayaUsd/fileio/jobs/jobArgs.h b/lib/mayaUsd/fileio/jobs/jobArgs.h index 27434358c8..42c5a9c0a4 100644 --- a/lib/mayaUsd/fileio/jobs/jobArgs.h +++ b/lib/mayaUsd/fileio/jobs/jobArgs.h @@ -133,7 +133,7 @@ TF_DECLARE_PUBLIC_TOKENS( (importInstances) \ (importUSDZTextures) \ (importUSDZTexturesFilePath) \ - (pullImport) \ + (pullImportStage) \ /* assemblyRep values */ \ (Collapsed) \ (Full) \ @@ -305,7 +305,7 @@ struct UsdMayaJobImportArgs const bool importInstances; const bool useAsAnimationCache; const bool importWithProxyShapes; - const bool pullImport; + const UsdStageRefPtr pullImportStage; /// The interval over which to import animated data. /// An empty interval (GfInterval::IsEmpty()) means that no /// animated (time-sampled) data should be imported. diff --git a/lib/mayaUsd/fileio/jobs/readJob.cpp b/lib/mayaUsd/fileio/jobs/readJob.cpp index 8129da8aeb..659f24250b 100644 --- a/lib/mayaUsd/fileio/jobs/readJob.cpp +++ b/lib/mayaUsd/fileio/jobs/readJob.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -142,10 +143,8 @@ bool UsdMaya_ReadJob::Read(std::vector* addedDagPaths) UsdStageCacheContext stageCacheContext(UsdMayaStageCache::Get( mImportData.stageInitialLoadSet() == UsdStage::InitialLoadSet::LoadAll)); - if (mArgs.pullImport) - // During a pullImport the sessionLayer is not used to request the proper stage. - // We don't want a stage with criteria on the variant selection. - stage = UsdStage::Open(rootLayer, mImportData.stageInitialLoadSet()); + if (mArgs.pullImportStage) + stage = mArgs.pullImportStage; else stage = UsdStage::Open(rootLayer, sessionLayer, mImportData.stageInitialLoadSet()); } @@ -153,6 +152,7 @@ bool UsdMaya_ReadJob::Read(std::vector* addedDagPaths) return false; } + UsdEditContext editContext(stage, stage->GetSessionLayer()); stage->SetEditTarget(stage->GetSessionLayer()); _setTimeSampleMultiplierFrom(stage->GetTimeCodesPerSecond()); diff --git a/lib/mayaUsd/fileio/primUpdaterManager.cpp b/lib/mayaUsd/fileio/primUpdaterManager.cpp index 94da769ce6..fc63aba23c 100644 --- a/lib/mayaUsd/fileio/primUpdaterManager.cpp +++ b/lib/mayaUsd/fileio/primUpdaterManager.cpp @@ -272,7 +272,7 @@ PullImportPaths pullImport( VtDictionary userArgs(context.GetUserArgs()); - userArgs[UsdMayaJobImportArgsTokens->pullImport] = true; + userArgs[UsdMayaJobImportArgsTokens->pullImportStage] = PXR_NS::VtValue(context.GetUsdStage()); UsdMayaJobImportArgs jobArgs = UsdMayaJobImportArgs::CreateFromDictionary( userArgs, From f945a9748b52a9ae00e8b356ddf58fb87055c6f6 Mon Sep 17 00:00:00 2001 From: Yves Boudreault Date: Mon, 4 Apr 2022 13:22:43 -0400 Subject: [PATCH 2/4] Merged conflict fix. + clang-format fixes --- lib/mayaUsd/fileio/jobs/jobArgs.cpp | 2 +- lib/mayaUsd/fileio/jobs/jobArgs.h | 14 +++++++------- lib/mayaUsd/fileio/primUpdaterManager.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/mayaUsd/fileio/jobs/jobArgs.cpp b/lib/mayaUsd/fileio/jobs/jobArgs.cpp index 7bbcd31ad9..4aada58929 100644 --- a/lib/mayaUsd/fileio/jobs/jobArgs.cpp +++ b/lib/mayaUsd/fileio/jobs/jobArgs.cpp @@ -100,7 +100,7 @@ UsdStageRefPtr _UsdStageRefPtr(const VtDictionary& userArgs, const TfToken& key) } return VtDictionaryGet(userArgs, key); } - + /// Extracts a double at \p key from \p userArgs, or defaultValue if it can't extract. double _Double(const VtDictionary& userArgs, const TfToken& key, double defaultValue) { diff --git a/lib/mayaUsd/fileio/jobs/jobArgs.h b/lib/mayaUsd/fileio/jobs/jobArgs.h index b8cf7028d9..4de27a4460 100644 --- a/lib/mayaUsd/fileio/jobs/jobArgs.h +++ b/lib/mayaUsd/fileio/jobs/jobArgs.h @@ -311,13 +311,13 @@ struct UsdMayaJobImportArgs TfToken materialConversion; }; using ShadingModes = std::vector; - ShadingModes shadingModes; // XXX can we make this const? - const TfToken preferredMaterial; - const std::string importUSDZTexturesFilePath; - const bool importUSDZTextures; - const bool importInstances; - const bool useAsAnimationCache; - const bool importWithProxyShapes; + ShadingModes shadingModes; // XXX can we make this const? + const TfToken preferredMaterial; + const std::string importUSDZTexturesFilePath; + const bool importUSDZTextures; + const bool importInstances; + const bool useAsAnimationCache; + const bool importWithProxyShapes; const UsdStageRefPtr pullImportStage; /// The interval over which to import animated data. /// An empty interval (GfInterval::IsEmpty()) means that no diff --git a/lib/mayaUsd/fileio/primUpdaterManager.cpp b/lib/mayaUsd/fileio/primUpdaterManager.cpp index b2c74d307b..a73d2961e5 100644 --- a/lib/mayaUsd/fileio/primUpdaterManager.cpp +++ b/lib/mayaUsd/fileio/primUpdaterManager.cpp @@ -272,7 +272,7 @@ PullImportPaths pullImport( return PullImportPaths(addedDagPaths, pulledUfePaths); } - const VtDictionary& userArgs = context.GetUserArgs(); + VtDictionary userArgs(context.GetUserArgs()); userArgs[UsdMayaJobImportArgsTokens->pullImportStage] = PXR_NS::VtValue(context.GetUsdStage()); UsdMayaJobImportArgs jobArgs = UsdMayaJobImportArgs::CreateFromDictionary( From 4dcf008841b54f250a1bee7b6bcf60741bc3f5e4 Mon Sep 17 00:00:00 2001 From: Yves Boudreault Date: Mon, 4 Apr 2022 14:43:55 -0400 Subject: [PATCH 3/4] Case issue fix. --- lib/mayaUsd/fileio/jobs/readJob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mayaUsd/fileio/jobs/readJob.cpp b/lib/mayaUsd/fileio/jobs/readJob.cpp index 65193722d2..f97d196b38 100644 --- a/lib/mayaUsd/fileio/jobs/readJob.cpp +++ b/lib/mayaUsd/fileio/jobs/readJob.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include From 04b0ef7108393ce87be301c2c2714d0539bac709 Mon Sep 17 00:00:00 2001 From: Yves Boudreault Date: Mon, 11 Apr 2022 12:10:26 -0400 Subject: [PATCH 4/4] Adding test to validate that the current layer is not changed after "Edit as Maya". --- test/lib/mayaUsd/fileio/testEditAsMaya.py | 41 ++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/test/lib/mayaUsd/fileio/testEditAsMaya.py b/test/lib/mayaUsd/fileio/testEditAsMaya.py index 5e79722efa..63ef2f6b7e 100644 --- a/test/lib/mayaUsd/fileio/testEditAsMaya.py +++ b/test/lib/mayaUsd/fileio/testEditAsMaya.py @@ -26,7 +26,7 @@ import mayaUtils import mayaUsd.ufe -from pxr import Usd, UsdGeom, Gf +from pxr import Usd, UsdGeom, Gf, Sdf from maya import cmds from maya import standalone @@ -255,5 +255,44 @@ def testSessionLayer(self): self.assertEqual(prim.GetCustomDataByKey(kPullPrimMetadataKey), None) + + @unittest.skipUnless(ufeFeatureSetVersion() >= 3, 'Test only available in UFE v3 or greater.') + def testTargetLayer(self): + '''Verify that the target layer is not moved after Edit As Maya.''' + + import mayaUsd_createStageWithNewLayer + + proxyShapePathStr = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() + stage = mayaUsd.lib.GetPrim(proxyShapePathStr).GetStage() + rootLayer = stage.GetRootLayer() + + currentLayer = stage.GetEditTarget().GetLayer() + self.assertEqual(currentLayer, rootLayer) # Current layer should be the Anonymous Root Layer + + sessionLayer = stage.GetSessionLayer() + prim = stage.DefinePrim('/A', 'Xform') + + primPathStr = proxyShapePathStr + ',/A' + + self.assertTrue(stage.GetSessionLayer().empty) + + otherLayerId = cmds.mayaUsdLayerEditor(rootLayer.identifier, edit=True, addAnonymous="otherLayer")[0] + otherLayer = Sdf.Layer.Find(otherLayerId) + + stage.SetEditTarget(otherLayer) + + currentLayer = stage.GetEditTarget().GetLayer() + self.assertEqual(currentLayer, otherLayer) # Current layer should be the Other Layer + + with mayaUsd.lib.OpUndoItemList(): + self.assertTrue(mayaUsd.lib.PrimUpdaterManager.canEditAsMaya(primPathStr)) + self.assertTrue(mayaUsd.lib.PrimUpdaterManager.editAsMaya(primPathStr)) + + self.assertFalse(stage.GetSessionLayer().empty) + + currentLayer = stage.GetEditTarget().GetLayer() + self.assertEqual(currentLayer, otherLayer) # Current layer should still be the Other Layer + + if __name__ == '__main__': unittest.main(verbosity=2)