-
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.
Merge pull request #4004 from Autodesk/bailp/EMSUSD-1571/add-schemas-…
…to-prims EMSUSD-1571 Manipulate prim schemas
- Loading branch information
Showing
17 changed files
with
1,236 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,324 @@ | ||
// | ||
// 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 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(MArgDatabase& argData); | ||
std::string parseStringArg(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(MArgDatabase& argData, const char* argFlag) | ||
{ | ||
if (!argData.isFlagSet(argFlag)) | ||
return {}; | ||
|
||
MString stringVal; | ||
argData.getFlagArgument(argFlag, 0, stringVal); | ||
return stringVal.asChar(); | ||
} | ||
|
||
void SchemaCommand::Data::parsePrimPaths(MArgDatabase& argData) | ||
{ | ||
_primPaths.clear(); | ||
|
||
MStringArray ufePathArray; | ||
argData.getObjects(ufePathArray); | ||
const unsigned int pathCount = ufePathArray.length(); | ||
for (unsigned int index = 0; index < pathCount; ++index) { | ||
const std::string arg = ufePathArray[index].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::kStringObjects); | ||
|
||
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.