-
Notifications
You must be signed in to change notification settings - Fork 214
Integrate the component manager #4386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
80eecf6
c53d685
8cb1555
50a6589
b30d7d3
602dbec
1ef409f
a33ee6a
3ad2d39
f2fa343
534d184
87da45d
df85d8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| // | ||
| // Copyright 2025 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/utilComponentCreator.h> | ||
|
|
||
| #include <pxr/base/tf/diagnostic.h> | ||
| #include <pxr/pxr.h> | ||
|
|
||
| #include <maya/MGlobal.h> | ||
| #include <maya/MString.h> | ||
|
|
||
| #include <vector> | ||
|
|
||
| PXR_NAMESPACE_USING_DIRECTIVE | ||
|
|
||
| namespace MAYAUSD_NS_DEF { | ||
| namespace ComponentUtils { | ||
|
|
||
| std::vector<std::string> getAdskUsdComponentLayersToSave(const std::string& proxyPath) | ||
| { | ||
| // Ask via python what layers need to be saved for the component. | ||
| // With the maya api we can only return a string, so we concat the ids. | ||
| MString getLayersFromComponent; | ||
| getLayersFromComponent.format( | ||
| "def usd_component_creator_get_layers_to_save():\n" | ||
| " import mayaUsd\n" | ||
| " import mayaUsd.ufe\n" | ||
| " from usd_component_creator_plugin import MayaComponentManager\n" | ||
| " stage = mayaUsd.ufe.getStage('^1s')\n" | ||
| " if stage is None:\n" | ||
| " return ''\n" | ||
| " ids = MayaComponentManager.GetInstance().GetSaveInfo(stage)\n" | ||
| " result = ''\n" | ||
| " first = True\n" | ||
| " for id in ids:\n" | ||
| " if not first:\n" | ||
| " result += '\\n'\n" | ||
| " result += id\n" | ||
| " first = False\n" | ||
| " return result\n", | ||
| proxyPath.c_str()); | ||
|
|
||
| if (MGlobal::executePythonCommand(getLayersFromComponent)) { | ||
| auto resultString = MGlobal::executePythonCommandStringResult( | ||
| "usd_component_creator_get_layers_to_save()"); | ||
| MStringArray layerIds; | ||
| resultString.split('\n', layerIds); | ||
| std::vector<std::string> toSave; | ||
| for (const auto& id : layerIds) { | ||
| toSave.push_back(id.asUTF8()); | ||
| } | ||
| return toSave; | ||
| } | ||
| return {}; | ||
| } | ||
|
|
||
| bool isAdskUsdComponent(const std::string& proxyShapePath) | ||
| { | ||
| MString defineIsComponentCmd; | ||
| defineIsComponentCmd.format( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not for now, but I think we should eventually refactor all those Python functions into a "helper" sub-module of usd_component_creator and avoid redefining and reparsing these functions all the time. (Merged with Anthon's) |
||
| "def usd_component_creator_is_proxy_shape_a_component():\n" | ||
| " from pxr import Sdf, Usd, UsdUtils\n" | ||
| " import mayaUsd\n" | ||
| " import mayaUsd.ufe\n" | ||
| " try:\n" | ||
| " from AdskUsdComponentCreator import ComponentDescription\n" | ||
| " except ImportError:\n" | ||
| " return -1\n" | ||
| " proxyStage = mayaUsd.ufe.getStage('^1s')\n" | ||
| " component_description = ComponentDescription.CreateFromStageMetadata(proxyStage)\n" | ||
| " if component_description:\n" | ||
| " return 1\n" | ||
| " else:\n" | ||
| " return 0", | ||
| proxyShapePath.c_str()); | ||
|
|
||
| int isStageAComponent = 0; | ||
| MStatus success; | ||
| if (MS::kSuccess | ||
| == (success = MGlobal::executePythonCommand(defineIsComponentCmd, false, false))) { | ||
| MString runIsComponentCmd = "usd_component_creator_is_proxy_shape_a_component()"; | ||
| success = MGlobal::executePythonCommand(runIsComponentCmd, isStageAComponent); | ||
| } | ||
|
|
||
| if (success != MS::kSuccess) { | ||
| TF_RUNTIME_ERROR( | ||
| "Error occurred when testing stage '%s' for component.", proxyShapePath.c_str()); | ||
| } | ||
|
|
||
| return isStageAComponent == 1; | ||
| } | ||
|
|
||
| void saveAdskUsdComponent(const std::string& proxyPath) | ||
| { | ||
| MString saveComponent; | ||
| saveComponent.format( | ||
| "from pxr import Sdf, Usd, UsdUtils\n" | ||
| "import mayaUsd\n" | ||
| "import mayaUsd.ufe\n" | ||
| "from usd_component_creator_plugin import MayaComponentManager\n" | ||
| "proxyStage = mayaUsd.ufe.getStage('^1s')\n" | ||
| "MayaComponentManager.GetInstance().SaveComponent(proxyStage)", | ||
| proxyPath.c_str()); | ||
|
|
||
| if (!MGlobal::executePythonCommand(saveComponent)) { | ||
| TF_RUNTIME_ERROR("Error while saving USD component '%s'", proxyPath.c_str()); | ||
| } | ||
| } | ||
|
|
||
| std::string previewSaveAdskUsdComponent( | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code moved from what Anton merged. I just changed double quotes to quotes in the inlined python |
||
| const std::string& saveLocation, | ||
| const std::string& componentName, | ||
| const std::string& proxyPath) | ||
| { | ||
| MString defMoveComponentPreviewCmd; | ||
| defMoveComponentPreviewCmd.format( | ||
| "def usd_component_creator_move_component_preview():\n" | ||
| " import json\n" | ||
| " from pxr import Sdf, Usd, UsdUtils\n" | ||
| " import mayaUsd\n" | ||
| " import mayaUsd.ufe\n" | ||
| " try:\n" | ||
| " from AdskUsdComponentCreator import ComponentDescription, " | ||
| "PreviewMoveComponentHierarchy\n" | ||
| " except ImportError:\n" | ||
| " return None\n" | ||
| " proxyStage = mayaUsd.ufe.getStage('^1s')\n" | ||
| " component_description = " | ||
| " ComponentDescription.CreateFromStageMetadata(proxyStage)\n" | ||
| " if component_description:\n" | ||
| " move_comp_preview = PreviewMoveComponentHierarchy(component_description, '^2s', " | ||
| "'^3s')\n" | ||
| " return json.dumps(move_comp_preview)\n" | ||
| " else:\n" | ||
| " return \"\"", | ||
| proxyPath.c_str(), | ||
| saveLocation.c_str(), | ||
| componentName.c_str()); | ||
|
|
||
| if (MS::kSuccess == MGlobal::executePythonCommand(defMoveComponentPreviewCmd)) { | ||
| MString result; | ||
| MString runComponentMovePreviewCmd = "usd_component_creator_move_component_preview()"; | ||
| if (MS::kSuccess == MGlobal::executePythonCommand(runComponentMovePreviewCmd, result)) { | ||
| return result.asChar(); | ||
| } | ||
| } | ||
| return {}; | ||
| } | ||
|
|
||
| } // namespace ComponentUtils | ||
| } // namespace MAYAUSD_NS_DEF | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // | ||
| // Copyright 2025 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. | ||
| // | ||
|
|
||
| #ifndef MAYAUSD_UTILS_UTILCOMPONENTCREATOR_H | ||
| #define MAYAUSD_UTILS_UTILCOMPONENTCREATOR_H | ||
|
|
||
| #include "mayaUsd/mayaUsd.h" | ||
|
|
||
| #include <mayaUsd/base/api.h> | ||
|
|
||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| namespace MAYAUSD_NS_DEF { | ||
| namespace ComponentUtils { | ||
|
|
||
| /*! \brief Returns whether the proxy shape at the given path identifies an Autodesk USD Component. | ||
| */ | ||
| MAYAUSD_CORE_PUBLIC | ||
| bool isAdskUsdComponent(const std::string& proxyPath); | ||
|
|
||
| /*! \brief Returns the ids of the USD layers that should be saved for the Autodesk USD Component. | ||
| * | ||
| * \note Expects \p proxyPath to be a valid component path. | ||
| */ | ||
| MAYAUSD_CORE_PUBLIC | ||
| std::vector<std::string> getAdskUsdComponentLayersToSave(const std::string& proxyPath); | ||
|
|
||
| /*! \brief Saves the Autodesk USD Component identified by \p proxyPath. | ||
| * | ||
| * \note Expects \p proxyPath to be a valid component path. | ||
| */ | ||
| MAYAUSD_CORE_PUBLIC | ||
| void saveAdskUsdComponent(const std::string& proxyPath); | ||
|
|
||
| /*! \brief Previews the structure of the Autodesk USD Component identified by \p proxyPath, | ||
| * when saved at the given location with the given name. | ||
| * \return Returns the expected component hierarchy, formatted in json. | ||
| */ | ||
| MAYAUSD_CORE_PUBLIC | ||
| std::string previewSaveAdskUsdComponent( | ||
| const std::string& saveLocation, | ||
| const std::string& componentName, | ||
| const std::string& proxyPath); | ||
|
|
||
| } // namespace ComponentUtils | ||
| } // namespace MAYAUSD_NS_DEF | ||
|
|
||
| #endif // MAYAUSD_UTILS_UTILCOMPONENTCREATOR_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,8 @@ | |
| #include "generatedIconButton.h" | ||
| #include "qtUtils.h" | ||
|
|
||
| #include <mayaUsd/utils/utilComponentCreator.h> | ||
|
|
||
| #include <maya/MGlobal.h> | ||
| #include <maya/MString.h> | ||
|
|
||
|
|
@@ -378,70 +380,41 @@ void ComponentSaveDialog::updateTreeView() | |
| std::string saveLocation(_locationEdit->text().toStdString()); | ||
| std::string componentName(_nameEdit->text().toStdString()); | ||
|
|
||
| MString defMoveComponentPreviewCmd; | ||
| defMoveComponentPreviewCmd.format( | ||
| "def usd_component_creator_move_component_preview():\n" | ||
| " import json\n" | ||
| " from pxr import Sdf, Usd, UsdUtils\n" | ||
| " import mayaUsd\n" | ||
| " import mayaUsd.ufe\n" | ||
| " try:\n" | ||
| " from AdskUsdComponentCreator import ComponentDescription, " | ||
| "PreviewMoveComponentHierarchy\n" | ||
| " except ImportError:\n" | ||
| " return None\n" | ||
| " proxyStage = mayaUsd.ufe.getStage(\"^1s\")\n" | ||
| " component_description = " | ||
| " ComponentDescription.CreateFromStageMetadata(proxyStage)\n" | ||
| " if component_description:\n" | ||
| " move_comp_preview = PreviewMoveComponentHierarchy(component_description, \"^2s\", " | ||
| "\"^3s\")\n" | ||
| " return json.dumps(move_comp_preview)\n" | ||
| " else:\n" | ||
| " return \"\"", | ||
| _proxyShapePath.c_str(), | ||
| saveLocation.c_str(), | ||
| componentName.c_str()); | ||
|
|
||
| if (MS::kSuccess == MGlobal::executePythonCommand(defMoveComponentPreviewCmd)) { | ||
| MString result; | ||
| MString runComponentMovePreviewCmd = "usd_component_creator_move_component_preview()"; | ||
| if (MS::kSuccess == MGlobal::executePythonCommand(runComponentMovePreviewCmd, result)) { | ||
| QString jsonStr = QString::fromStdWString(result.asWChar()); | ||
|
|
||
| // Clear existing tree first | ||
| _treeWidget->clear(); | ||
|
|
||
| QStackedWidget* stackedWidget | ||
| = qobject_cast<QStackedWidget*>(_treeScrollArea->widget()); | ||
|
|
||
| QJsonParseError parseError; | ||
| QJsonDocument doc = QJsonDocument::fromJson(jsonStr.toUtf8(), &parseError); | ||
| QJsonObject jsonObj; | ||
| bool hasData = false; | ||
|
|
||
| if (parseError.error == QJsonParseError::NoError && doc.isObject() && !doc.isEmpty()) { | ||
| jsonObj = doc.object(); | ||
| hasData = !jsonObj.isEmpty(); | ||
| } | ||
|
|
||
| if (hasData) { | ||
| // Populate tree view with JSON data and show tree | ||
| populateTreeView(jsonObj); | ||
| if (stackedWidget) { | ||
| stackedWidget->setCurrentIndex(0); | ||
| } | ||
| } else { | ||
| // Show "Nothing to preview" message | ||
| if (stackedWidget) { | ||
| stackedWidget->setCurrentIndex(1); | ||
| } | ||
| } | ||
|
|
||
| // Update last component name | ||
| _lastComponentName = _nameEdit->text(); | ||
| const auto result = MayaUsd::ComponentUtils::previewSaveAdskUsdComponent( | ||
| saveLocation, componentName, _proxyShapePath.c_str()); | ||
|
|
||
| QString jsonStr = QString::fromStdString(result); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No changes starting here. |
||
|
|
||
| // Clear existing tree first | ||
| _treeWidget->clear(); | ||
|
|
||
| QStackedWidget* stackedWidget = qobject_cast<QStackedWidget*>(_treeScrollArea->widget()); | ||
|
|
||
| QJsonParseError parseError; | ||
| QJsonDocument doc = QJsonDocument::fromJson(jsonStr.toUtf8(), &parseError); | ||
| QJsonObject jsonObj; | ||
| bool hasData = false; | ||
|
|
||
| if (parseError.error == QJsonParseError::NoError && doc.isObject() && !doc.isEmpty()) { | ||
| jsonObj = doc.object(); | ||
| hasData = !jsonObj.isEmpty(); | ||
| } | ||
|
|
||
| if (hasData) { | ||
| // Populate tree view with JSON data and show tree | ||
| populateTreeView(jsonObj); | ||
| if (stackedWidget) { | ||
| stackedWidget->setCurrentIndex(0); | ||
| } | ||
| } else { | ||
| // Show "Nothing to preview" message | ||
| if (stackedWidget) { | ||
| stackedWidget->setCurrentIndex(1); | ||
| } | ||
| } | ||
|
|
||
| // Update last component name | ||
| _lastComponentName = _nameEdit->text(); | ||
| } | ||
|
|
||
| void ComponentSaveDialog::onShowMore() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this fail? if so maybe we need to add validation on the evaluation and reporting that error occured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(answer offline) the only thing that can fail is if the CC isnt present or the path isnt a component path - but this function documents expecting a valid component path - and this is made sure of before calling into this one. So any such error would be reported from "above"