-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MAYA-129059 - Add command to create stages.
Add an undoable command that creates a stage with a new layer. The new command is a C++ implementation of the existing mayaUsd_createStageWithNewLayer.py Python script. The command enables the creation of stages from within the C++ code, which will be required by future work (MAYA-128151) and might also be generally useful. This commit also adds a Python binding for the stage creation command, which is used in mayaUsd_createStageWithNewLayer.py to replace the current implementation.
- Loading branch information
1 parent
329d37d
commit defb109
Showing
5 changed files
with
330 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
211 changes: 211 additions & 0 deletions
211
lib/mayaUsd/ufe/UsdUndoCreateStageWithNewLayerCommand.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
// | ||
// Copyright 2023 Autodesk | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
#include "UsdUndoCreateStageWithNewLayerCommand.h" | ||
|
||
#include <mayaUsd/ufe/UsdStageMap.h> | ||
#include <mayaUsd/ufe/UsdUndoRenameCommand.h> | ||
#include <mayaUsd/ufe/Utils.h> | ||
#include <mayaUsd/undo/OpUndoItems.h> | ||
|
||
#include <ufe/hierarchy.h> | ||
|
||
PXR_NAMESPACE_USING_DIRECTIVE | ||
|
||
namespace MAYAUSD_NS_DEF { | ||
namespace ufe { | ||
|
||
extern UsdStageMap g_StageMap; | ||
|
||
UsdUndoCreateStageWithNewLayerCommand::UsdUndoCreateStageWithNewLayerCommand( | ||
const Ufe::SceneItem::Ptr& parentItem) | ||
: _parentItem(nullptr) | ||
, _insertedChild(nullptr) | ||
, _createTransformDagMod(MDagModifierUndoItem::create("Create transform")) | ||
, _createProxyShapeDagMod(MDagModifierUndoItem::create("Create Stage with new Layer")) | ||
, _createTransformSuccess(false) | ||
, _createProxyShapeSuccess(false) | ||
{ | ||
if (!TF_VERIFY(parentItem)) | ||
return; | ||
|
||
_parentItem = parentItem; | ||
} | ||
|
||
UsdUndoCreateStageWithNewLayerCommand::~UsdUndoCreateStageWithNewLayerCommand() { } | ||
|
||
UsdUndoCreateStageWithNewLayerCommand::Ptr | ||
UsdUndoCreateStageWithNewLayerCommand::create(const Ufe::SceneItem::Ptr& parentItem) | ||
{ | ||
if (!parentItem) | ||
return nullptr; | ||
|
||
return std::make_shared<UsdUndoCreateStageWithNewLayerCommand>(parentItem); | ||
} | ||
|
||
Ufe::SceneItem::Ptr UsdUndoCreateStageWithNewLayerCommand::sceneItem() const | ||
{ | ||
return _insertedChild; | ||
} | ||
|
||
void UsdUndoCreateStageWithNewLayerCommand::execute() | ||
{ | ||
if (!_parentItem) { | ||
return; | ||
} | ||
|
||
// Get a MObject from the parent scene item. | ||
// Note: If and only if the parent is the world node, MDagPath::transform() will set status to | ||
// kInvalidParameter. In this case MObject::kNullObj is returned, which is a valid parent | ||
// object. Thus, kInvalidParameter will not be treated as a failure. | ||
MStatus status; | ||
MDagPath parentDagPath = MayaUsd::ufe::ufeToDagPath(_parentItem->path()); | ||
MObject parentObject = parentDagPath.transform(&status); | ||
if (status != MStatus::kInvalidParameter && MFAIL(status)) { | ||
return; | ||
} | ||
|
||
// Create a transform node. | ||
// Note: It would be possible to create the transform and the proxy shape in one doIt() call of | ||
// a single MDagModifier. However, doing so causes notifications to be sent in a different | ||
// order, which triggers a `TF_VERIFY(g_StageMap.isDirty())` in StagesSubject::onStageSet(). | ||
// Using a separate MDagModifier to create the transform seems more robust and avoids triggering | ||
// the TF_VERIFY. | ||
MObject transformObj; | ||
transformObj = _createTransformDagMod.createNode("transform", parentObject, &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
TF_VERIFY(!transformObj.isNull()); | ||
status = _createTransformDagMod.doIt(); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
_createTransformSuccess = true; | ||
|
||
// Create a proxy shape. | ||
MObject proxyShape; | ||
proxyShape = _createProxyShapeDagMod.createNode("mayaUsdProxyShape", transformObj, &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
TF_VERIFY(!proxyShape.isNull()); | ||
|
||
// Rename the transform and the proxy shape. | ||
// Note: The transform is renamed twice. The first rename operation renames it from its default | ||
// name "transform1" to "stage1". The number-suffix will be automatically incremented if | ||
// necessary. The second rename operation renames it from "stageX" to "stage1". This doesn't do | ||
// anything for the transform itself but it will adjust the number-suffix of the proxy shape | ||
// according to the suffix of the transform, because they now share the common prefix "stage". | ||
status = _createProxyShapeDagMod.renameNode(proxyShape, "stageShape1"); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
status = _createProxyShapeDagMod.renameNode(transformObj, "stage1"); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
status = _createProxyShapeDagMod.renameNode(transformObj, "stage1"); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
|
||
// Get the global `time1` object and its `outTime` attribute. | ||
MSelectionList selection; | ||
selection.add("time1"); | ||
MObject time1; | ||
status = selection.getDependNode(0, time1); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
MFnDependencyNode time1DepNodeFn(time1, &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
MObject time1OutTimeAttr = time1DepNodeFn.attribute("outTime", &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
|
||
// Get the `time` attribute of the newly created mayaUsdProxyShape. | ||
MDagPath proxyShapeDagPath = MDagPath::getAPathTo(proxyShape, &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
MFnDependencyNode proxyShapeDepNodeFn(proxyShapeDagPath.node(), &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
MObject proxyShapeTimeAttr = proxyShapeDepNodeFn.attribute("time", &status); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
|
||
// Connect `time1.outTime` to `proxyShapde.time`. | ||
status | ||
= _createProxyShapeDagMod.connect(time1, time1OutTimeAttr, proxyShape, proxyShapeTimeAttr); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
|
||
// Execute the operations. | ||
status = _createProxyShapeDagMod.doIt(); | ||
if (MFAIL(status)) { | ||
return; | ||
} | ||
_createProxyShapeSuccess = true; | ||
|
||
// Create a UFE scene item for the newly created mayaUsdProxyShape. | ||
Ufe::Path proxyShapeUfePath = MayaUsd::ufe::dagPathToUfe(proxyShapeDagPath); | ||
_insertedChild = Ufe::Hierarchy::createItem(proxyShapeUfePath); | ||
|
||
// Refresh the cache of the stage map. | ||
// When creating the proxy shape, the stage map gets dirtied and cleaned. Afterwards, the proxy | ||
// shape is renamed. The stage map does not observe the Maya data model, so renaming does not | ||
// dirty the stage map again. Thus, the cache is in an invalid state, where it contains the | ||
// path of the proxy shape before it was renamed. Calling UsdStageMap::proxyShape() refreshes | ||
// the cache. See comments within UsdStageMap::proxyShape() for more details. | ||
g_StageMap.proxyShape(proxyShapeUfePath); | ||
} | ||
|
||
void UsdUndoCreateStageWithNewLayerCommand::undo() | ||
{ | ||
if (_createProxyShapeSuccess) { | ||
_createProxyShapeDagMod.undoIt(); | ||
} | ||
|
||
if (_createTransformSuccess) { | ||
_createTransformDagMod.undoIt(); | ||
} | ||
} | ||
|
||
void UsdUndoCreateStageWithNewLayerCommand::redo() | ||
{ | ||
if (_createTransformSuccess) { | ||
_createTransformDagMod.doIt(); | ||
} | ||
|
||
if (_createProxyShapeSuccess) { | ||
_createProxyShapeDagMod.doIt(); | ||
} | ||
|
||
// Refresh the cache of the stage map. | ||
if (_insertedChild) { | ||
g_StageMap.proxyShape(_insertedChild->path()); | ||
} | ||
} | ||
|
||
} // namespace ufe | ||
} // namespace MAYAUSD_NS_DEF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// | ||
// Copyright 2023 Autodesk | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
#pragma once | ||
|
||
#include <mayaUsd/base/api.h> | ||
|
||
#include <maya/MDagModifier.h> | ||
#include <ufe/undoableCommand.h> | ||
|
||
namespace MAYAUSD_NS_DEF { | ||
namespace ufe { | ||
|
||
//! \brief This command is used to create a new empty stage in memory. | ||
class MAYAUSD_CORE_PUBLIC UsdUndoCreateStageWithNewLayerCommand | ||
: public Ufe::SceneItemResultUndoableCommand | ||
{ | ||
public: | ||
typedef std::shared_ptr<UsdUndoCreateStageWithNewLayerCommand> Ptr; | ||
|
||
UsdUndoCreateStageWithNewLayerCommand(const Ufe::SceneItem::Ptr& parentItem); | ||
~UsdUndoCreateStageWithNewLayerCommand() override; | ||
|
||
// Delete the copy/move constructors assignment operators. | ||
UsdUndoCreateStageWithNewLayerCommand(const UsdUndoCreateStageWithNewLayerCommand&) = delete; | ||
UsdUndoCreateStageWithNewLayerCommand& operator=(const UsdUndoCreateStageWithNewLayerCommand&) | ||
= delete; | ||
UsdUndoCreateStageWithNewLayerCommand(UsdUndoCreateStageWithNewLayerCommand&&) = delete; | ||
UsdUndoCreateStageWithNewLayerCommand& operator=(UsdUndoCreateStageWithNewLayerCommand&&) | ||
= delete; | ||
|
||
//! Create a UsdUndoCreateStageWithNewLayerCommand. Executing this command should produce the | ||
//! following: | ||
//! - Proxyshape | ||
//! - Stage | ||
//! - Session Layer | ||
//! - Anonymous Root Layer (this is set as the target layer) | ||
//! Since the proxy shape does not have a USD file associated (in the .filePath attribute), the | ||
//! proxy shape base will create an empty stage in memory. This will create the session and root | ||
//! layer as well. | ||
static UsdUndoCreateStageWithNewLayerCommand::Ptr create(const Ufe::SceneItem::Ptr& parentItem); | ||
|
||
Ufe::SceneItem::Ptr sceneItem() const override; | ||
|
||
void execute() override; | ||
void undo() override; | ||
void redo() override; | ||
|
||
private: | ||
Ufe::SceneItem::Ptr _parentItem; | ||
Ufe::SceneItem::Ptr _insertedChild; | ||
|
||
MDagModifier& _createTransformDagMod; | ||
MDagModifier& _createProxyShapeDagMod; | ||
bool _createTransformSuccess; | ||
bool _createProxyShapeSuccess; | ||
}; // UsdUndoCreateStageWithNewLayerCommand | ||
|
||
} // namespace ufe | ||
} // namespace MAYAUSD_NS_DEF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters