From 22e80916e328936a8df33002d96111b4465a9636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Francisco=20Fleith?= Date: Thu, 8 Aug 2019 10:25:56 -0300 Subject: [PATCH] Add save material option (#571) * Add save material option * Fix the wrong assignment * Persist uniform changes into the material document * Change the MaterialX document on every edit * Skip stdlib and extra XIncludes * Remove compile warnings * Code review requests * Fix integer enum on properties * Remove compile warnings * Fix compile error: lambda capture 'INVALID_INDEX' is not required --- source/MaterialXRender/Util.cpp | 4 + source/MaterialXTest/RenderUtil.cpp | 54 +++++----- source/MaterialXTest/RenderUtil.h | 4 + source/MaterialXView/Editor.cpp | 161 ++++++++++++---------------- source/MaterialXView/Material.cpp | 94 ++++++++++++++++ source/MaterialXView/Material.h | 21 ++++ source/MaterialXView/Viewer.cpp | 60 +++++++++-- source/MaterialXView/Viewer.h | 3 + 8 files changed, 272 insertions(+), 129 deletions(-) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index b22e0fed3b..9b5fcce2a7 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -93,6 +93,10 @@ unsigned int getUIProperties(ConstValueElementPtr nodeDefElement, UIProperties& { uiProperties.enumerationValues.push_back(Value::createValue(enumerationValues)); } + if(uiProperties.enumeration.size() != uiProperties.enumerationValues.size()) + { + throw std::runtime_error("Every enum must have a value!"); + } propertyCount++; } } diff --git a/source/MaterialXTest/RenderUtil.cpp b/source/MaterialXTest/RenderUtil.cpp index eeadad95bd..7645a55d08 100644 --- a/source/MaterialXTest/RenderUtil.cpp +++ b/source/MaterialXTest/RenderUtil.cpp @@ -78,6 +78,31 @@ void ShaderRenderTester::printRunLog(const RenderProfileTimes &profileTimes, //} } +void ShaderRenderTester::loadDependentLibraries(GenShaderUtil::TestSuiteOptions options, mx::FilePath searchPath, mx::DocumentPtr& dependLib) +{ + dependLib = mx::createDocument(); + + const mx::StringVec libraries = { "stdlib", "pbrlib", "lights" }; + mx::loadLibraries(libraries, searchPath, dependLib, nullptr); + for (size_t i = 0; i < options.externalLibraryPaths.size(); i++) + { + const mx::FilePath& extraPath = options.externalLibraryPaths[i]; + mx::FilePathVec libraryFiles = extraPath.getFilesInDirectory("mtlx"); + for (size_t l = 0; l < libraryFiles.size(); l++) + { + std::cout << "Extra library path: " << (extraPath / libraryFiles[l]).asString() << std::endl; + mx::loadLibrary((extraPath / libraryFiles[l]), dependLib); + } + } + + // Load shader definitions used in the test suite. + loadLibrary(mx::FilePath::getCurrentPath() / mx::FilePath("libraries/bxdf/standard_surface.mtlx"), dependLib); + loadLibrary(mx::FilePath::getCurrentPath() / mx::FilePath("libraries/bxdf/usd_preview_surface.mtlx"), dependLib); + + // Load any addition per validator libraries + loadAdditionalLibraries(dependLib, options); +} + bool ShaderRenderTester::validate(const mx::FilePathVec& testRootPaths, const mx::FilePath optionsFilePath) { // Test has been turned off so just do nothing. @@ -143,36 +168,17 @@ bool ShaderRenderTester::validate(const mx::FilePathVec& testRootPaths, const mx ioTimer.endTimer(); + // Add files to skip + addSkipFiles(); + // Library search path mx::FilePath searchPath = mx::FilePath::getCurrentPath() / mx::FilePath("libraries"); // Load in the library dependencies once // This will be imported in each test document below ioTimer.startTimer(); - mx::DocumentPtr dependLib = mx::createDocument(); - - // Add files to skip - addSkipFiles(); - - const mx::StringVec libraries = { "stdlib", "pbrlib", "lights" }; - mx::loadLibraries(libraries, searchPath, dependLib, nullptr); - for (size_t i = 0; i < options.externalLibraryPaths.size(); i++) - { - const mx::FilePath& extraPath = options.externalLibraryPaths[i]; - mx::FilePathVec libraryFiles = extraPath.getFilesInDirectory("mtlx"); - for (size_t l = 0; l < libraryFiles.size(); l++) - { - std::cout << "Extra library path: " << (extraPath / libraryFiles[l]).asString() << std::endl; - mx::loadLibrary((extraPath / libraryFiles[l]), dependLib); - } - } - - // Load shader definitions used in the test suite. - loadLibrary(mx::FilePath::getCurrentPath() / mx::FilePath("libraries/bxdf/standard_surface.mtlx"), dependLib); - loadLibrary(mx::FilePath::getCurrentPath() / mx::FilePath("libraries/bxdf/usd_preview_surface.mtlx"), dependLib); - - // Load any addition per validator libraries - loadAdditionalLibraries(dependLib, options); + mx::DocumentPtr dependLib; + loadDependentLibraries(options, searchPath, dependLib); ioTimer.endTimer(); // Create validators and generators diff --git a/source/MaterialXTest/RenderUtil.h b/source/MaterialXTest/RenderUtil.h index 54ea58afb7..10debdd6c6 100644 --- a/source/MaterialXTest/RenderUtil.h +++ b/source/MaterialXTest/RenderUtil.h @@ -178,6 +178,10 @@ class ShaderRenderTester _skipFiles.insert("default_viewer_lights.mtlx"); } + // Load dependencies + void loadDependentLibraries(GenShaderUtil::TestSuiteOptions options, mx::FilePath searchPath, + mx::DocumentPtr& dependLib); + // Load any additional libraries requird by the generator virtual void loadAdditionalLibraries(mx::DocumentPtr /*dependLib*/, GenShaderUtil::TestSuiteOptions& /*options*/) {}; diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index 3db8753504..d77ad2b439 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -168,12 +168,7 @@ ng::FloatBox* PropertyEditor::makeFloatWidget(ng::Widget* container, cons MaterialPtr material = viewer->getSelectedMaterial(); if (material) { - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) - { - material->getShader()->bind(); - material->getShader()->setUniform(uniform->getVariable(), value); - } + material->setUniformFloat(path, value); } }); floatVar->setCallback([slider, path, viewer](float value) @@ -182,12 +177,7 @@ ng::FloatBox* PropertyEditor::makeFloatWidget(ng::Widget* container, cons MaterialPtr material = viewer->getSelectedMaterial(); if (material) { - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) - { - material->getShader()->bind(); - material->getShader()->setUniform(uniform->getVariable(), value); - } + material->setUniformFloat(path, value); } }); @@ -224,13 +214,34 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Integer input. Can map to a combo box if an enumeration if (value->isA()) { - int v = value->asA(); + const size_t INVALID_INDEX = std::numeric_limits::max(); + auto indexInEnumeration = [&value, &enumValues, &enumeration]() + { + size_t index = 0; + for(auto& enumValue: enumValues) + { + if(value->getValueString() == enumValue->getValueString()) + { + return index; + } + index++; + } + index = 0; + for(auto& enumName: enumeration) + { + if(value->getValueString() == enumName) + { + return index; + } + index++; + } + return std::numeric_limits::max(); // INVALID_INDEX; + }; // Create a combo box. The items are the enumerations in order. - if (v < (int) enumeration.size()) + const size_t valueIndex = indexInEnumeration(); + if (INVALID_INDEX != valueIndex) { - std::string enumValue = enumeration[v]; - ng::Widget* twoColumns = new ng::Widget(container); twoColumns->setLayout(_gridLayout2); @@ -238,24 +249,19 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, {""}); comboBox->setEnabled(editable); comboBox->setItems(enumeration); - comboBox->setSelectedIndex(v); + comboBox->setSelectedIndex(static_cast(valueIndex)); comboBox->setFixedSize(ng::Vector2i(100, 20)); comboBox->setFontSize(15); - comboBox->setCallback([path, viewer, enumValues](int v) + comboBox->setCallback([path, viewer, enumeration, enumValues](int index) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if(index >= 0 && static_cast(index) < enumValues.size()) { - material->getShader()->bind(); - if (v < (int) enumValues.size()) - { - material->getShader()->setUniform(uniform->getVariable(), enumValues[v]->asA()); - } - else - { - material->getShader()->setUniform(uniform->getVariable(), v); - } + material->setUniformInt(path, enumValues[index]->asA()); + } + else if(index >= 0 && static_cast(index) < enumeration.size()) + { + material->setUniformEnum(path, index, enumeration[index]); } }); } @@ -274,12 +280,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st MaterialPtr material = viewer->getSelectedMaterial(); if (material) { - mx::ShaderPort* uniform = material->findUniform(path); - if (uniform) - { - material->getShader()->bind(); - material->getShader()->setUniform(uniform->getVariable(), v); - } + material->setUniformInt(path, v); } }); } @@ -307,11 +308,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st boolVar->setCallback([path, viewer](bool v) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if(material) { - material->getShader()->bind(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformFloat(path, v); } }); } @@ -335,14 +334,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st colorVar->setFinalCallback([path, viewer, colorVar](const ng::Color &c) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if(material) { - material->getShader()->bind(); ng::Vector2f v; v.x() = c.r(); v.y() = c.g(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec2(path, v); ng::Color c2 = c; c2.b() = 0.0f; c2.w() = 1.0f; @@ -384,10 +381,8 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st comboBox->setCallback([path, enumValues, viewer](int index) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); if (index < (int) enumValues.size()) { mx::Color3 c = enumValues[index]->asA(); @@ -395,7 +390,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st v.x() = c[0]; v.y() = c[1]; v.z() = c[2]; - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec3(path, v); } } }); @@ -416,16 +411,11 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st colorVar->setFinalCallback([path, viewer](const ng::Color &c) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) - { - material->getShader()->bind(); - ng::Vector3f v; - v.x() = c.r(); - v.y() = c.g(); - v.z() = c.b(); - material->getShader()->setUniform(uniform->getVariable(), v); - } + ng::Vector3f v; + v[0] = c.r(); + v[1] = c.g(); + v[2] = c.b(); + material->setUniformVec3(path, v); }); } } @@ -449,16 +439,14 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st colorVar->setFinalCallback([path, viewer](const ng::Color &c) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector4f v; v.x() = c.r(); v.y() = c.g(); v.z() = c.b(); v.w() = c.w(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec4(path, v); } }); } @@ -481,28 +469,25 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st v1->setCallback([v2, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector2f v; v.x() = f; v.y() = v2->value(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec2(path, v); } }); v1->setSpinnable(editable); v2->setCallback([v1, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { material->getShader()->bind(); ng::Vector2f v; v.x() = v1->value(); v.y() = f; - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec2(path, v); } }); v2->setSpinnable(editable); @@ -531,45 +516,41 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st v1->setCallback([v2, v3, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { material->getShader()->bind(); ng::Vector3f v; v.x() = f; v.y() = v2->value(); v.z() = v3->value(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec3(path, v); } }); v1->setSpinnable(editable); v2->setCallback([v1, v3, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { material->getShader()->bind(); ng::Vector3f v; v.x() = v1->value(); v.y() = f; v.z() = v3->value(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec3(path, v); } }); v2->setSpinnable(editable); v3->setCallback([v1, v2, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector3f v; v.x() = v1->value(); v.y() = v2->value(); v.z() = f; - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec3(path, v); } }); v3->setSpinnable(editable); @@ -602,64 +583,56 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st v1->setCallback([v2, v3, v4, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector4f v; v.x() = f; v.y() = v2->value(); v.z() = v3->value(); v.w() = v4->value(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec4(path, v); } }); v1->setSpinnable(editable); v2->setCallback([v1, v3, v4, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector4f v; v.x() = v1->value(); v.y() = f; v.z() = v3->value(); v.w() = v4->value(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec4(path, v); } }); v2->setSpinnable(editable); v3->setCallback([v1, v2, v4, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector4f v; v.x() = v1->value(); v.y() = v2->value(); v.z() = f; v.w() = v4->value(); - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec4(path, v); } }); v3->setSpinnable(editable); v4->setCallback([v1, v2, v3, path, viewer](float f) { MaterialPtr material = viewer->getSelectedMaterial(); - mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; - if (uniform) + if (material) { - material->getShader()->bind(); ng::Vector4f v; v.x() = v1->value(); v.y() = v2->value(); v.z() = v3->value(); v.w() = f; - material->getShader()->setUniform(uniform->getVariable(), v); + material->setUniformVec4(path, v); } }); v4->setSpinnable(editable); diff --git a/source/MaterialXView/Material.cpp b/source/MaterialXView/Material.cpp index fc00c3d99c..9ae355ee1a 100644 --- a/source/MaterialXView/Material.cpp +++ b/source/MaterialXView/Material.cpp @@ -609,3 +609,97 @@ mx::ShaderPort* Material::findUniform(const std::string& path) const } return port; } + +void Material::changeUniformElement(mx::ShaderPort* uniform, const std::string& value) +{ + if (nullptr == uniform) + { + throw std::runtime_error("Null ShaderPort"); + } + uniform->setValue(mx::Value::createValueFromStrings(value, uniform->getType()->getName())); + mx::ElementPtr element = _doc->getDescendant(uniform->getPath()); + if (element) + { + mx::ValueElementPtr valueElement = element->asA(); + if (valueElement) + { + valueElement->setValueString(value); + } + } +} + +void Material::setUniformInt(const std::string& path, int value) +{ + mx::ShaderPort* uniform = findUniform(path); + if (uniform) + { + getShader()->bind(); + getShader()->setUniform(uniform->getVariable(), value); + std::stringstream intValue; + intValue << value; + changeUniformElement(uniform, intValue.str()); + } +} + +void Material::setUniformFloat(const std::string& path, float value) +{ + mx::ShaderPort* uniform = findUniform(path); + if (uniform) + { + getShader()->bind(); + getShader()->setUniform(uniform->getVariable(), value); + std::stringstream floatValue; + floatValue << value; + changeUniformElement(uniform, floatValue.str()); + } +} + +void Material::setUniformVec2(const std::string& path, const ng::Vector2f& value) +{ + mx::ShaderPort* uniform = findUniform(path); + if (uniform) + { + getShader()->bind(); + getShader()->setUniform(uniform->getVariable(), value); + std::stringstream vec2Value; + vec2Value << value[0] << mx::ARRAY_VALID_SEPARATORS << value[1]; + changeUniformElement(uniform, vec2Value.str()); + } +} + +void Material::setUniformVec3(const std::string& path, const ng::Vector3f& value) +{ + mx::ShaderPort* uniform = findUniform(path); + if (uniform) + { + getShader()->bind(); + getShader()->setUniform(uniform->getVariable(), value); + std::stringstream vec3Value; + vec3Value << value[0] << mx::ARRAY_VALID_SEPARATORS << value[1] << mx::ARRAY_VALID_SEPARATORS << value[2]; + changeUniformElement(uniform, vec3Value.str()); + } +} + +void Material::setUniformVec4(const std::string& path, const ng::Vector4f& value) +{ + mx::ShaderPort* uniform = findUniform(path); + if (uniform) + { + getShader()->bind(); + getShader()->setUniform(uniform->getVariable(), value); + std::stringstream vec4Value; + vec4Value << value[0] << mx::ARRAY_VALID_SEPARATORS << value[1] << mx::ARRAY_VALID_SEPARATORS << value[2] << mx::ARRAY_VALID_SEPARATORS << value[3]; + changeUniformElement(uniform, vec4Value.str()); + } +} + +void Material::setUniformEnum(const std::string& path, int index, const std::string& value) +{ + mx::ShaderPort* uniform = findUniform(path); + if (uniform) + { + getShader()->bind(); + getShader()->setUniform(uniform->getVariable(), index); + changeUniformElement(uniform, value); + } +} diff --git a/source/MaterialXView/Material.h b/source/MaterialXView/Material.h index 93dd37690b..7aa42defe6 100644 --- a/source/MaterialXView/Material.h +++ b/source/MaterialXView/Material.h @@ -164,6 +164,27 @@ class Material /// Find a public uniform from its MaterialX path. mx::ShaderPort* findUniform(const std::string& path) const; + /// Change the uniform value inside the shader and the associated element in the MaterialX document. + void changeUniformElement(mx::ShaderPort* uniform, const std::string& value); + + /// Set the value for an element with a given path. + void setUniformInt(const std::string& path, int value); + + /// Set the value for an element with a given path. + void setUniformFloat(const std::string& path, float value); + + /// Set the value for an element with a given path. + void setUniformVec2(const std::string& path, const ng::Vector2f& value); + + /// Set the value for an element with a given path. + void setUniformVec3(const std::string& path, const ng::Vector3f& value); + + /// Set the value for an element with a given path. + void setUniformVec4(const std::string& path, const ng::Vector4f& value); + + /// Set the value for an element with a given path. + void setUniformEnum(const std::string& path, int index, const std::string& value); + protected: void bindUniform(const std::string& name, mx::ConstValuePtr value); void updateUniformsList(); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 2736376eef..77d08a307b 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -70,9 +70,10 @@ void writeTextFile(const std::string& text, const std::string& filePath) file.close(); } -mx::DocumentPtr loadLibraries(const mx::StringVec& libraryFolders, const mx::FileSearchPath& searchPath) +std::pair loadLibraries(const mx::StringVec& libraryFolders, const mx::FileSearchPath& searchPath) { mx::DocumentPtr doc = mx::createDocument(); + mx::StringVec xincludeFiles; for (const std::string& libraryFolder : libraryFolders) { mx::FilePath path = searchPath.find(libraryFolder); @@ -90,9 +91,10 @@ mx::DocumentPtr loadLibraries(const mx::StringVec& libraryFolders, const mx::Fil mx::readFromXmlFile(libDoc, file, mx::EMPTY_STRING, &readOptions); libDoc->setSourceUri(file); doc->importLibrary(libDoc, ©Options); + xincludeFiles.push_back(file); } } - return doc; + return std::make_pair(doc, xincludeFiles); } void applyModifiers(mx::DocumentPtr doc, const DocumentModifiers& modifiers) @@ -219,14 +221,8 @@ Viewer::Viewer(const mx::StringVec& libraryFolders, createLoadMeshInterface(_window, "Load Mesh"); createLoadMaterialsInterface(_window, "Load Material"); - - ng::Button* editorButton = new ng::Button(_window, "Property Editor"); - editorButton->setFlags(ng::Button::ToggleButton); - editorButton->setChangeCallback([this](bool state) - { - _propertyEditor.setVisible(state); - performLayout(); - }); + createSaveMaterialsInterface(_window, "Save Material"); + createPropertyEditorInterface(_window, "Property Editor"); // Set this before building UI as this flag is used // for the UI building @@ -276,7 +272,10 @@ Viewer::Viewer(const mx::StringVec& libraryFolders, _lightFileName = "resources/Materials/TestSuite/Utilities/Lights/default_viewer_lights.mtlx"; // Initialize standard library and color management. - _stdLib = loadLibraries(_libraryFolders, _searchPath); + const auto stdDocAndXIncludes = loadLibraries(_libraryFolders, _searchPath); + _stdLib = stdDocAndXIncludes.first; + _xincludeFiles = stdDocAndXIncludes.second; + mx::DefaultColorManagementSystemPtr cms = mx::DefaultColorManagementSystem::create(_genContext.getShaderGenerator().getLanguage()); cms->loadLibrary(_stdLib); for (size_t i = 0; i < _searchPath.size(); i++) @@ -370,6 +369,7 @@ void Viewer::setupLights(mx::DocumentPtr doc) mx::CopyOptions copyOptions; copyOptions.skipConflictingElements = true; doc->importLibrary(lightDoc, ©Options); + _xincludeFiles.push_back(path); } catch (std::exception& e) { @@ -519,6 +519,44 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab }); } +void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& label) +{ + ng::Button* materialButton = new ng::Button(parent, label); + materialButton->setIcon(ENTYPO_ICON_SAVE); + materialButton->setCallback([this]() + { + mProcessEvents = false; + std::string filename = ng::file_dialog({ { "mtlx", "MaterialX" } }, true); + + // Save document + if (!filename.empty() && !_materials.empty()) + { + mx::DocumentPtr doc = _materials.front()->getDocument(); + mx::XmlWriteOptions writeOptions; + writeOptions.ignoredXIncludes = _xincludeFiles; + MaterialX::writeToXmlFile(doc, filename, &writeOptions); + } + + // Update material file name + if (!filename.empty() && _materialFilename != filename) + { + _materialFilename = filename; + } + mProcessEvents = true; + }); +} + +void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& label) +{ + ng::Button* editorButton = new ng::Button(parent, label); + editorButton->setFlags(ng::Button::ToggleButton); + editorButton->setChangeCallback([this](bool state) + { + _propertyEditor.setVisible(state); + performLayout(); + }); +} + void Viewer::createAdvancedSettings(Widget* parent) { ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index a72eb84e9b..77872fcb0b 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -107,6 +107,8 @@ class Viewer : public ng::Screen void createLoadMeshInterface(Widget* parent, const std::string& label); void createLoadMaterialsInterface(Widget* parent, const std::string& label); + void createSaveMaterialsInterface(Widget* parent, const std::string& label); + void createPropertyEditorInterface(Widget* parent, const std::string& label); void createAdvancedSettings(Widget* parent); mx::MeshStreamPtr createUvPositionStream(mx::MeshPtr mesh, @@ -139,6 +141,7 @@ class Viewer : public ng::Screen mx::DocumentPtr _stdLib; mx::FilePath _materialFilename; DocumentModifiers _modifiers; + mx::StringVec _xincludeFiles; // Lighting information std::string _lightFileName;