Skip to content

Commit

Permalink
Merge pull request #1922 from Autodesk/boudrey/MAYA-112882/editRouter
Browse files Browse the repository at this point in the history
Boudrey/maya 112882/edit router
  • Loading branch information
seando-adsk authored Jan 12, 2022
2 parents 5dd44b1 + c74d89f commit 14b93b8
Show file tree
Hide file tree
Showing 13 changed files with 403 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/mayaUsd/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ target_sources(${PYTHON_TARGET_NAME}
wrapColorSpace.cpp
wrapConverter.cpp
wrapDiagnosticDelegate.cpp
wrapEditRouter.cpp
wrapMeshWriteUtils.cpp
wrapQuery.cpp
wrapReadUtil.cpp
Expand Down
1 change: 1 addition & 0 deletions lib/mayaUsd/python/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ TF_WRAP_MODULE
TF_WRAP(Converter);
TF_WRAP(ConverterArgs);
TF_WRAP(DiagnosticDelegate);
TF_WRAP(EditRouter);
TF_WRAP(MeshWriteUtils);
#ifdef UFE_V3_FEATURES_AVAILABLE
TF_WRAP(PrimUpdater);
Expand Down
77 changes: 77 additions & 0 deletions lib/mayaUsd/python/wrapEditRouter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// Copyright 2021 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 <mayaUsd/utils/editRouter.h>

#include <pxr/base/tf/pyLock.h>

#include <boost/python.hpp>
#include <boost/python/def.hpp>

#include <iostream>

using namespace boost::python;

namespace {

class PyEditRouter : public MayaUsd::EditRouter
{
public:
PyEditRouter(PyObject* pyCallable)
: _pyCb(pyCallable)
{
}

~PyEditRouter() override { }

void operator()(const PXR_NS::VtDictionary& context, PXR_NS::VtDictionary& routingData) override
{
PXR_NS::TfPyLock pyLock;
if (!PyCallable_Check(_pyCb)) {
return;
}
try {
boost::python::object dictObject(routingData);
call<void>(_pyCb, context, dictObject);
boost::python::extract<PXR_NS::VtDictionary> extractedDict(dictObject);
if (extractedDict.check()) {
routingData = extractedDict;
}
} catch (const error_already_set&) {
std::cout << "Python exception raised in call() of Python callback." << std::endl;
PyErr_Print();
}
}

private:
PyObject* _pyCb;
};

} // namespace

void wrapEditRouter()
{
// As per
// https://stackoverflow.com/questions/18889028/a-positive-lambda-what-sorcery-is-this
// the plus (+) sign before the lambda triggers a conversion to a plain old
// function pointer for the lambda, which is required for successful Boost
// Python compilation of the lambda and its argument.

def(
"registerEditRouter", +[](const PXR_NS::TfToken& operation, PyObject* editRouter) {
return MayaUsd::registerEditRouter(
operation, std::make_shared<PyEditRouter>(editRouter));
});
}
7 changes: 7 additions & 0 deletions lib/mayaUsd/ufe/Global.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <mayaUsd/ufe/PulledObjectHierarchyHandler.h>
#include <mayaUsd/ufe/UsdPathMappingHandler.h>
#endif
#include <mayaUsd/utils/editRouter.h>

#include <maya/MSceneMessage.h>
#include <ufe/hierarchyHandler.h>
Expand Down Expand Up @@ -204,6 +205,12 @@ MStatus initialize()
// Register for UFE string to path service using path component separator '/'
UFE_V2(Ufe::PathString::registerPathComponentSeparator(g_USDRtid, '/');)

// Initialize edit router registry with default routers.
auto defaults = editRouterDefaults();
for (const auto& entry : defaults) {
registerEditRouter(entry.first, entry.second);
}

gExitingCbId = MSceneMessage::addCallback(MSceneMessage::kMayaExiting, exitingCallback);

return MS::kSuccess;
Expand Down
13 changes: 6 additions & 7 deletions lib/mayaUsd/ufe/UsdUndoDuplicateCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "private/Utils.h"

#include <mayaUsd/ufe/Utils.h>
#include <mayaUsd/utils/editRouter.h>
#ifdef UFE_V2_FEATURES_AVAILABLE
#include <mayaUsd/undo/UsdUndoBlock.h>
#endif
Expand Down Expand Up @@ -48,6 +49,9 @@ UsdUndoDuplicateCommand::UsdUndoDuplicateCommand(const UsdSceneItem::Ptr& srcIte

auto newName = uniqueChildName(parentPrim, srcPrim.GetName());
_usdDstPath = parentPrim.GetPath().AppendChild(TfToken(newName));

_srcLayer = srcPrim.GetStage()->GetEditTarget().GetLayer();
_dstLayer = getEditRouterLayer(PXR_NS::TfToken("duplicate"), srcPrim);
}

UsdUndoDuplicateCommand::~UsdUndoDuplicateCommand() { }
Expand Down Expand Up @@ -97,8 +101,7 @@ void UsdUndoDuplicateCommand::execute()
}
stage->SetLoadRules(rules);

