-
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.
Add new UFE helper functions: - Add the getKnownSchemas helper function to retrieve all known schemas. - Schemas are categorized by single and multi apply. - Schemas are described by their plugin name and schema type name. - Add the applySchemaToPrim and applyMultiSchemaToPrim helper functions. - Add a getPrimAppliedSchemas helper function to retrieve the applied schemas of a prim. - Add a getPrimsAppliedSchemas helper function to get all schemas of a set of prims. - Add a findSchemasByTypeName helper function to find a schema. - Expose the helper functions to Python. Add unit tests: - Add a unit test to verify the schemas helper function. - Add unit tests for the schema application. Add a command to manipulate prim schemas: - Add a mayaUsdSchema command. - Add undo/redo support to the schema command. - Document the mayaUsdSchema command and its flags in the Readme.md. - The -ufe flag to specify the prim UFE paths. - The -app (-appliedSchemas) flag to retrieve the already applied schemas. - The -sch (-schema) flag to specify which schema to add to the prims. - The -in (-instanceName) flag to specify the instance name of a multi-apply schema. - The -sas (-singleApplicationSchemas) flag to retrieve the list of known single-apply schemas. - The -mas (-multiApplicationSchemas) flag tto retrieve the list of known multi-apply schemas. - Add unit tests for the schema command. - Work around the bug in Maya 2022 Linux regarding parsing multi-use flags in commands executed from Python. Add schemas menu: - Add a "Add Schema" menu item in the AE "Attributes" menu. - Create sub-item for each schema, organized by plugin. - Cleanup and prettify the plugin and schema names. - Sort plugin and schema names to have consistent menu item order. - Ask the user for the multi-apply schema instance name. - Adjust callback metadata to have a nice undo entry name.
- Loading branch information
1 parent
56d2b24
commit 98018a9
Showing
17 changed files
with
1,239 additions
and
0 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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,332 @@ | ||
// | ||
// Copyright 2024 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 dataied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
#include "schemaCommand.h" | ||
|
||
#include <mayaUsd/ufe/Utils.h> | ||
|
||
#include <usdUfe/undo/UsdUndoBlock.h> | ||
#include <usdUfe/undo/UsdUndoableItem.h> | ||
#include <usdUfe/utils/schemas.h> | ||
|
||
#include <pxr/base/tf/stringUtils.h> | ||
#include <pxr/usd/usd/prim.h> | ||
#include <pxr/usd/usd/stage.h> | ||
|
||
#include <maya/MArgDatabase.h> | ||
#include <maya/MArgList.h> | ||
#include <maya/MGlobal.h> | ||
#include <maya/MStringArray.h> | ||
#include <maya/MSyntax.h> | ||
#include <ufe/path.h> | ||
#include <ufe/pathString.h> | ||
|
||
namespace MAYAUSD_NS_DEF { | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// | ||
// Error message formatting. | ||
|
||
static MString formatMessage(const char* format, const std::string& text) | ||
{ | ||
return PXR_NS::TfStringPrintf(format, text.c_str()).c_str(); | ||
} | ||
|
||
static MString formatMessage(const char* format, PXR_NS::UsdPrim& prim, const std::string& text) | ||
{ | ||
return PXR_NS::TfStringPrintf(format, prim.GetPath().GetString().c_str(), text.c_str()).c_str(); | ||
} | ||
|
||
static std::string formatMessage(const char* format, const Ufe::Path& ufePath) | ||
{ | ||
return PXR_NS::TfStringPrintf(format, Ufe::PathString::string(ufePath).c_str()); | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// | ||
// Command name and flags. | ||
|
||
const char SchemaCommand::commandName[] = "mayaUsdSchema"; | ||
|
||
static const char kPrimUfePathsFlag[] = "ufe"; | ||
static const char kPrimUfePathsLongFlag[] = "primUfePath"; | ||
static const char kAppliedSchemasFlag[] = "app"; | ||
static const char kAppliedSchemasLongFlag[] = "appliedSchemas"; | ||
static const char kSchemaFlag[] = "sch"; | ||
static const char kSchemaLongFlag[] = "schema"; | ||
static const char kInstanceNameFlag[] = "in"; | ||
static const char kInstanceNameLongFlag[] = "instanceName"; | ||
|
||
static const char kSingleApplicationFlag[] = "sas"; | ||
static const char kSingleApplicationLongFlag[] = "singleApplicationSchemas"; | ||
static const char kMultiApplicationFlag[] = "mas"; | ||
static const char kMultiApplicationLongFlag[] = "multiApplicationSchemas"; | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// | ||
// Command data and argument parsing to fill that data. | ||
|
||
class SchemaCommand::Data | ||
{ | ||
public: | ||
// Parse the Maya argument list and fill the data with it. | ||
MStatus parseArgs(const MArgList& argList); | ||
|
||
// Convert the list of UFE paths given to the command to the corresponding USD prims. | ||
std::vector<PXR_NS::UsdPrim> getPrims() const; | ||
|
||
// Clears the list of UFE paths given to the command. | ||
// Used to reduce the memory consupmtion once the command has been executed. | ||
void clearPrimPaths() { _primPaths.clear(); } | ||
|
||
// Retrieve the schema name or schema instance name given to the command. | ||
const std::string& getSchema() const { return _schema; } | ||
const std::string& getInstanceName() const { return _instanceName; } | ||
|
||
// Check if the command is a query or which specific type of query. | ||
bool isQuerying() const { return isQueryingAppliedSchemas() || isQueryingKnownSchemas(); } | ||
bool isQueryingKnownSchemas() const | ||
{ | ||
return isQueryingSingleAppSchemas() || isQueryingMultiAppSchemas(); | ||
} | ||
bool isQueryingAppliedSchemas() const { return _isQueryingAppliedSchemas; } | ||
bool isQueryingSingleAppSchemas() const { return _singleApplicationSchemas; } | ||
bool isQueryingMultiAppSchemas() const { return _multiApplicationSchemas; } | ||
|
||
// Undo and redo data and implementation. | ||
UsdUfe::UsdUndoableItem& getUsdUndoItem() { return _undoData; } | ||
void undo() { _undoData.undo(); } | ||
void redo() { _undoData.redo(); } | ||
|
||
private: | ||
void parsePrimPaths(const MArgDatabase& argData); | ||
std::string parseStringArg(const MArgDatabase& argData, const char* argFlag); | ||
|
||
std::vector<Ufe::Path> _primPaths; | ||
bool _isQueryingAppliedSchemas { false }; | ||
bool _singleApplicationSchemas { false }; | ||
bool _multiApplicationSchemas { false }; | ||
std::string _schema; | ||
std::string _instanceName; | ||
|
||
UsdUfe::UsdUndoableItem _undoData; | ||
}; | ||
|
||
MStatus SchemaCommand::Data::parseArgs(const MArgList& argList) | ||
{ | ||
MStatus status; | ||
MArgDatabase argData(SchemaCommand::createSyntax(), argList, &status); | ||
if (!status) | ||
return status; | ||
|
||
_isQueryingAppliedSchemas = argData.isFlagSet(kAppliedSchemasFlag); | ||
_schema = parseStringArg(argData, kSchemaFlag); | ||
_instanceName = parseStringArg(argData, kInstanceNameFlag); | ||
_singleApplicationSchemas = argData.isFlagSet(kSingleApplicationFlag); | ||
_multiApplicationSchemas = argData.isFlagSet(kMultiApplicationFlag); | ||
|
||
parsePrimPaths(argData); | ||
|
||
return status; | ||
} | ||
|
||
std::string SchemaCommand::Data::parseStringArg(const MArgDatabase& argData, const char* argFlag) | ||
{ | ||
if (!argData.isFlagSet(argFlag)) | ||
return {}; | ||
|
||
MString stringVal; | ||
argData.getFlagArgument(argFlag, 0, stringVal); | ||
return stringVal.asChar(); | ||
} | ||
|
||
void SchemaCommand::Data::parsePrimPaths(const MArgDatabase& argData) | ||
{ | ||
_primPaths.clear(); | ||
|
||
const unsigned int flagCount = argData.numberOfFlagUses(kPrimUfePathsLongFlag); | ||
for (unsigned int flagIndex = 0; flagIndex < flagCount; ++flagIndex) { | ||
MArgList argList; | ||
argData.getFlagArgumentList(kPrimUfePathsLongFlag, flagIndex, argList); | ||
const unsigned int argCount = argList.length(); | ||
for (unsigned int argIndex = 0; argIndex < argCount; ++argIndex) { | ||
const std::string arg = argList.asString(argIndex).asChar(); | ||
if (arg.size() <= 0) | ||
continue; | ||
_primPaths.push_back(Ufe::PathString::path(arg)); | ||
} | ||
} | ||
} | ||
|
||
std::vector<PXR_NS::UsdPrim> SchemaCommand::Data::getPrims() const | ||
{ | ||
std::vector<PXR_NS::UsdPrim> prims; | ||
|
||
for (const Ufe::Path& ufePath : _primPaths) { | ||
PXR_NS::UsdPrim prim = ufe::ufePathToPrim(ufePath); | ||
if (!prim) | ||
throw std::runtime_error(formatMessage("Prim path \"%s\" is invalid", ufePath)); | ||
prims.push_back(prim); | ||
} | ||
|
||
return prims; | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// | ||
// Command creation and syntax. | ||
|
||
void* SchemaCommand::creator() { return static_cast<MPxCommand*>(new SchemaCommand()); } | ||
|
||
SchemaCommand::SchemaCommand() | ||
: _data(std::make_unique<SchemaCommand::Data>()) | ||
{ | ||
} | ||
|
||
MSyntax SchemaCommand::createSyntax() | ||
{ | ||
MSyntax syntax; | ||
|
||
syntax.setObjectType(MSyntax::kNone, 0, 0); | ||
|
||
syntax.addFlag(kPrimUfePathsFlag, kPrimUfePathsLongFlag, MSyntax::kString); | ||
syntax.makeFlagMultiUse(kPrimUfePathsFlag); | ||
|
||
syntax.addFlag(kAppliedSchemasFlag, kAppliedSchemasLongFlag); | ||
|
||
syntax.addFlag(kSchemaFlag, kSchemaLongFlag, MSyntax::kString); | ||
syntax.addFlag(kInstanceNameFlag, kInstanceNameLongFlag, MSyntax::kString); | ||
|
||
syntax.addFlag(kSingleApplicationFlag, kSingleApplicationLongFlag); | ||
syntax.addFlag(kMultiApplicationFlag, kMultiApplicationLongFlag); | ||
|
||
return syntax; | ||
} | ||
|
||
bool SchemaCommand::isUndoable() const { return !_data->isQuerying(); } | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// | ||
// Command execution. | ||
|
||
MStatus SchemaCommand::handleAppliedSchemas() | ||
{ | ||
std::set<PXR_NS::TfToken> allSchemas = UsdUfe::getPrimsAppliedSchemas(_data->getPrims()); | ||
|
||
MStringArray results; | ||
for (const PXR_NS::TfToken& schema : allSchemas) | ||
results.append(schema.GetString().c_str()); | ||
setResult(results); | ||
|
||
return MS::kSuccess; | ||
} | ||
|
||
MStatus SchemaCommand::handleKnownSchemas() | ||
{ | ||
const UsdUfe::KnownSchemas knownSchemas = UsdUfe::getKnownApplicableSchemas(); | ||
|
||
for (const auto& schema : knownSchemas) { | ||
const bool shouldAppend = schema.second.isMultiApply ? _data->isQueryingMultiAppSchemas() | ||
: _data->isQueryingSingleAppSchemas(); | ||
if (shouldAppend) | ||
appendToResult(schema.second.schemaTypeName.GetString().c_str()); | ||
} | ||
|
||
return MS::kSuccess; | ||
} | ||
|
||
MStatus SchemaCommand::handleApplySchema() | ||
{ | ||
UsdUfe::UsdUndoBlock undoBlock(&_data->getUsdUndoItem()); | ||
|
||
const std::string& schemaName = _data->getSchema(); | ||
if (schemaName.empty()) { | ||
displayError("No schema given to apply to the prims"); | ||
return MS::kInvalidParameter; | ||
} | ||
|
||
auto maybeInfo = UsdUfe::findSchemasByTypeName(PXR_NS::TfToken(schemaName)); | ||
if (!maybeInfo) { | ||
displayError(formatMessage("Cannot find the schema for the type named \"%s\"", schemaName)); | ||
return MS::kInvalidParameter; | ||
} | ||
|
||
const PXR_NS::TfType& schemaType = maybeInfo->schemaType; | ||
|
||
if (maybeInfo->isMultiApply) { | ||
if (_data->getInstanceName().empty()) { | ||
displayError(formatMessage( | ||
"No schema instance name given for the \"%s\" multi-apply schema", schemaName)); | ||
return MS::kInvalidParameter; | ||
} | ||
|
||
for (PXR_NS::UsdPrim& prim : _data->getPrims()) { | ||
if (!UsdUfe::applyMultiSchemaToPrim( | ||
prim, schemaType, PXR_NS::TfToken(_data->getInstanceName()))) { | ||
displayWarning( | ||
formatMessage("Could no apply schema \"%s\" to prim \"%s\"", prim, schemaName)); | ||
} | ||
} | ||
} else { | ||
for (PXR_NS::UsdPrim& prim : _data->getPrims()) { | ||
if (!UsdUfe::applySchemaToPrim(prim, schemaType)) { | ||
displayWarning( | ||
formatMessage("Could no apply schema \"%s\" to prim \"%s\"", prim, schemaName)); | ||
} | ||
} | ||
} | ||
|
||
_data->clearPrimPaths(); | ||
|
||
return MS::kSuccess; | ||
} | ||
|
||
MStatus SchemaCommand::doIt(const MArgList& argList) | ||
{ | ||
try { | ||
setCommandString(commandName); | ||
clearResult(); | ||
|
||
MStatus status = _data->parseArgs(argList); | ||
if (!status) | ||
return status; | ||
|
||
if (_data->isQueryingAppliedSchemas()) | ||
return handleAppliedSchemas(); | ||
|
||
if (_data->isQueryingKnownSchemas()) | ||
return handleKnownSchemas(); | ||
|
||
return handleApplySchema(); | ||
} catch (const std::exception& exc) { | ||
displayError(exc.what()); | ||
return MS::kFailure; | ||
} | ||
} | ||
|
||
MStatus SchemaCommand::redoIt() | ||
{ | ||
_data->redo(); | ||
return MS::kSuccess; | ||
} | ||
|
||
MStatus SchemaCommand::undoIt() | ||
{ | ||
_data->undo(); | ||
return MS::kSuccess; | ||
} | ||
|
||
} // namespace MAYAUSD_NS_DEF |
Oops, something went wrong.