载入中...
搜索中...
未找到
MaterialGraph.cpp
浏览该文件的文档.
2
3#include <algorithm>
4
5namespace eve::material_editing {
6namespace {
7
8} // namespace
9
12 decision.allowed = from.direction == GraphPinDirection::Output && to.direction == GraphPinDirection::Input &&
13 from.type == to.type && from.node != to.node;
14 if (!decision.allowed)
16 eve::DiagnosticCode::InvalidArgument, RuleId("editor.material.pin-type-mismatch"),
17 DiagnosticSeverity::Error,
18 "Material pins require matching types, output-to-input and distinct nodes"));
19 return decision;
20}
21
24 result.documentRevision = graph.revision;
25 if (graph.domain != domain()) {
26 result.status = EditorStatus::Rejected;
28 eve::DiagnosticCode::InvalidArgument, RuleId("editor.material.wrong-domain"),
29 DiagnosticSeverity::Error, "Graph is not a material domain document"));
30 return result;
31 }
32 const std::size_t outputs =
33 static_cast<std::size_t>(std::count_if(graph.nodes.begin(), graph.nodes.end(), [](const GraphNodeRecord& node) {
34 return node.type == "material.output";
35 }));
36 const bool errorNode = std::any_of(graph.nodes.begin(), graph.nodes.end(),
37 [](const GraphNodeRecord& node) { return node.type == "material.error"; });
38 if (outputs != 1 || errorNode) {
39 result.status = EditorStatus::Failed;
41 eve::DiagnosticCode::Failed, RuleId("editor.material.compile-failed"), DiagnosticSeverity::Error,
42 outputs != 1 ? "Material graph requires exactly one output node"
43 : "Material graph contains an invalid node"));
44 return result;
45 }
46 result.status = EditorStatus::Applied;
47 result.shaderArtifact = "material-shader:r" + std::to_string(graph.revision) + ":n" +
48 std::to_string(graph.nodes.size()) + ":e" + std::to_string(graph.edges.size());
49 return result;
50}
51
53 const MaterialGraphDomain& domain) {
54 if (document.empty())
55 return eve::editing::failed<TaskId>(EditorStatus::Rejected, RuleId("editor.material.missing-document"),
56 "Material document id is required");
57 TaskId task(document.value() + ".compile." + std::to_string(++taskSequence_));
58 tasks_.emplace(task, Task{document, domain.compile(graph), nullptr});
59 return eve::editing::applied<TaskId>(std::move(task));
60}
61
63 const MaterialGraphDomain& domain, TaskService& tasks) {
64 if (document.empty())
65 return eve::editing::failed<TaskId>(EditorStatus::Rejected, RuleId("editor.material.missing-document"),
66 "Material document id is required");
67 const MaterialGraphDomain domainCopy = domain;
68 auto queued = tasks.submit("Compile material " + document.value(), [graph = std::move(graph),
69 domainCopy](const TaskContext& context) {
70 TaskOutcome outcome;
71 if (context.isCancellationRequested()) {
72 outcome.status = EditorStatus::Cancelled;
73 return outcome;
74 }
75 context.reportProgress(0.25F);
76 const MaterialCompileResult compiled = domainCopy.compile(graph);
78 value["status"] = EditorValue(static_cast<std::int64_t>(compiled.status));
79 value["revision"] = EditorValue(static_cast<std::int64_t>(compiled.documentRevision));
80 value["artifact"] = EditorValue(compiled.shaderArtifact);
81 outcome.status = compiled.status;
82 outcome.output = EditorValue(std::move(value));
83 outcome.diagnostics = compiled.diagnostics;
84 context.reportProgress(1.0F);
85 return outcome;
86 });
87 if (!queued.ok()) return queued;
88 tasks_.emplace(queued.value(), Task{document, {}, &tasks});
89 return queued;
90}
91
92Result<void> MaterialEditorService::cancel(const TaskId& task) {
93 auto found = tasks_.find(task);
94 if (found == tasks_.end() || !found->second.service)
95 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.material.async-task-not-found"),
96 "Asynchronous material task does not exist");
97 return found->second.service->cancel(task);
98}
99
100Result<MaterialCompileResult> MaterialEditorService::result(const TaskId& task) const {
101 auto found = tasks_.find(task);
102 if (found == tasks_.end())
103 return eve::editing::failed<MaterialCompileResult>(
104 EditorStatus::NotFound, RuleId("editor.material.task-not-found"), "Material compile task does not exist");
105 if (found->second.service) {
106 const auto snapshot = found->second.service->snapshot(task);
107 if (!snapshot.ok())
108 return eve::editing::failed<MaterialCompileResult>(EditorStatus::NotFound,
109 RuleId("editor.material.task-not-found"),
110 "Material compile task does not exist");
111 if (snapshot.value().state == TaskState::Queued || snapshot.value().state == TaskState::Running)
113 MaterialCompileResult{}, eve::Status::success(EditorStatus::Pending));
114 MaterialCompileResult compiled;
115 compiled.diagnostics = snapshot.value().diagnostics;
116 if (snapshot.value().state == TaskState::Cancelled) {
117 compiled.status = EditorStatus::Cancelled;
118 return eve::editing::applied<MaterialCompileResult>(std::move(compiled));
119 }
120 const auto* object = snapshot.value().output.getIf<EditorValue::Object>();
121 if (!object)
122 return eve::editing::failed<MaterialCompileResult>(EditorStatus::Failed,
123 RuleId("editor.material.invalid-task-output"),
124 "Material worker returned an invalid result");
125 const auto status = object->find("status");
126 const auto revision = object->find("revision");
127 const auto artifact = object->find("artifact");
128 const auto* statusValue = status == object->end() ? nullptr : status->second.getIf<std::int64_t>();
129 const auto* revisionValue = revision == object->end() ? nullptr : revision->second.getIf<std::int64_t>();
130 const auto* artifactValue = artifact == object->end() ? nullptr : artifact->second.getIf<std::string>();
131 if (!statusValue || !revisionValue || !artifactValue)
132 return eve::editing::failed<MaterialCompileResult>(EditorStatus::Failed,
133 RuleId("editor.material.invalid-task-output"),
134 "Material worker result fields are invalid");
135 compiled.status = static_cast<EditorStatus>(*statusValue);
136 compiled.documentRevision = static_cast<Revision>(*revisionValue);
137 compiled.shaderArtifact = *artifactValue;
138 return eve::editing::applied<MaterialCompileResult>(std::move(compiled));
139 }
140 return eve::editing::applied<MaterialCompileResult>(found->second.result);
141}
142
143Result<void> MaterialEditorService::publishPreview(const DocumentId& document, Revision currentRevision,
144 const TaskId& task) {
145 auto found = tasks_.find(task);
146 if (found == tasks_.end() || found->second.document != document)
147 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.material.task-not-found"),
148 "Material compile task does not belong to this document");
149 const auto compileResult = result(task);
150 if (compileResult.code() == EditorStatus::Pending)
151 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.material.compile-pending"),
152 "Material compile task has not completed");
153 if (!compileResult.ok())
154 return eve::editing::failed<void>(EditorStatus::Failed, RuleId("editor.material.compile-result-unavailable"),
155 "Material compile result is unavailable");
156 const MaterialCompileResult& compiled = compileResult.value();
157 if (compiled.status != EditorStatus::Applied)
158 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.material.compile-not-successful"),
159 "Failed material output cannot replace the current preview");
160 if (compiled.documentRevision != currentRevision)
161 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.material.stale-compile"),
162 "Material changed after this compile task started");
163 previews_.insert_or_assign(document, compiled.shaderArtifact);
164 return eve::editing::applied<void>();
165}
166
167std::string MaterialEditorService::previewArtifact(const DocumentId& document) const {
168 auto found = previews_.find(document);
169 return found == previews_.end() ? std::string{} : found->second;
170}
171
172} // namespace eve::material_editing
double value
std::string from
wgpu::PopErrorScopeStatus status
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
size_t queued
Definition OnnxGpgpu.cpp:60
std::map< std::string, std::vector< std::string > > graph
Definition Package.cpp:59
std::uint64_t revision
const RoadNode * node
bool found
const VegetationPresetContext & context
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
const std::vector< Diagnostic > & diagnostics() const noexcept
Inspect all diagnostics; this counts as checking the Result.
Definition Result.h:283
const Status & status() const noexcept
Inspect the structured operation status.
Definition Result.h:269
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
Id128 public API.
Definition Identity.h:112
Cooperative cancellation and progress API passed to worker code.
Single-worker background queue shared by editor domains.
Result< TaskId > submit(std::string name, Work work)
Queue background work and return its stable task identity.
std::map< std::string, Value > Object
Result< TaskId > compile(const DocumentId &document, const GraphDocumentData &graph, const MaterialGraphDomain &domain)
Compile and cache a task result.
Result< TaskId > compileAsync(const DocumentId &document, GraphDocumentData graph, const MaterialGraphDomain &domain, TaskService &tasks)
Queue a cancellable compile using an immutable graph snapshot.
Minimal material domain with typed pin validation and deterministic compile artifacts.
std::string domain() const override
Domain.
GraphConnectionDecision canConnect(const GraphPinRecord &from, const GraphPinRecord &to) const override
Can connect.
MaterialCompileResult compile(const GraphDocumentData &graph) const
Compile a material graph without mutating preview state.
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
editing::Value EditorValue
StatusCode
Stable outcome category for an operation.
Definition Status.h:27
detail::StrongUint64< detail::RevisionTag > Revision
Monotonic content/state revision used for optimistic-concurrency checks.
Definition Revision.h:13
Result of domain-specific connection validation.
std::vector< Diagnostic > diagnostics
Immutable graph document value sent to a domain compiler.
Generic graph node independent of its domain.
Stable typed pin owned by a graph node.
Material graph compilation value; artifact is published separately.
std::vector< EditorDiagnostic > diagnostics