auto layer = stage->GetEditTarget().GetLayer();
bool retVal = PXR_NS::SdfCopySpec(layer, path, layer, _usdDstPath);
bool retVal = PXR_NS::SdfCopySpec(_srcLayer, path, _dstLayer, _usdDstPath);
TF_VERIFY(
retVal,
"Failed to copy spec data at '%s' to '%s'",
Expand Down Expand Up @@ -144,11 +147,7 @@ bool UsdUndoDuplicateCommand::duplicateUndo()
bool UsdUndoDuplicateCommand::duplicateRedo()
{
auto prim = ufePathToPrim(_ufeSrcPath);
auto layer = prim.GetStage()->GetEditTarget().GetLayer();

bool retVal = SdfCopySpec(layer, prim.GetPath(), layer, _usdDstPath);

return retVal;
return SdfCopySpec(_srcLayer, prim.GetPath(), _dstLayer, _usdDstPath);
}

void UsdUndoDuplicateCommand::undo()
Expand Down
3 changes: 3 additions & 0 deletions lib/mayaUsd/ufe/UsdUndoDuplicateCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class MAYAUSD_CORE_PUBLIC UsdUndoDuplicateCommand : public Ufe::UndoableCommand
Ufe::Path _ufeSrcPath;
PXR_NS::SdfPath _usdDstPath;

PXR_NS::SdfLayerHandle _srcLayer;
PXR_NS::SdfLayerHandle _dstLayer;

}; // UsdUndoDuplicateCommand

} // namespace ufe
Expand Down
4 changes: 2 additions & 2 deletions lib/mayaUsd/ufe/UsdUndoInsertChildCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "private/UfeNotifGuard.h"
#include "private/Utils.h"

#include <mayaUsd/utils/editRouter.h>
#include <mayaUsdUtils/util.h>

#include <pxr/base/tf/token.h>
Expand Down Expand Up @@ -104,8 +105,7 @@ UsdUndoInsertChildCommand::UsdUndoInsertChildCommand(
_usdDstPath = parentPrim.GetPath().AppendChild(TfToken(childName));

_childLayer = childPrim.GetStage()->GetEditTarget().GetLayer();

_parentLayer = parentPrim.GetStage()->GetEditTarget().GetLayer();
_parentLayer = getEditRouterLayer(PXR_NS::TfToken("parent"), parentPrim);
}

