载入中...
搜索中...
未找到
MaterialEditorModule.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
9
10#include <simplesquirrel/simplesquirrel.hpp>
11
12#include <cstdint>
13#include <limits>
14#include <stdexcept>
15#include <string_view>
16#include <typeindex>
17#include <vector>
18
20namespace {
21
22const std::int64_t* integerField(const editor::EditorValue::Object& request, const char* key) {
23 const auto found = request.find(key);
24 return found == request.end() ? nullptr : found->second.getIf<std::int64_t>();
25}
26
27class AutomationMaterialAssetResolver final : public material_editing::IMaterialRuntimeAssetResolver {
28public:
29 editor::Result<graphics::Texture*> resolveTexture(const std::string& asset) const override {
30 return unresolved<graphics::Texture>(asset);
31 }
32 editor::Result<graphics::Shader*> resolveShader(const std::string& asset) const override {
33 return unresolved<graphics::Shader>(asset);
34 }
35
36private:
37 template <class T>
38 static editor::Result<T*> unresolved(const std::string& asset) {
39 return eve::editing::failed<T*>(
40 editor::EditorStatus::Unsupported, editor::RuleId("editor.automation.material-asset"),
41 "Automation binding cannot resolve material asset: " + asset);
42 }
43};
44
45graphics::Renderable3D* findRenderable(std::uint32_t id, std::uint32_t generation) {
46 ecs::EntityHandle handle{ecs::current(), std::type_index(typeid(graphics::Renderable3D)), id, generation};
47 return dynamic_cast<graphics::Renderable3D*>(ecs::try_get(handle));
48}
49
50editor::EditorValue runtimeMaterialSnapshot(const graphics::Renderable3D::MeshRenderer& renderer) {
51 material_editing::MaterialDocumentTarget defaults("material.runtime.seed");
52 editor::EditorValue snapshot = defaults.snapshotValue();
53 auto* root = snapshot.getIf<editor::EditorValue::Object>();
54 auto* properties = root ? root->at("properties").getIf<editor::EditorValue::Object>() : nullptr;
55 (*properties)["shading.tint"] = editor::EditorValue::Array{double(renderer.r), double(renderer.g),
56 double(renderer.b), double(renderer.a)};
57 (*properties)["shading.metallic"] = double(renderer.metallic);
58 (*properties)["shading.roughness"] = double(renderer.roughness);
59 (*properties)["parallax.scale"] = double(renderer.parallaxScale);
60 (*properties)["lighting.receive"] = renderer.receiveLight;
61 (*properties)["shadow.cast"] = renderer.castShadow;
62 (*properties)["shadow.receive"] = renderer.receiveShadow;
63 return snapshot;
64}
65
66} // namespace
67
69public:
70 std::vector<std::string_view> types() const override { return {"material", "material-renderable3d"}; }
71
73 const editor::TargetId& target, std::string_view type,
74 const editor::EditorValue::Object& request) override {
76 if (type == "material") {
77 owned.target = std::make_unique<material_editing::MaterialDocumentTarget>(target.value());
78 return eve::editing::applied<editor::AutomationOwnedTarget>(std::move(owned));
79 }
80 const auto* id = integerField(request, "entityId");
81 const auto* generation = integerField(request, "generation");
82 constexpr auto maxId = static_cast<std::int64_t>(std::numeric_limits<std::uint32_t>::max());
83 if (!id || !generation || *id < 0 || *generation < 0 || *id > maxId || *generation > maxId)
84 return eve::editing::failed<editor::AutomationOwnedTarget>(
85 editor::EditorStatus::Rejected, editor::RuleId("editor.automation.material-handle"),
86 "Live material target requires uint32 entityId and generation");
87 auto* renderable = findRenderable(static_cast<std::uint32_t>(*id), static_cast<std::uint32_t>(*generation));
88 if (!renderable)
89 return eve::editing::failed<editor::AutomationOwnedTarget>(
90 editor::EditorStatus::Conflict, editor::RuleId("editor.automation.material-stale"),
91 "Renderable3D handle is missing or stale");
92 auto renderer = renderable->meshRenderer();
93 if (renderer->material || renderer->texture || renderer->normalTexture || renderer->heightTexture ||
94 renderer->shader)
95 return eve::editing::failed<editor::AutomationOwnedTarget>(
96 editor::EditorStatus::Unsupported, editor::RuleId("editor.automation.material-assets"),
97 "Live material binding currently supports field-backed materials without asset overrides");
98 static const AutomationMaterialAssetResolver assets;
99 auto sink = std::make_shared<material_editing::Renderable3DMaterialRuntimeSink>(renderable, &assets);
100 auto publishing = std::make_unique<material_editing::MaterialPublishingTarget>(target.value(), sink.get());
101 auto loaded = publishing->authoringTarget().loadSnapshot(runtimeMaterialSnapshot(*renderer));
102 if (!loaded.ok()) {
104 }
105 owned.support = std::move(sink);
106 owned.target = std::move(publishing);
107 return eve::editing::applied<editor::AutomationOwnedTarget>(std::move(owned));
108 }
109};
110
112
114 auto* registry = eve::cap::query<editing::IEditingCommandRegistry>();
115 if (!registry || !material_editing::registerEditingCommands(*registry).ok())
116 throw std::runtime_error("Failed to register material editing commands");
117 eve::cap::addListener<editor::IEditorAutomationTargetFactory>(factory_.get());
118}
119
121 eve::cap::removeListener<editor::IEditorAutomationTargetFactory>(factory_.get());
122 if (auto* registry = eve::cap::query<editing::IEditingCommandRegistry>())
123 registry->unregisterOwner("material_editing").ignore("material editor adapter shutdown");
124}
125
126void MaterialEditorModule::expose(ssq::Table& table) { table.addClass(name, MaterialEditorModule::create, false); }
127void MaterialEditorModule::expose(ssq::Class&) {}
128
129} // namespace eve::material_editor
LogicalId target
int root
Definition AnimSmr.cpp:119
ActiveSource owned
const GltfImportRequest & request
std::uint32_t key
std::map< std::string, PropertyRule > properties
std::string name
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::string id
Definition PlayHost.cpp:108
std::uint32_t generation
PrimitiveHandle handle
bool found
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
Deterministic owning value tree shared by authoring hosts.
std::vector< Value > Array
std::map< std::string, Value > Object
const T * getIf() const
Return an immediately borrowed typed value.
Multi-provider extension point for domain-specific automation target creation.
EVENGINE_API_BACKENDS public API.
UI-neutral, serializable material authoring target.
EditorValue snapshotValue() const override
Capture deterministic content suitable for DocumentService persistence.
editor::Result< editor::AutomationOwnedTarget > create(const editor::TargetId &target, std::string_view type, const editor::EditorValue::Object &request) override
Create a domain target from an automation request. @ownership Success transfers the target and any su...
std::vector< std::string_view > types() const override
Stable target type names this factory accepts.
Composition adapter that contributes material editing commands and automation targets.
~MaterialEditorModule() override
Material editor module.
editing::Result< void > registerEditingCommands(editing::IEditingCommandRegistry &registry)
Register Material-owned property commands with a generic editing host.
Target plus optional borrowed-dependency owner returned by an automation factory.
std::unique_ptr< IEditableTarget > target