Skip to content

Commit 76fd34a

Browse files
EMSUSD-1039 First pas adding a C++ expot plugin example
C++ example plugins: - Wrote working example of C++ import and export plugin with UI. - Add C++ plugin example code and CMake files. - Add way to find the C++ plugin via MAYA_PLUG_IN_PATH, finding it as a Maya plugin. - Add way to find the C++ plugin via MAYA_PXR_PLUGINPATH_NAME, finding ist as a USD plugin. Python example plugins: - Change Python plugin JSON to load both plugin. Seems USD does not like having more than one Python plugin in a single JSON. - Overlay the forced settings over the given settings in the Python example. - Catch exception when accessing a settings that may not exists in Python. - The Python import plugin example use MEL-style UI creation. Documentation: - Write documentation about the C++ import and export plugins. - Add link to C++ doc from main doc. - Document that we recommend not forcing existing settings unless specific values are required. Code fixes: - Add a macro to register the import plugin UI. - Fix registry code to not lose the export info when adding the import info and vis--versa. - Fix import job dictionary decoding to use the correct guiding dictionary. - Fix typos in the example Python plugins. - Allow not reporting errors when converting text to VtDictionary when a value is not known to the guiding dictionary. Helper functions for the C++ example plugins: - Add a helper function to convert a VtDictionary to JsObject. - Add helper function to create UI to simplify and clarify the C++ example plugins. - Put all helper functions into a Helpers namespace to make clear where the function come from in the C++ example plugins.
1 parent cfe8396 commit 76fd34a

29 files changed

+1423
-137
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,11 @@ endif()
252252
#------------------------------------------------------------------------------
253253
add_subdirectory(lib)
254254

255+
#------------------------------------------------------------------------------
256+
# tutorials
257+
#------------------------------------------------------------------------------
258+
add_subdirectory(tutorials/import-export-plugin-c++)
259+
255260
#------------------------------------------------------------------------------
256261
# plugins
257262
#------------------------------------------------------------------------------

README_DOC.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
+ [Common Plug-in Base Commands](lib/mayaUsd/commands/Readme.md)
88
+ [Managing Translation (Import/Export) Options](lib/mayaUsd/fileio/doc/Managing_export_options_via_JobContext_in_Python.md)
99
+ [Example Import and Export Plugin in Python](tutorials/import-export-plugin/README.md)
10+
+ [Example Import and Export Plugin in C++](tutorials/import-export-plugin-c++/README.md)
1011
+ [SchemaAPI Translators](lib/mayaUsd/fileio/doc/SchemaAPI_Import_Export_in_Python.md)
1112
+ [UFE Transform](lib/mayaUsd/ufe/UsdTransform3d.md)
1213
+ [Undo/Redo Support](lib/mayaUsd/undo/README.md)

lib/mayaUsd/fileio/jobContextRegistry.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,9 @@ void UsdMayaJobContextRegistry::RegisterExportJobContext(
8282
itFound->niceName.GetText());
8383
}
8484
// Fill the export part:
85-
ContextInfo updatedInfo {
86-
key, itFound->niceName, TfToken(description),
87-
enablerFct, itFound->importDescription, itFound->importEnablerCallback
88-
};
85+
ContextInfo updatedInfo(*itFound);
86+
updatedInfo.exportDescription = TfToken(description);
87+
updatedInfo.exportEnablerCallback = enablerFct;
8988
_jobContextReg.erase(updatedInfo);
9089
_jobContextReg.insert(updatedInfo);
9190
} else {
@@ -145,12 +144,9 @@ void UsdMayaJobContextRegistry::RegisterImportJobContext(
145144
itFound->niceName.GetText());
146145
}
147146
// Fill the import part:
148-
ContextInfo updatedInfo { key,
149-
itFound->niceName,
150-
itFound->exportDescription,
151-
itFound->exportEnablerCallback,
152-
TfToken(description),
153-
enablerFct };
147+
ContextInfo updatedInfo(*itFound);
148+
updatedInfo.importDescription = TfToken(description);
149+
updatedInfo.importEnablerCallback = enablerFct;
154150
_jobContextReg.erase(updatedInfo);
155151
_jobContextReg.insert(updatedInfo);
156152
} else {

lib/mayaUsd/fileio/jobContextRegistry.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ class UsdMayaJobContextRegistry : public TfWeakBase
243243
} \
244244
VtDictionary _ImportJobContextEnabler_##name()
245245

