mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 21:55:09 +00:00
ROADMAP.md
This commit is contained in:
@@ -295,6 +295,14 @@ set(WORKFLOW_SOURCES
|
||||
src/services/impl/workflow_default_step_registrar.cpp
|
||||
)
|
||||
|
||||
set(MATERIALX_SCRIPT_SOURCES
|
||||
src/services/impl/materialx_path_resolver.cpp
|
||||
src/services/impl/materialx_search_path_builder.cpp
|
||||
src/services/impl/materialx_document_loader.cpp
|
||||
src/services/impl/materialx_surface_node_resolver.cpp
|
||||
src/services/impl/materialx_surface_parameter_reader.cpp
|
||||
)
|
||||
|
||||
if(BUILD_SDL3_APP)
|
||||
add_executable(sdl3_app
|
||||
src/main.cpp
|
||||
@@ -303,6 +311,7 @@ if(BUILD_SDL3_APP)
|
||||
src/events/event_bus.cpp
|
||||
${JSON_CONFIG_SOURCES}
|
||||
${WORKFLOW_SOURCES}
|
||||
${MATERIALX_SCRIPT_SOURCES}
|
||||
src/services/impl/config_compiler_service.cpp
|
||||
src/services/impl/command_line_service.cpp
|
||||
src/services/impl/json_config_writer_service.cpp
|
||||
@@ -428,6 +437,7 @@ add_executable(script_engine_tests
|
||||
src/services/impl/physics_bridge_service.cpp
|
||||
src/services/impl/platform_service.cpp
|
||||
src/services/impl/script_engine_service.cpp
|
||||
${MATERIALX_SCRIPT_SOURCES}
|
||||
src/services/impl/lua_helpers.cpp
|
||||
src/services/impl/scene_script_service.cpp
|
||||
src/services/impl/shader_script_service.cpp
|
||||
|
||||
@@ -160,6 +160,7 @@ Treat JSON config as a declarative control plane that compiles into scene, resou
|
||||
### Phase A: Mechanical Extraction (1-3 days)
|
||||
- [~] JsonConfigService: extracted config document load/merge helpers into `src/services/impl/json_config_document_loader.cpp` plus small parser/extend/merge services to keep files <100 LOC.
|
||||
- [~] JsonConfigService: split schema validation/versioning/migration into `json_config_*` services (`schema_validator`, `version_validator`, `migration_service`).
|
||||
- [~] ScriptEngineService: extracted MaterialX helpers into micro services (`materialx_path_resolver`, `materialx_search_path_builder`, `materialx_document_loader`, `materialx_surface_node_resolver`, `materialx_surface_parameter_reader`).
|
||||
- Move self-contained helpers into `*_helpers.cpp` with clear headers.
|
||||
- Extract pure data transforms into free functions with unit tests.
|
||||
- Preserve public interfaces; no behavior change in this phase.
|
||||
@@ -231,6 +232,7 @@ Option B: per-shader only
|
||||
- Describe boot + frame pipelines as a declarative JSON workflow graph.
|
||||
- Keep each step tiny (<100 LOC), with explicit inputs/outputs and DI-backed plugin lookup.
|
||||
- Package common pipelines as templates so users don't start from scratch.
|
||||
- Only register/instantiate step plugins that are referenced by the active workflow.
|
||||
|
||||
### Status
|
||||
- [~] Workflow core: step registry + executor + JSON definition parser.
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "services/impl/pipeline_compiler_service.hpp"
|
||||
#include "services/impl/validation_tour_service.hpp"
|
||||
#include "services/impl/workflow_default_step_registrar.hpp"
|
||||
#include "services/impl/workflow_definition_parser.hpp"
|
||||
#include "services/impl/workflow_executor.hpp"
|
||||
#include "services/impl/workflow_step_registry.hpp"
|
||||
#include "services/interfaces/i_platform_service.hpp"
|
||||
@@ -49,6 +50,7 @@
|
||||
#include "services/interfaces/i_workflow_step_registry.hpp"
|
||||
#include "services/interfaces/i_config_compiler_service.hpp"
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
@@ -233,10 +235,26 @@ void ServiceBasedApp::RegisterServices() {
|
||||
registry_.RegisterService<services::IWorkflowExecutor, services::impl::WorkflowExecutor>(
|
||||
registry_.GetService<services::IWorkflowStepRegistry>(),
|
||||
registry_.GetService<services::ILogger>());
|
||||
services::impl::WorkflowDefaultStepRegistrar workflowRegistrar(
|
||||
registry_.GetService<services::ILogger>(),
|
||||
registry_.GetService<services::IProbeService>());
|
||||
workflowRegistrar.RegisterDefaults(registry_.GetService<services::IWorkflowStepRegistry>());
|
||||
services::impl::WorkflowDefinitionParser workflowParser;
|
||||
services::WorkflowDefinition workflowDefinition;
|
||||
bool workflowLoaded = false;
|
||||
try {
|
||||
const std::filesystem::path workflowPath =
|
||||
std::filesystem::current_path() / "config" / "workflows" / "templates" / "boot_default.json";
|
||||
workflowDefinition = workflowParser.ParseFile(workflowPath);
|
||||
workflowLoaded = true;
|
||||
} catch (const std::exception& e) {
|
||||
logger_->Warn("ServiceBasedApp::RegisterServices: Failed to load workflow template: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
if (workflowLoaded) {
|
||||
services::impl::WorkflowDefaultStepRegistrar workflowRegistrar(
|
||||
registry_.GetService<services::ILogger>(),
|
||||
registry_.GetService<services::IProbeService>());
|
||||
workflowRegistrar.RegisterUsedSteps(
|
||||
workflowDefinition,
|
||||
registry_.GetService<services::IWorkflowStepRegistry>());
|
||||
}
|
||||
|
||||
// Configuration service
|
||||
registry_.RegisterService<services::IConfigService, services::impl::JsonConfigService>(
|
||||
|
||||
31
src/services/impl/materialx_document_loader.cpp
Normal file
31
src/services/impl/materialx_document_loader.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "materialx_document_loader.hpp"
|
||||
#include "materialx_search_path_builder.hpp"
|
||||
|
||||
#include <MaterialXFormat/Util.h>
|
||||
#include <MaterialXFormat/XmlIo.h>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
MaterialX::DocumentPtr MaterialXDocumentLoader::Load(const std::filesystem::path& documentPath,
|
||||
const MaterialXConfig& config,
|
||||
const std::filesystem::path& scriptDirectory) const {
|
||||
MaterialX::DocumentPtr document = MaterialX::createDocument();
|
||||
MaterialXSearchPathBuilder builder;
|
||||
auto searchPath = builder.Build(config, scriptDirectory);
|
||||
MaterialX::readFromXmlFile(document, MaterialX::FilePath(documentPath.string()), searchPath);
|
||||
|
||||
if (!config.libraryFolders.empty()) {
|
||||
MaterialX::DocumentPtr stdLib = MaterialX::createDocument();
|
||||
MaterialX::FilePathVec folders;
|
||||
folders.reserve(config.libraryFolders.size());
|
||||
for (const auto& folder : config.libraryFolders) {
|
||||
folders.emplace_back(folder);
|
||||
}
|
||||
MaterialX::loadLibraries(folders, searchPath, stdLib);
|
||||
document->importLibrary(stdLib);
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
18
src/services/impl/materialx_document_loader.hpp
Normal file
18
src/services/impl/materialx_document_loader.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/config_types.hpp"
|
||||
|
||||
#include <MaterialXCore/Document.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class MaterialXDocumentLoader {
|
||||
public:
|
||||
MaterialX::DocumentPtr Load(const std::filesystem::path& documentPath,
|
||||
const MaterialXConfig& config,
|
||||
const std::filesystem::path& scriptDirectory) const;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
33
src/services/impl/materialx_path_resolver.cpp
Normal file
33
src/services/impl/materialx_path_resolver.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "materialx_path_resolver.hpp"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
std::filesystem::path MaterialXPathResolver::Resolve(const std::filesystem::path& path,
|
||||
const std::filesystem::path& scriptDirectory) const {
|
||||
if (path.empty()) {
|
||||
return {};
|
||||
}
|
||||
if (path.is_absolute()) {
|
||||
return path;
|
||||
}
|
||||
if (!scriptDirectory.empty()) {
|
||||
auto projectRoot = scriptDirectory.parent_path();
|
||||
if (!projectRoot.empty()) {
|
||||
std::error_code ec;
|
||||
auto resolved = std::filesystem::weakly_canonical(projectRoot / path, ec);
|
||||
if (!ec) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::error_code ec;
|
||||
auto resolved = std::filesystem::weakly_canonical(path, ec);
|
||||
if (ec) {
|
||||
return {};
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
13
src/services/impl/materialx_path_resolver.hpp
Normal file
13
src/services/impl/materialx_path_resolver.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class MaterialXPathResolver {
|
||||
public:
|
||||
std::filesystem::path Resolve(const std::filesystem::path& path,
|
||||
const std::filesystem::path& scriptDirectory) const;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
26
src/services/impl/materialx_search_path_builder.cpp
Normal file
26
src/services/impl/materialx_search_path_builder.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "materialx_search_path_builder.hpp"
|
||||
#include "materialx_path_resolver.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
MaterialX::FileSearchPath MaterialXSearchPathBuilder::Build(
|
||||
const MaterialXConfig& config,
|
||||
const std::filesystem::path& scriptDirectory) const {
|
||||
MaterialX::FileSearchPath searchPath;
|
||||
MaterialXPathResolver resolver;
|
||||
std::filesystem::path libraryPath = resolver.Resolve(config.libraryPath, scriptDirectory);
|
||||
if (libraryPath.empty() && !scriptDirectory.empty()) {
|
||||
auto fallback = scriptDirectory.parent_path() / "MaterialX" / "libraries";
|
||||
if (std::filesystem::exists(fallback)) {
|
||||
libraryPath = fallback;
|
||||
}
|
||||
}
|
||||
if (!libraryPath.empty()) {
|
||||
searchPath.append(MaterialX::FilePath(libraryPath.string()));
|
||||
}
|
||||
return searchPath;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
17
src/services/impl/materialx_search_path_builder.hpp
Normal file
17
src/services/impl/materialx_search_path_builder.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/config_types.hpp"
|
||||
|
||||
#include <MaterialXFormat/Util.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class MaterialXSearchPathBuilder {
|
||||
public:
|
||||
MaterialX::FileSearchPath Build(const MaterialXConfig& config,
|
||||
const std::filesystem::path& scriptDirectory) const;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
41
src/services/impl/materialx_surface_node_resolver.cpp
Normal file
41
src/services/impl/materialx_surface_node_resolver.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "materialx_surface_node_resolver.hpp"
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
MaterialX::NodePtr MaterialXSurfaceNodeResolver::ResolveSurfaceNode(
|
||||
const MaterialX::DocumentPtr& document,
|
||||
const std::string& materialName) const {
|
||||
if (!materialName.empty()) {
|
||||
MaterialX::NodePtr candidate = document->getNode(materialName);
|
||||
if (candidate && candidate->getCategory() == "surfacematerial") {
|
||||
MaterialX::NodePtr surfaceNode = candidate->getConnectedNode("surfaceshader");
|
||||
if (surfaceNode) {
|
||||
return surfaceNode;
|
||||
}
|
||||
}
|
||||
if (candidate && (candidate->getCategory() == "standard_surface"
|
||||
|| candidate->getCategory() == "usd_preview_surface")) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& node : document->getNodes()) {
|
||||
if (node->getCategory() == "surfacematerial") {
|
||||
MaterialX::NodePtr surfaceNode = node->getConnectedNode("surfaceshader");
|
||||
if (surfaceNode) {
|
||||
return surfaceNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& node : document->getNodes()) {
|
||||
if (node->getCategory() == "standard_surface"
|
||||
|| node->getCategory() == "usd_preview_surface") {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
15
src/services/impl/materialx_surface_node_resolver.hpp
Normal file
15
src/services/impl/materialx_surface_node_resolver.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <MaterialXCore/Document.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class MaterialXSurfaceNodeResolver {
|
||||
public:
|
||||
MaterialX::NodePtr ResolveSurfaceNode(const MaterialX::DocumentPtr& document,
|
||||
const std::string& materialName) const;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
81
src/services/impl/materialx_surface_parameter_reader.cpp
Normal file
81
src/services/impl/materialx_surface_parameter_reader.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "materialx_surface_parameter_reader.hpp"
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
bool MaterialXSurfaceParameterReader::TryReadColor3(const MaterialX::NodePtr& node,
|
||||
const char* name,
|
||||
std::array<float, 3>& outColor) const {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
MaterialX::InputPtr input = node->getInput(name);
|
||||
if (!input || !input->hasValueString()) {
|
||||
return false;
|
||||
}
|
||||
MaterialX::ValuePtr value = input->getValue();
|
||||
if (!value || !value->isA<MaterialX::Color3>()) {
|
||||
return false;
|
||||
}
|
||||
const MaterialX::Color3& color = value->asA<MaterialX::Color3>();
|
||||
outColor = {color[0], color[1], color[2]};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialXSurfaceParameterReader::TryReadFloat(const MaterialX::NodePtr& node,
|
||||
const char* name,
|
||||
float& outValue) const {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
MaterialX::InputPtr input = node->getInput(name);
|
||||
if (!input || !input->hasValueString()) {
|
||||
return false;
|
||||
}
|
||||
MaterialX::ValuePtr value = input->getValue();
|
||||
if (!value || !value->isA<float>()) {
|
||||
return false;
|
||||
}
|
||||
outValue = value->asA<float>();
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialXSurfaceParameters MaterialXSurfaceParameterReader::ReadStandardSurfaceParameters(
|
||||
const MaterialX::NodePtr& node) const {
|
||||
MaterialXSurfaceParameters parameters;
|
||||
std::array<float, 3> baseColor = parameters.albedo;
|
||||
bool hasBaseColor = TryReadColor3(node, "base_color", baseColor);
|
||||
if (!hasBaseColor) {
|
||||
hasBaseColor = TryReadColor3(node, "diffuse_color", baseColor);
|
||||
}
|
||||
float baseStrength = 1.0f;
|
||||
bool hasBaseStrength = TryReadFloat(node, "base", baseStrength);
|
||||
if (hasBaseColor) {
|
||||
parameters.albedo = {
|
||||
baseColor[0] * baseStrength,
|
||||
baseColor[1] * baseStrength,
|
||||
baseColor[2] * baseStrength
|
||||
};
|
||||
parameters.hasAlbedo = true;
|
||||
} else if (hasBaseStrength) {
|
||||
parameters.albedo = {baseStrength, baseStrength, baseStrength};
|
||||
parameters.hasAlbedo = true;
|
||||
}
|
||||
|
||||
float roughness = parameters.roughness;
|
||||
if (TryReadFloat(node, "specular_roughness", roughness)
|
||||
|| TryReadFloat(node, "roughness", roughness)) {
|
||||
parameters.roughness = roughness;
|
||||
parameters.hasRoughness = true;
|
||||
}
|
||||
|
||||
float metallic = parameters.metallic;
|
||||
if (TryReadFloat(node, "metalness", metallic)
|
||||
|| TryReadFloat(node, "metallic", metallic)) {
|
||||
parameters.metallic = metallic;
|
||||
parameters.hasMetallic = true;
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
20
src/services/impl/materialx_surface_parameter_reader.hpp
Normal file
20
src/services/impl/materialx_surface_parameter_reader.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "materialx_surface_parameters.hpp"
|
||||
|
||||
#include <MaterialXCore/Document.h>
|
||||
#include <MaterialXCore/Types.h>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class MaterialXSurfaceParameterReader {
|
||||
public:
|
||||
MaterialXSurfaceParameters ReadStandardSurfaceParameters(const MaterialX::NodePtr& node) const;
|
||||
|
||||
private:
|
||||
bool TryReadColor3(const MaterialX::NodePtr& node, const char* name,
|
||||
std::array<float, 3>& outColor) const;
|
||||
bool TryReadFloat(const MaterialX::NodePtr& node, const char* name, float& outValue) const;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
16
src/services/impl/materialx_surface_parameters.hpp
Normal file
16
src/services/impl/materialx_surface_parameters.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
struct MaterialXSurfaceParameters {
|
||||
std::array<float, 3> albedo = {1.0f, 1.0f, 1.0f};
|
||||
float roughness = 0.3f;
|
||||
float metallic = 0.0f;
|
||||
bool hasAlbedo = false;
|
||||
bool hasRoughness = false;
|
||||
bool hasMetallic = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -1,15 +1,14 @@
|
||||
#include "script_engine_service.hpp"
|
||||
|
||||
#include "lua_helpers.hpp"
|
||||
#include "materialx_document_loader.hpp"
|
||||
#include "materialx_path_resolver.hpp"
|
||||
#include "materialx_surface_node_resolver.hpp"
|
||||
#include "materialx_surface_parameter_reader.hpp"
|
||||
#include "services/interfaces/i_logger.hpp"
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <lua.hpp>
|
||||
#include <MaterialXCore/Document.h>
|
||||
#include <MaterialXCore/Types.h>
|
||||
#include <MaterialXFormat/File.h>
|
||||
#include <MaterialXFormat/Util.h>
|
||||
#include <MaterialXFormat/XmlIo.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
@@ -24,17 +23,6 @@
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
namespace mx = MaterialX;
|
||||
|
||||
struct MaterialXSurfaceParameters {
|
||||
std::array<float, 3> albedo = {1.0f, 1.0f, 1.0f};
|
||||
float roughness = 0.3f;
|
||||
float metallic = 0.0f;
|
||||
bool hasAlbedo = false;
|
||||
bool hasRoughness = false;
|
||||
bool hasMetallic = false;
|
||||
};
|
||||
|
||||
std::array<float, 3> TransformPoint(const std::array<float, 16>& matrix,
|
||||
const std::array<float, 3>& point) {
|
||||
const float x = point[0];
|
||||
@@ -47,174 +35,6 @@ std::array<float, 3> TransformPoint(const std::array<float, 16>& matrix,
|
||||
};
|
||||
}
|
||||
|
||||
std::filesystem::path ResolveMaterialXPath(const std::filesystem::path& path,
|
||||
const std::filesystem::path& scriptDirectory) {
|
||||
if (path.empty()) {
|
||||
return {};
|
||||
}
|
||||
if (path.is_absolute()) {
|
||||
return path;
|
||||
}
|
||||
if (!scriptDirectory.empty()) {
|
||||
auto projectRoot = scriptDirectory.parent_path();
|
||||
if (!projectRoot.empty()) {
|
||||
std::error_code ec;
|
||||
auto resolved = std::filesystem::weakly_canonical(projectRoot / path, ec);
|
||||
if (!ec) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::error_code ec;
|
||||
auto resolved = std::filesystem::weakly_canonical(path, ec);
|
||||
if (ec) {
|
||||
return {};
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
mx::FileSearchPath BuildMaterialXSearchPath(const sdl3cpp::services::MaterialXConfig& config,
|
||||
const std::filesystem::path& scriptDirectory) {
|
||||
mx::FileSearchPath searchPath;
|
||||
std::filesystem::path libraryPath = ResolveMaterialXPath(config.libraryPath, scriptDirectory);
|
||||
if (libraryPath.empty() && !scriptDirectory.empty()) {
|
||||
auto fallback = scriptDirectory.parent_path() / "MaterialX" / "libraries";
|
||||
if (std::filesystem::exists(fallback)) {
|
||||
libraryPath = fallback;
|
||||
}
|
||||
}
|
||||
if (!libraryPath.empty()) {
|
||||
searchPath.append(mx::FilePath(libraryPath.string()));
|
||||
}
|
||||
return searchPath;
|
||||
}
|
||||
|
||||
mx::DocumentPtr LoadMaterialXDocument(const std::filesystem::path& documentPath,
|
||||
const sdl3cpp::services::MaterialXConfig& config,
|
||||
const std::filesystem::path& scriptDirectory) {
|
||||
mx::DocumentPtr document = mx::createDocument();
|
||||
mx::FileSearchPath searchPath = BuildMaterialXSearchPath(config, scriptDirectory);
|
||||
mx::readFromXmlFile(document, mx::FilePath(documentPath.string()), searchPath);
|
||||
|
||||
if (!config.libraryFolders.empty()) {
|
||||
mx::DocumentPtr stdLib = mx::createDocument();
|
||||
mx::FilePathVec folders;
|
||||
folders.reserve(config.libraryFolders.size());
|
||||
for (const auto& folder : config.libraryFolders) {
|
||||
folders.emplace_back(folder);
|
||||
}
|
||||
mx::loadLibraries(folders, searchPath, stdLib);
|
||||
document->importLibrary(stdLib);
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
mx::NodePtr ResolveSurfaceNode(const mx::DocumentPtr& document, const std::string& materialName) {
|
||||
if (!materialName.empty()) {
|
||||
mx::NodePtr candidate = document->getNode(materialName);
|
||||
if (candidate && candidate->getCategory() == "surfacematerial") {
|
||||
mx::NodePtr surfaceNode = candidate->getConnectedNode("surfaceshader");
|
||||
if (surfaceNode) {
|
||||
return surfaceNode;
|
||||
}
|
||||
}
|
||||
if (candidate && (candidate->getCategory() == "standard_surface"
|
||||
|| candidate->getCategory() == "usd_preview_surface")) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& node : document->getNodes()) {
|
||||
if (node->getCategory() == "surfacematerial") {
|
||||
mx::NodePtr surfaceNode = node->getConnectedNode("surfaceshader");
|
||||
if (surfaceNode) {
|
||||
return surfaceNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& node : document->getNodes()) {
|
||||
if (node->getCategory() == "standard_surface"
|
||||
|| node->getCategory() == "usd_preview_surface") {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool TryReadColor3(const mx::NodePtr& node, const char* name, std::array<float, 3>& outColor) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
mx::InputPtr input = node->getInput(name);
|
||||
if (!input || !input->hasValueString()) {
|
||||
return false;
|
||||
}
|
||||
mx::ValuePtr value = input->getValue();
|
||||
if (!value || !value->isA<mx::Color3>()) {
|
||||
return false;
|
||||
}
|
||||
const mx::Color3& color = value->asA<mx::Color3>();
|
||||
outColor = {color[0], color[1], color[2]};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReadFloat(const mx::NodePtr& node, const char* name, float& outValue) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
mx::InputPtr input = node->getInput(name);
|
||||
if (!input || !input->hasValueString()) {
|
||||
return false;
|
||||
}
|
||||
mx::ValuePtr value = input->getValue();
|
||||
if (!value || !value->isA<float>()) {
|
||||
return false;
|
||||
}
|
||||
outValue = value->asA<float>();
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialXSurfaceParameters ReadStandardSurfaceParameters(const mx::NodePtr& node) {
|
||||
MaterialXSurfaceParameters parameters;
|
||||
std::array<float, 3> baseColor = parameters.albedo;
|
||||
bool hasBaseColor = TryReadColor3(node, "base_color", baseColor);
|
||||
if (!hasBaseColor) {
|
||||
hasBaseColor = TryReadColor3(node, "diffuse_color", baseColor);
|
||||
}
|
||||
float baseStrength = 1.0f;
|
||||
bool hasBaseStrength = TryReadFloat(node, "base", baseStrength);
|
||||
if (hasBaseColor) {
|
||||
parameters.albedo = {
|
||||
baseColor[0] * baseStrength,
|
||||
baseColor[1] * baseStrength,
|
||||
baseColor[2] * baseStrength
|
||||
};
|
||||
parameters.hasAlbedo = true;
|
||||
} else if (hasBaseStrength) {
|
||||
parameters.albedo = {baseStrength, baseStrength, baseStrength};
|
||||
parameters.hasAlbedo = true;
|
||||
}
|
||||
|
||||
float roughness = parameters.roughness;
|
||||
if (TryReadFloat(node, "specular_roughness", roughness)
|
||||
|| TryReadFloat(node, "roughness", roughness)) {
|
||||
parameters.roughness = roughness;
|
||||
parameters.hasRoughness = true;
|
||||
}
|
||||
|
||||
float metallic = parameters.metallic;
|
||||
if (TryReadFloat(node, "metalness", metallic)
|
||||
|| TryReadFloat(node, "metallic", metallic)) {
|
||||
parameters.metallic = metallic;
|
||||
parameters.hasMetallic = true;
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
bool TryParseMouseButtonName(const char* name, uint8_t& button) {
|
||||
if (!name) {
|
||||
return false;
|
||||
@@ -1356,7 +1176,8 @@ int ScriptEngineService::MaterialXGetSurfaceParameters(lua_State* L) {
|
||||
", material=" + std::string(materialArg ? materialArg : ""));
|
||||
}
|
||||
|
||||
std::filesystem::path documentPath = ResolveMaterialXPath(documentArg ? documentArg : "", scriptDirectory);
|
||||
MaterialXPathResolver pathResolver;
|
||||
std::filesystem::path documentPath = pathResolver.Resolve(documentArg ? documentArg : "", scriptDirectory);
|
||||
if (documentPath.empty()) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "MaterialX document path could not be resolved");
|
||||
@@ -1370,9 +1191,12 @@ int ScriptEngineService::MaterialXGetSurfaceParameters(lua_State* L) {
|
||||
}
|
||||
|
||||
const auto& materialConfig = context->configService->GetMaterialXConfig();
|
||||
mx::DocumentPtr document;
|
||||
MaterialXDocumentLoader documentLoader;
|
||||
MaterialXSurfaceNodeResolver nodeResolver;
|
||||
MaterialXSurfaceParameterReader parameterReader;
|
||||
MaterialX::DocumentPtr document;
|
||||
try {
|
||||
document = LoadMaterialXDocument(documentPath, materialConfig, scriptDirectory);
|
||||
document = documentLoader.Load(documentPath, materialConfig, scriptDirectory);
|
||||
} catch (const std::exception& ex) {
|
||||
lua_pushnil(L);
|
||||
std::string message = "MaterialX document load failed: ";
|
||||
@@ -1381,14 +1205,14 @@ int ScriptEngineService::MaterialXGetSurfaceParameters(lua_State* L) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
mx::NodePtr surfaceNode = ResolveSurfaceNode(document, materialArg ? materialArg : "");
|
||||
auto surfaceNode = nodeResolver.ResolveSurfaceNode(document, materialArg ? materialArg : "");
|
||||
if (!surfaceNode) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "MaterialX document has no standard_surface material");
|
||||
return 2;
|
||||
}
|
||||
|
||||
MaterialXSurfaceParameters parameters = ReadStandardSurfaceParameters(surfaceNode);
|
||||
MaterialXSurfaceParameters parameters = parameterReader.ReadStandardSurfaceParameters(surfaceNode);
|
||||
if (!parameters.hasAlbedo && !parameters.hasRoughness && !parameters.hasMetallic) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "MaterialX material does not expose supported PBR parameters");
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "workflow_config_version_step.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
@@ -13,13 +14,27 @@ WorkflowDefaultStepRegistrar::WorkflowDefaultStepRegistrar(std::shared_ptr<ILogg
|
||||
: logger_(std::move(logger)),
|
||||
probeService_(std::move(probeService)) {}
|
||||
|
||||
void WorkflowDefaultStepRegistrar::RegisterDefaults(const std::shared_ptr<IWorkflowStepRegistry>& registry) const {
|
||||
void WorkflowDefaultStepRegistrar::RegisterUsedSteps(
|
||||
const WorkflowDefinition& workflow,
|
||||
const std::shared_ptr<IWorkflowStepRegistry>& registry) const {
|
||||
if (!registry) {
|
||||
throw std::runtime_error("WorkflowDefaultStepRegistrar: registry is null");
|
||||
}
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigLoadStep>(logger_));
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigVersionStep>(logger_));
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigSchemaStep>(logger_, probeService_));
|
||||
|
||||
std::unordered_set<std::string> plugins;
|
||||
for (const auto& step : workflow.steps) {
|
||||
plugins.insert(step.plugin);
|
||||
}
|
||||
|
||||
if (plugins.contains("config.load")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigLoadStep>(logger_));
|
||||
}
|
||||
if (plugins.contains("config.version.validate")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigVersionStep>(logger_));
|
||||
}
|
||||
if (plugins.contains("config.schema.validate")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigSchemaStep>(logger_, probeService_));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_probe_service.hpp"
|
||||
#include "../interfaces/i_workflow_step_registry.hpp"
|
||||
#include "../interfaces/workflow_definition.hpp"
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
@@ -11,7 +12,8 @@ public:
|
||||
WorkflowDefaultStepRegistrar(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IProbeService> probeService);
|
||||
|
||||
void RegisterDefaults(const std::shared_ptr<IWorkflowStepRegistry>& registry) const;
|
||||
void RegisterUsedSteps(const WorkflowDefinition& workflow,
|
||||
const std::shared_ptr<IWorkflowStepRegistry>& registry) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
|
||||
Reference in New Issue
Block a user