UsdUndoInsertChildCommand::~UsdUndoInsertChildCommand() { }
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ target_sources(${PROJECT_NAME}
customLayerData.cpp
diagnosticDelegate.cpp
editability.cpp
editRouter.cpp
query.cpp
plugRegistryHelper.cpp
selectability.cpp
Expand All @@ -27,6 +28,7 @@ set(HEADERS
converter.h
diagnosticDelegate.h
editability.h
editRouter.h
hash.h
query.h
plugRegistryHelper.h
Expand Down
105 changes: 105 additions & 0 deletions lib/mayaUsd/utils/editRouter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// Copyright 2021 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 "editRouter.h"

#include <pxr/base/tf/callContext.h>
#include <pxr/base/tf/diagnosticLite.h>
#include <pxr/base/tf/token.h>
#include <pxr/usd/usd/editContext.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdGeom/gprim.h>

#include <iostream>

namespace {

MayaUsd::EditRouters editRouters;

void editTargetLayer(const PXR_NS::VtDictionary& context, PXR_NS::VtDictionary& routingData)
{
// We expect a prim in the context.
auto found = context.find("prim");
if (found == context.end()) {
return;
}
auto primValue = found->second;
auto prim = primValue.Get<PXR_NS::UsdPrim>();
if (!prim) {
return;
}
auto layer = prim.GetStage()->GetEditTarget().GetLayer();
routingData["layer"] = PXR_NS::VtValue(layer);
}

} // namespace

namespace MAYAUSD_NS_DEF {

EditRouter::~EditRouter() { }

CxxEditRouter::~CxxEditRouter() { }

void CxxEditRouter::operator()(
const PXR_NS::VtDictionary& context,
PXR_NS::VtDictionary& routingData)
{
_cb(context, routingData);
}

EditRouters editRouterDefaults()
{
using namespace PXR_NS;

EditRouters defaultRouters;
TfTokenVector defaultOperations = { TfToken("parent"), TfToken("duplicate") };
for (const auto& o : defaultOperations) {
defaultRouters[o] = std::make_shared<CxxEditRouter>(editTargetLayer);
}
return defaultRouters;
}

void registerEditRouter(const PXR_NS::TfToken& operation, const EditRouter::Ptr& editRouter)
{
editRouters[operation] = editRouter;
}

PXR_NS::SdfLayerHandle
getEditRouterLayer(const PXR_NS::TfToken& operation, const PXR_NS::UsdPrim& prim)
{
auto foundRouter = editRouters.find(operation);
if (foundRouter == editRouters.end())
return nullptr;

auto dstEditRouter = foundRouter->second;
PXR_NS::VtDictionary context;
PXR_NS::VtDictionary routingData;
context["prim"] = PXR_NS::VtValue(prim);
(*dstEditRouter)(context, routingData);
// Try to retrieve the layer from the edit control data.
auto found = routingData.find("layer");
if (found != routingData.end()) {
if (found->second.IsHolding<std::string>()) {
std::string layerName = found->second.Get<std::string>();
PXR_NS::SdfLayerRefPtr layer = prim.GetStage()->GetRootLayer()->Find(layerName);
return layer;
} else if (found->second.IsHolding<PXR_NS::SdfLayerHandle>()) {
return found->second.Get<PXR_NS::SdfLayerHandle>();
}
}
return prim.GetStage()->GetEditTarget().GetLayer();
}

} // namespace MAYAUSD_NS_DEF
81 changes: 81 additions & 0 deletions lib/mayaUsd/utils/editRouter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// Copyright 2021 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 <pxr/base/tf/hashmap.h>
#include <pxr/base/vt/dictionary.h>
#include <pxr/usd/sdf/types.h>
#include <pxr/usd/usd/prim.h>

#include <functional>
#include <memory>

namespace MAYAUSD_NS_DEF {

// An edit router is used to direct USD edits to their destination in the scene
// graph. This may be a layer, a variant, a USD payload file, etc.
class MAYAUSD_CORE_PUBLIC EditRouter
{
public:
typedef std::shared_ptr<EditRouter> Ptr;

virtual ~EditRouter();

// Compute the routing data. The context is immutable, and is input to
// the computation of the routing data. Routing data may be initialized,
// so that acceptable defaults can be left unchanged.
virtual void operator()(const PXR_NS::VtDictionary& context, PXR_NS::VtDictionary& routingData)
= 0;
};

// Wrap an argument edit router callback for storage in the edit router map.
class MAYAUSD_CORE_PUBLIC CxxEditRouter : public EditRouter
{
public:
using EditRouterCb = std::function<
void(const PXR_NS::VtDictionary& context, PXR_NS::VtDictionary& routingData)>;

CxxEditRouter(EditRouterCb cb)
: _cb(cb)
{
}

~CxxEditRouter() override;

void
operator()(const PXR_NS::VtDictionary& context, PXR_NS::VtDictionary& routingData) override;

private:
EditRouterCb _cb;
};

using EditRouters
= PXR_NS::TfHashMap<PXR_NS::TfToken, EditRouter::Ptr, PXR_NS::TfToken::HashFunctor>;

MAYAUSD_CORE_PUBLIC
PXR_NS::SdfLayerHandle
getEditRouterLayer(const PXR_NS::TfToken& operation, const PXR_NS::UsdPrim& prim);

// Register an edit router for the argument operation.
MAYAUSD_CORE_PUBLIC
void registerEditRouter(const PXR_NS::TfToken& operation, const EditRouter::Ptr& editRouter);

// Return built-in default edit routers.
EditRouters editRouterDefaults();

} // namespace MAYAUSD_NS_DEF
Loading

0 comments on commit 14b93b8

Please sign in to comment.