246+
#define REGISTER_IMPORT_JOB_CONTEXT_UI_FCT(name) \
247+
static VtDictionary _ImportJobContextUI_##name( \
248+
const TfToken& jobContext, const std::string& parentUIName, const VtDictionary& settings); \
249+
TF_REGISTRY_FUNCTION(UsdMayaJobContextRegistry) \
250+
{ \
251+
UsdMayaJobContextRegistry::GetInstance().SetImportOptionsUI( \
252+
#name, &_ImportJobContextUI_##name); \
253+
} \
254+
VtDictionary _ImportJobContextUI_##name( \
255+
const TfToken& jobContext, const std::string& parentUIName, const VtDictionary& settings)
256+
246257
PXR_NAMESPACE_CLOSE_SCOPE
247258

248259
#endif

lib/mayaUsd/fileio/jobs/jobArgs.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -909,8 +909,15 @@ MStatus UsdMayaJobExportArgs::GetDictionaryFromEncodedOptions(
909909
return MS::kFailure;
910910
}
911911
}
912+
913+
// Note: when round-tripping settings, some extra settings are not part
914+
// of the guiding dictionary. Ignore them.
915+
const static bool reportError = false;
912916
userArgs[argName] = UsdMayaUtil::ParseArgumentValue(
913-
argName, theOption[1].asChar(), UsdMayaJobExportArgs::GetGuideDictionary());
917+
argName,
918+
theOption[1].asChar(),
919+
UsdMayaJobExportArgs::GetGuideDictionary(),
920+
reportError);
914921
}
915922
}
916923
}
@@ -1241,8 +1248,15 @@ MStatus UsdMayaJobImportArgs::GetDictionaryFromEncodedOptions(
12411248
// Note: if some argument needs special handling, do like in the
12421249
// same function in the export version in UsdMayaJobExportArgs
12431250
std::string argName(theOption[0].asChar());
1251+
1252+
// Note: when round-tripping settings, some extra settings are not part
1253+
// of the guiding dictionary. Ignore them.
1254+
const static bool reportError = false;
12441255
userArgs[argName] = UsdMayaUtil::ParseArgumentValue(
1245-
argName, theOption[1].asChar(), UsdMayaJobExportArgs::GetGuideDictionary());
1256+
argName,
1257+
theOption[1].asChar(),
1258+
UsdMayaJobImportArgs::GetGuideDictionary(),
1259+
reportError);
12461260
}
12471261
}
12481262

lib/mayaUsd/utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ set(HEADERS
4747
editability.h
4848
hash.h
4949
json.h
50+
jsonDict.h
5051
layerLocking.h
5152
layerMuting.h
5253
layers.h

lib/mayaUsd/utils/json.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
// limitations under the License.
1515
//
1616

17+
#ifndef MAYAUSD_UTILS_JSON_H
18+
#define MAYAUSD_UTILS_JSON_H
19+
1720
#include <mayaUsd/base/api.h>
1821

1922
#include <pxr/base/js/json.h>
@@ -55,3 +58,5 @@ MAYAUSD_CORE_PUBLIC
5558
PXR_NS::JsValue convertJsonKeyToValue(const PXR_NS::JsObject& object, const std::string& key);
5659

5760
} // namespace MAYAUSD_NS_DEF
61+
62+
#endif

