Skip to content

Commit e549a67

Browse files
authored
Merge pull request #4004 from Autodesk/bailp/EMSUSD-1571/add-schemas-to-prims
EMSUSD-1571 Manipulate prim schemas
2 parents a239482 + 93b66a6 commit e549a67

17 files changed

+1236
-0
lines changed

lib/mayaUsd/commands/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ target_sources(${PROJECT_NAME}
1010
editTargetCommand.cpp
1111
layerEditorCommand.cpp
1212
layerEditorWindowCommand.cpp
13+
schemaCommand.cpp
1314
)
1415

1516
set(HEADERS
@@ -21,6 +22,7 @@ set(HEADERS
2122
editTargetCommand.h
2223
layerEditorCommand.h
2324
layerEditorWindowCommand.h
25+
schemaCommand.h
2426
)
2527

2628
if(CMAKE_UFE_V3_FEATURES_AVAILABLE)

lib/mayaUsd/commands/Readme.md

+15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ in this instance for the mayaUsd plug-in.
1919
| EditTargetCommand | mayaUsdEditTarget | Command to set or get the edit target |
2020
| LayerEditorCommand | mayaUsdLayerEditor | Manipulate layers |
2121
| LayerEditorWindowCommand | mayaUsdLayerEditorWindow | Open or manipulate the layer window |
22+
| SchemaCommand | mayaUsdSchema | Manipulate prim schemas |
2223

2324
Each base command class is documented in the following sections.
2425

@@ -632,6 +633,20 @@ The purpose of this command is to set the current edit target.
632633
| `-query` | `-q` | noarg | Retrieve the current edit target |
633634
| `-editTarget` | `-et` | string | The name of the target to set with the `-edit` flag |
634635
636+
## `mayaUsdSchema`
637+
638+
The purpose of this command is to query or apply USD schemas to USD prims.
639+
It takes as its main arguments a list of UFE paths.
640+
641+
### Command Flags
642+
643+
| Long flag | Short flag | Type | Description |
644+
| --------------------------- | ---------- | -------------- | -------------------------------------------- |
645+
| `-appliedSchemas` | `-app` | noarg | Query which schemas the prims have in common |
646+
| `-schema` | `-sch` | string | The schema type name to apply to the prims |
647+
| `-instanceName` | `-in` | string | The instance name for multi-apply schema |
648+
| `-singleApplicationSchemas` | `-sas` | noarg | Query the list of known single-apply schemas |
649+
| `-multiApplicationSchemas` | `-mas` | noarg | Query the list of known multi-apply schemas |
635650
636651
## `LayerEditorCommand`
637652
+324
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
//
2+
// Copyright 2024 Autodesk
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or dataied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#include "schemaCommand.h"
18+
19+
#include <mayaUsd/ufe/Utils.h>
20+
21+
#include <usdUfe/undo/UsdUndoBlock.h>
22+
#include <usdUfe/undo/UsdUndoableItem.h>
23+
#include <usdUfe/utils/schemas.h>
24+
25+
#include <pxr/base/tf/stringUtils.h>
26+
#include <pxr/usd/usd/prim.h>
27+
#include <pxr/usd/usd/stage.h>
28+
29+
#include <maya/MArgDatabase.h>
30+
#include <maya/MArgList.h>
31+
#include <maya/MGlobal.h>
32+
#include <maya/MStringArray.h>
33+
#include <maya/MSyntax.h>
34+
#include <ufe/path.h>
35+
#include <ufe/pathString.h>
36+
37+
namespace MAYAUSD_NS_DEF {
38+
39+
////////////////////////////////////////////////////////////////////////////
40+
//
41+
// Error message formatting.
42+
43+
static MString formatMessage(const char* format, const std::string& text)
44+
{
45+
return PXR_NS::TfStringPrintf(format, text.c_str()).c_str();
46+
}
47+
48+
static MString formatMessage(const char* format, PXR_NS::UsdPrim& prim, const std::string& text)
49+
{
50+
return PXR_NS::TfStringPrintf(format, prim.GetPath().GetString().c_str(), text.c_str()).c_str();
51+
}
52+
53+
static std::string formatMessage(const char* format, const Ufe::Path& ufePath)
54+
{
55+
return PXR_NS::TfStringPrintf(format, Ufe::PathString::string(ufePath).c_str());
56+
}
57+
58+
////////////////////////////////////////////////////////////////////////////
59+
//
60+
// Command name and flags.
61+
62+
const char SchemaCommand::commandName[] = "mayaUsdSchema";
63+
64+
static const char kAppliedSchemasFlag[] = "app";
65+
static const char kAppliedSchemasLongFlag[] = "appliedSchemas";
66+
static const char kSchemaFlag[] = "sch";
67+
static const char kSchemaLongFlag[] = "schema";
68+
static const char kInstanceNameFlag[] = "in";
69+
static const char kInstanceNameLongFlag[] = "instanceName";
70+
71+
static const char kSingleApplicationFlag[] = "sas";
72+
static const char kSingleApplicationLongFlag[] = "singleApplicationSchemas";
73+
static const char kMultiApplicationFlag[] = "mas";
74+
static const char kMultiApplicationLongFlag[] = "multiApplicationSchemas";
75+
76+
////////////////////////////////////////////////////////////////////////////
77+
//
78+
// Command data and argument parsing to fill that data.
79+
80+
class SchemaCommand::Data
81+
{
82+
public:
83+
// Parse the Maya argument list and fill the data with it.
84+
MStatus parseArgs(const MArgList& argList);
85+
86+
// Convert the list of UFE paths given to the command to the corresponding USD prims.
87+
std::vector<PXR_NS::UsdPrim> getPrims() const;
88+
89+
// Clears the list of UFE paths given to the command.
90+
// Used to reduce the memory consupmtion once the command has been executed.
91+
void clearPrimPaths() { _primPaths.clear(); }
92+
93+
// Retrieve the schema name or schema instance name given to the command.
94+
const std::string& getSchema() const { return _schema; }
95+
const std::string& getInstanceName() const { return _instanceName; }
96+
97+
// Check if the command is a query or which specific type of query.
98+
bool isQuerying() const { return isQueryingAppliedSchemas() || isQueryingKnownSchemas(); }
99+
bool isQueryingKnownSchemas() const
100+
{
101+
return isQueryingSingleAppSchemas() || isQueryingMultiAppSchemas();
102+
}
103+
bool isQueryingAppliedSchemas() const { return _isQueryingAppliedSchemas; }
104+
bool isQueryingSingleAppSchemas() const { return _singleApplicationSchemas; }
105+
bool isQueryingMultiAppSchemas() const { return _multiApplicationSchemas; }
106+
107+
// Undo and redo data and implementation.
108+
UsdUfe::UsdUndoableItem& getUsdUndoItem() { return _undoData; }
109+
void undo() { _undoData.undo(); }
110+
void redo() { _undoData.redo(); }
111+
112+
private:
113+
void parsePrimPaths(MArgDatabase& argData);
114+
std::string parseStringArg(MArgDatabase& argData, const char* argFlag);
115+
116+
std::vector<Ufe::Path> _primPaths;
117+
bool _isQueryingAppliedSchemas { false };
118+
bool _singleApplicationSchemas { false };
119+
bool _multiApplicationSchemas { false };
120+
std::string _schema;
121+
std::string _instanceName;
122+
123+
UsdUfe::UsdUndoableItem _undoData;
124+
};
125+
126+
MStatus SchemaCommand::Data::parseArgs(const MArgList& argList)
127+
{
128+
MStatus status;
129+
MArgDatabase argData(SchemaCommand::createSyntax(), argList, &status);
130+
if (!status)
131+
return status;
132+
133+
_isQueryingAppliedSchemas = argData.isFlagSet(kAppliedSchemasFlag);
134+
_schema = parseStringArg(argData, kSchemaFlag);
135+
_instanceName = parseStringArg(argData, kInstanceNameFlag);
136+
_singleApplicationSchemas = argData.isFlagSet(kSingleApplicationFlag);
137+
_multiApplicationSchemas = argData.isFlagSet(kMultiApplicationFlag);
138+
139+
parsePrimPaths(argData);
140+
141+
return status;
142+
}
143+
144+
std::string SchemaCommand::Data::parseStringArg(MArgDatabase& argData, const char* argFlag)
145+
{
146+
if (!argData.isFlagSet(argFlag))
147+
return {};
148+
149+
MString stringVal;
150+
argData.getFlagArgument(argFlag, 0, stringVal);
151+
return stringVal.asChar();
152+
}
153+
154+
void SchemaCommand::Data::parsePrimPaths(MArgDatabase& argData)
155+
{
156+
_primPaths.clear();
157+
158+
MStringArray ufePathArray;
159+
argData.getObjects(ufePathArray);
160+
const unsigned int pathCount = ufePathArray.length();
161+
for (unsigned int index = 0; index < pathCount; ++index) {
162+
const std::string arg = ufePathArray[index].asChar();
163+
if (arg.size() <= 0)
164+
continue;
165+
_primPaths.push_back(Ufe::PathString::path(arg));
166+
}
167+
}
168+
169+
std::vector<PXR_NS::UsdPrim> SchemaCommand::Data::getPrims() const
170+
{
171+
std::vector<PXR_NS::UsdPrim> prims;
172+
173+
for (const Ufe::Path& ufePath : _primPaths) {
174+
PXR_NS::UsdPrim prim = ufe::ufePathToPrim(ufePath);
175+
if (!prim)
176+
throw std::runtime_error(formatMessage("Prim path \"%s\" is invalid", ufePath));
177+
prims.push_back(prim);
178+
}
179+
180+
return prims;
181+
}
182+
183+
////////////////////////////////////////////////////////////////////////////
184+
//
185+
// Command creation and syntax.
186+
187+
void* SchemaCommand::creator() { return static_cast<MPxCommand*>(new SchemaCommand()); }
188+
189+
SchemaCommand::SchemaCommand()
190+
: _data(std::make_unique<SchemaCommand::Data>())
191+
{
192+
}
193+
194+
MSyntax SchemaCommand::createSyntax()
195+
{
196+
MSyntax syntax;
197+
198+
syntax.setObjectType(MSyntax::kStringObjects);
199+
200+
syntax.addFlag(kAppliedSchemasFlag, kAppliedSchemasLongFlag);
201+
202+
syntax.addFlag(kSchemaFlag, kSchemaLongFlag, MSyntax::kString);
203+
syntax.addFlag(kInstanceNameFlag, kInstanceNameLongFlag, MSyntax::kString);
204+
205+
syntax.addFlag(kSingleApplicationFlag, kSingleApplicationLongFlag);
206+
syntax.addFlag(kMultiApplicationFlag, kMultiApplicationLongFlag);
207+
208+
return syntax;
209+
}
210+
211+
bool SchemaCommand::isUndoable() const { return !_data->isQuerying(); }
212+
213+
////////////////////////////////////////////////////////////////////////////
214+
//
215+
// Command execution.
216+
217+
MStatus SchemaCommand::handleAppliedSchemas()
218+
{
219+
std::set<PXR_NS::TfToken> allSchemas = UsdUfe::getPrimsAppliedSchemas(_data->getPrims());
220+
221+
MStringArray results;
222+
for (const PXR_NS::TfToken& schema : allSchemas)
223+
results.append(schema.GetString().c_str());
224+
setResult(results);
225+
226+
return MS::kSuccess;
227+
}
228+
229+
MStatus SchemaCommand::handleKnownSchemas()
230+
{
231+
const UsdUfe::KnownSchemas knownSchemas = UsdUfe::getKnownApplicableSchemas();
232+
233+
for (const auto& schema : knownSchemas) {
234+
const bool shouldAppend = schema.second.isMultiApply ? _data->isQueryingMultiAppSchemas()
235+
: _data->isQueryingSingleAppSchemas();
236+
if (shouldAppend)
237+
appendToResult(schema.second.schemaTypeName.GetString().c_str());
238+
}
239+
240+
return MS::kSuccess;
241+
}
242+
243+
MStatus SchemaCommand::handleApplySchema()
244+
{
245+
UsdUfe::UsdUndoBlock undoBlock(&_data->getUsdUndoItem());
246+
247+
const std::string& schemaName = _data->getSchema();
248+
if (schemaName.empty()) {
249+
displayError("No schema given to apply to the prims");
250+
return MS::kInvalidParameter;
251+
}
252+
253+
auto maybeInfo = UsdUfe::findSchemasByTypeName(PXR_NS::TfToken(schemaName));
254+
if (!maybeInfo) {
255+
displayError(formatMessage("Cannot find the schema for the type named \"%s\"", schemaName));
256+
return MS::kInvalidParameter;
257+
}
258+
259+
const PXR_NS::TfType& schemaType = maybeInfo->schemaType;
260+
261+
if (maybeInfo->isMultiApply) {
262+
if (_data->getInstanceName().empty()) {
263+
displayError(formatMessage(
264+
"No schema instance name given for the \"%s\" multi-apply schema", schemaName));
265+
return MS::kInvalidParameter;
266+
}
267+
268+
for (PXR_NS::UsdPrim& prim : _data->getPrims()) {
269+
if (!UsdUfe::applyMultiSchemaToPrim(
270+
prim, schemaType, PXR_NS::TfToken(_data->getInstanceName()))) {
271+
displayWarning(
272+
formatMessage("Could no apply schema \"%s\" to prim \"%s\"", prim, schemaName));
273+
}
274+
}
275+
} else {
276+
for (PXR_NS::UsdPrim& prim : _data->getPrims()) {
277+
if (!UsdUfe::applySchemaToPrim(prim, schemaType)) {
278+
displayWarning(
279+
formatMessage("Could no apply schema \"%s\" to prim \"%s\"", prim, schemaName));
280+
}
281+
}
282+
}
283+
284+
_data->clearPrimPaths();
285+
286+
return MS::kSuccess;
287+
}
288+
289+
MStatus SchemaCommand::doIt(const MArgList& argList)
290+
{
291+
try {
292+
setCommandString(commandName);
293+
clearResult();
294+
295+
MStatus status = _data->parseArgs(argList);
296+
if (!status)
297+
return status;
298+
299+
if (_data->isQueryingAppliedSchemas())
300+
return handleAppliedSchemas();
301+
302+
if (_data->isQueryingKnownSchemas())
303+
return handleKnownSchemas();
304+
305+
return handleApplySchema();
306+
} catch (const std::exception& exc) {
307+
displayError(exc.what());
308+
return MS::kFailure;
309+
}
310+
}
311+
312+
MStatus SchemaCommand::redoIt()
313+
{
314+
_data->redo();
315+
return MS::kSuccess;
316+
}
317+
318+
MStatus SchemaCommand::undoIt()
319+
{
320+
_data->undo();
321+
return MS::kSuccess;
322+
}
323+
324+
} // namespace MAYAUSD_NS_DEF

0 commit comments

Comments
 (0)