lib/mayaUsd/utils/jsonDict.h

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
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 implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#ifndef MAYAUSD_UTILS_JSON_DICT_H
18+
#define MAYAUSD_UTILS_JSON_DICT_H
19+
20+
#include <mayaUsd/base/api.h>
21+
22+
#include <pxr/base/js/json.h>
23+
#include <pxr/base/vt/dictionary.h>
24+
#include <pxr/base/vt/value.h>
25+
26+
#include <string>
27+
#include <vector>
28+
29+
namespace MAYAUSD_NS_DEF {
30+
31+
////////////////////////////////////////////////////////////////////////////
32+
//
33+
// Convert a VtDictionary to JsValue.
34+
// Modeled after PXR_NS::JsValueTypeConverter
35+
36+
class VtDictionaryToJsValueConverter
37+
{
38+
public:
39+
static PXR_NS::JsObject convertToDictionary(const PXR_NS::VtDictionary& dict)
40+
{
41+
PXR_NS::JsObject object;
42+
43+
for (const auto& keyAndValue : dict) {
44+
PXR_NS::JsValue sub;
45+
if (canConvertToValue(keyAndValue.second, sub))
46+
object[keyAndValue.first] = sub;
47+
}
48+
49+
return object;
50+
}
51+
52+
static bool canConvertToDictionary(const PXR_NS::VtValue& value, PXR_NS::JsValue& into)
53+
{
54+
if (!value.IsHolding<PXR_NS::VtDictionary>())
55+
return false;
56+
57+
into = convertToDictionary(value.UncheckedGet<PXR_NS::VtDictionary>());
58+
return true;
59+
}
60+
61+
static PXR_NS::JsArray convertToArrayOfValues(const std::vector<PXR_NS::VtValue>& vec)
62+
{
63+
PXR_NS::JsArray array;
64+
65+
for (const PXR_NS::VtValue& element : vec) {
66+
PXR_NS::JsValue sub;
67+
if (canConvertToValue(element, sub))
68+
array.push_back(sub);
69+
}
70+
71+
return array;
72+
}
73+
74+
static bool canConvertToArrayOfValues(const PXR_NS::VtValue& value, PXR_NS::JsValue& into)
75+
{
76+
if (!value.IsHolding<std::vector<PXR_NS::VtValue>>())
77+
return false;
78+
79+
into = convertToArrayOfValues(value.UncheckedGet<std::vector<PXR_NS::VtValue>>());
80+
return true;
81+
}
82+
83+
template <typename T, typename TARGET = T>
84+
static PXR_NS::JsArray convertToArrayOf(const std::vector<T>& vec)
85+
{
86+
PXR_NS::JsArray array;
87+
88+
for (auto&& element : vec)
89+
array.push_back(PXR_NS::JsValue(TARGET(element)));
90+
91+
return array;
92+
}
93+
94+
template <typename T, typename TARGET = T>
95+
static bool canConvertToArrayOf(const PXR_NS::VtValue& value, PXR_NS::JsValue& into)
96+
{
97+
if (!value.IsHolding<std::vector<T>>())
98+
return false;
99+
100+
into = convertToArrayOf<T, TARGET>(value.UncheckedGet<std::vector<T>>());
101+
return true;
102+
}
103+
104+
static bool canConvertToArray(const PXR_NS::VtValue& value, PXR_NS::JsValue& into)
105+
{
106+
// Note: we don't support array of boolean becasue they are rare and in
107+
// C++, vector<bool> is specialized and cause problems when iterating
108+
// because the MacOS compiler complain about lost optimization and
109+
// cause the compilation to fail to to warning-as-error compilation
110+
// flag.
111+
// if (canConvertToArrayOf<bool>(value, into))
112+
// return true;
113+
if (canConvertToArrayOf<int>(value, into))
114+
return true;
115+
if (canConvertToArrayOf<unsigned int, int>(value, into))
116+
return true;
117+
if (canConvertToArrayOf<short, int>(value, into))
118+
return true;
119+
if (canConvertToArrayOf<unsigned short, int>(value, into))
120+
return true;
121+
if (canConvertToArrayOf<long, int64_t>(value, into))
122+
return true;
123+
if (canConvertToArrayOf<unsigned long, int64_t>(value, into))
124+
return true;
125+
if (canConvertToArrayOf<int8_t, int>(value, into))
126+
return true;
127+
if (canConvertToArrayOf<uint8_t, int>(value, into))
128+
return true;
129+
if (canConvertToArrayOf<int16_t, int>(value, into))
130+
return true;
131+
if (canConvertToArrayOf<uint16_t, int>(value, into))
132+
return true;
133+
if (canConvertToArrayOf<int32_t, int>(value, into))
134+
return true;
135+
if (canConvertToArrayOf<uint32_t, int>(value, into))
136+
return true;
137+
if (canConvertToArrayOf<int64_t>(value, into))
138+
return true;
139+
if (canConvertToArrayOf<uint64_t, int64_t>(value, into))
140+
return true;
141+
if (canConvertToArrayOf<float>(value, into))
142+
return true;
143+
if (canConvertToArrayOf<double>(value, into))
144+
return true;
145+
if (canConvertToArrayOf<std::string>(value, into))
146+
return true;
147+
if (canConvertToArrayOfValues(value, into))
148+
return true;
149+
150+
// TODO: we don't support arrays or arrays or arrays of dictionaries.
151+
// We never need that for our purpose.
152+
153+
return false;
154+
}
155+
156+
template <typename T, typename TARGET = T>
157+
static bool canConvertTo(const PXR_NS::VtValue& value, PXR_NS::JsValue& into)
158+
{
159+
if (!value.IsHolding<T>())
160+
return false;
161+
into = PXR_NS::JsValue(TARGET(value.UncheckedGet<T>()));
162+
return true;
163+
}
164+
165+
static bool canConvertToValue(const PXR_NS::VtValue& value, PXR_NS::JsValue& into)
166+
{
167+
if (canConvertTo<bool>(value, into))
168+
return true;
169+
if (canConvertTo<int>(value, into))
170+
return true;
171+
if (canConvertTo<unsigned int, int>(value, into))
172+
return true;
173+
if (canConvertTo<short, int>(value, into))
174+
return true;
175+
if (canConvertTo<unsigned short, int>(value, into))
176+
return true;
177+
if (canConvertTo<long, int64_t>(value, into))
178+
return true;
179+
if (canConvertTo<unsigned long, int64_t>(value, into))
180+
return true;
181+
if (canConvertTo<int8_t, int>(value, into))
182+
return true;
183+
if (canConvertTo<uint8_t, int>(value, into))
184+
return true;
185+
if (canConvertTo<int16_t, int>(value, into))
186+
return true;
187+
if (canConvertTo<uint16_t, int>(value, into))
188+
return true;
189+
if (canConvertTo<int32_t, int>(value, into))
190+
return true;
191+
if (canConvertTo<uint32_t, int>(value, into))
192+
return true;
193+
if (canConvertTo<int64_t>(value, into))
194+
return true;
195+
if (canConvertTo<uint64_t, int64_t>(value, into))
196+
return true;
197+
if (canConvertTo<float, double>(value, into))
198+
return true;
199+
if (canConvertTo<double>(value, into))
200+
return true;
201+
if (canConvertTo<std::string>(value, into))
202+
return true;
203+
204+
if (canConvertToDictionary(value, into))
205+
return true;
206+
207+
if (canConvertToArray(value, into))
208+
return true;
209+
210+
return true;
211+
}
212+
};
213+
214+
} // namespace MAYAUSD_NS_DEF
215+
216+
#endif

lib/mayaUsd/utils/util.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,7 +1970,8 @@ VtValue _ParseArgumentValue(const std::string& value, const VtValue& guideValue)
19701970
VtValue UsdMayaUtil::ParseArgumentValue(
19711971
const std::string& key,
19721972
const std::string& value,
1973-
const VtDictionary& guideDict)
1973+
const VtDictionary& guideDict,
1974+
bool reportErrors)
19741975
{
19751976
// We handle two types of arguments:
19761977
// 1 - bools: Should be encoded by translator UI as a "1" or "0" string.
@@ -1982,7 +1983,7 @@ VtValue UsdMayaUtil::ParseArgumentValue(
19821983
if (iter != guideDict.end()) {
19831984
const VtValue& guideValue = iter->second;
19841985
return _ParseArgumentValue(value, guideValue);
1985-
} else {
1986+
} else if (reportErrors) {
19861987
TF_CODING_ERROR("Unknown flag '%s'", key.c_str());
19871988
}
19881989

lib/mayaUsd/utils/util.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,11 @@ GetDictionaryFromArgDatabase(const MArgDatabase& argData, const VtDictionary& gu
527527
/// strings. If you have an MArgList/MArgParser/MArgDatabase, it's going to be
528528
/// way simpler to use GetDictionaryFromArgDatabase() instead.
529529
MAYAUSD_CORE_PUBLIC
530-
VtValue
531-
ParseArgumentValue(const std::string& key, const std::string& value, const VtDictionary& guideDict);
530+
VtValue ParseArgumentValue(
531+
const std::string& key,
532+
const std::string& value,
533+
const VtDictionary& guideDict,
534+
bool reportErrors = true);
532535

533536
/// Converts a value into a string that can be parsed back using ParseArgumentValue.
534537
/// Should be used when generating argument strings that are to be used by translators.

0 commit comments

Comments
 (0)