载入中...
搜索中...
未找到
EditorMaterialStudio.cpp
浏览该文件的文档.
2
3#include <cmath>
4#include <utility>
5
6namespace eve::editor {
7namespace {
8
9Result<void> noStudioChange() {
10 return eve::editing::noOp();
11}
12
13} // namespace
14
16 IEditorTransactionBackend& transactions,
18 : document_(std::move(document)),
19 target_(target),
20 transactions_(transactions),
21 previews_(previews),
22 renderer_(renderer) {}
23
25 settings_ = std::move(settings);
26 previewDirty_ = true;
27 return eve::editing::applied<void>();
28}
29
31 if (activeProperty_ || transactions_.active())
32 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.material.studio-interaction-active"),
33 "Finish or cancel the active material edit first");
34 const auto selection = selectionFor(target_.authoringTarget());
35 const auto descriptor = target_.authoringTarget().schema(selection).find(path);
36 if (!descriptor)
37 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.material.studio-property"),
38 "Material property is not present in the schema: " + path.value());
39 draft_ = std::make_unique<MaterialDocumentTarget>(target_.authoringTarget());
40 activeProperty_ = std::move(path);
41 finalValue_.reset();
42 diagnostics_.clear();
43 return eve::editing::applied<void>();
44}
45
47 if (!draft_ || !activeProperty_)
48 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.material.studio-no-interaction"),
49 "Begin a material interaction before updating it");
50 auto operation = draft_->makeSet(selectionFor(*draft_), *activeProperty_, value, PropertySetMode::Absolute);
51 if (!operation.ok()) {
52 diagnostics_ = operation.diagnostics();
53 return Result<void>::failure(operation.status());
54 }
55 auto applied = draft_->applyDomainOperation(operation.value());
56 if (!applied.ok()) {
57 diagnostics_ = applied.diagnostics();
58 return applied;
59 }
60 finalValue_ = std::move(value);
61 diagnostics_ = draft_->validate();
62 previewDirty_ = true;
63 return eve::editing::applied<void>();
64}
65
67 if (!draft_ || !activeProperty_ || !finalValue_)
68 return eve::editing::failed<TransactionReceipt>(EditorStatus::Rejected,
69 RuleId("editor.material.studio-no-final-value"),
70 "The material interaction has no value to commit");
71 auto operation = target_.authoringTarget().makeSet(selectionFor(target_.authoringTarget()), *activeProperty_,
72 *finalValue_, PropertySetMode::Absolute);
73 if (!operation.ok())
75 TransactionSpec specification;
76 specification.id = TransactionId("material-studio-" + std::to_string(++transactionSequence_));
77 specification.label = "Edit material " + activeProperty_->value();
78 specification.target = TargetId(target_.targetId());
79 specification.baseRevision = target_.revision();
80 specification.mergeKey = operation.value().mergeKey;
81 auto begun = transactions_.begin(std::move(specification));
82 if (!begun.ok())
83 return eve::editing::failed<TransactionReceipt>(begun.code(), RuleId("editor.material.studio-begin"),
84 "Could not begin the material transaction");
85 auto appended = transactions_.append(std::move(operation).takeValue());
86 if (!appended.ok()) {
87 [[maybe_unused]] auto discarded = transactions_.discard();
88 return eve::editing::failed<TransactionReceipt>(appended.code(), RuleId("editor.material.studio-append"),
89 "Could not append the material edit");
90 }
91 auto previewed = transactions_.preview();
92 if (!previewed.ok()) {
93 [[maybe_unused]] auto discarded = transactions_.discard();
94 return eve::editing::failed<TransactionReceipt>(previewed.code(), RuleId("editor.material.studio-preflight"),
95 "Material transaction preflight failed");
96 }
97 auto committed = transactions_.commit();
98 if (!committed.ok()) return committed;
99 clearInteraction();
100 previewDirty_ = true;
101 return committed;
102}
103
105 if (!draft_) return noStudioChange();
106 clearInteraction();
107 previewDirty_ = true;
108 diagnostics_ = target_.authoringTarget().validate();
109 return eve::editing::applied<void>();
110}
111
112Result<void> MaterialStudioController::tick(std::uint64_t monotonicMilliseconds) {
113 if (!previewDirty_) return noStudioChange();
114 if (hasPreviewTimestamp_ && monotonicMilliseconds < lastPreviewMilliseconds_)
115 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.material.studio-time-regressed"),
116 "Material preview time must be monotonic");
117 if (hasPreviewTimestamp_ && monotonicMilliseconds - lastPreviewMilliseconds_ < previewIntervalMilliseconds_)
118 return noStudioChange();
119 auto rendered = refreshPreview();
120 if (rendered.ok()) {
121 lastPreviewMilliseconds_ = monotonicMilliseconds;
122 hasPreviewTimestamp_ = true;
123 }
124 return rendered;
125}
126
128 return renderPreview(draft_ ? *draft_ : target_.authoringTarget());
129}
130
132 if (!std::isfinite(framesPerSecond) || framesPerSecond < 1.0 || framesPerSecond > 240.0)
133 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.material.studio-preview-rate"),
134 "Material preview rate must be between 1 and 240 Hz");
135 previewIntervalMilliseconds_ = static_cast<std::uint64_t>(std::ceil(1000.0 / framesPerSecond));
136 return eve::editing::applied<void>();
137}
138
140 MaterialStudioState result;
141 result.interactionActive = draft_ != nullptr;
142 result.previewDirty = previewDirty_;
143 result.activeProperty = activeProperty_.value_or(PropertyPath{});
144 result.documentRevision = target_.revision();
145 result.previewRevision = previewRevision_;
146 result.previewArtifact = previewArtifact_;
147 result.diagnostics = diagnostics_;
148 return result;
149}
150
151SelectionSnapshot MaterialStudioController::selectionFor(const MaterialDocumentTarget& material) const {
152 SelectionSnapshot selection;
153 selection.channel = "asset";
154 SelectionItem item;
155 item.domain = SelectionDomain::Asset;
156 item.target = TargetId(material.targetId());
157 item.item = StableId(material.targetId().value());
158 item.type = "graphics.material";
159 selection.items.push_back(item);
160 selection.primary = item;
161 return selection;
162}
163
164Result<void> MaterialStudioController::renderPreview(const MaterialDocumentTarget& material) {
165 auto task = previews_.render(document_, material, settings_, renderer_);
166 if (!task.ok()) {
167 diagnostics_ = task.diagnostics();
168 return eve::editing::failed<void>(task.code(), RuleId("editor.material.studio-preview"),
169 "Material preview request was rejected");
170 }
171 auto result = previews_.result(task.value());
172 if (!result.ok()) {
173 diagnostics_ = result.diagnostics();
174 return eve::editing::failed<void>(result.code(), RuleId("editor.material.studio-preview-result"),
175 "Material preview result is unavailable");
176 }
177 auto published = previews_.publish(document_, material.revision(), task.value());
178 diagnostics_ = result.value().diagnostics;
179 if (!published.ok()) {
180 diagnostics_.insert(diagnostics_.end(), published.diagnostics().begin(),
181 published.diagnostics().end());
182 return published;
183 }
184 previewArtifact_ = result.value().artifact;
185 previewRevision_ = material.revision();
186 previewDirty_ = false;
187 return eve::editing::applied<void>();
188}
189
190void MaterialStudioController::clearInteraction() {
191 draft_.reset();
192 activeProperty_.reset();
193 finalValue_.reset();
194}
195
196} // namespace eve::editor
LogicalId target
ActionParameterOperation operation
double value
std::string descriptor
std::string path
Definition PlayHost.cpp:110
Material * material
TerrainThermalSettings settings
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
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
Definition Identity.h:362
Dotted property path (layout.size) compared and persisted as text.
Definition EditingIds.h:78
Deterministic owning value tree shared by authoring hosts.
Transaction boundary consumed by editor property and other UI models.
virtual Result< void > discard()=0
Discard pending work after reverting any provisional preview.
virtual Result< TransactionReceipt > commit()=0
Publish the pending transaction and retain it for undo.
virtual Result< void > append(DomainOperation operation)=0
Append a serializable operation to the pending transaction.
virtual bool active() const noexcept=0
Whether a transaction is currently pending.
virtual Result< EditorDryRunReport > preview()=0
Validate the pending transaction without publishing target state.
virtual Result< TransactionId > begin(TransactionSpec specification)=0
Begin an explicit transaction without mutating its target.
Host boundary that owns creation and teardown of an isolated preview scene.
Revision-safe material preview request and publication service.
Result< MaterialPreviewRenderResult > result(const TaskId &task) const
Return one immutable render result.
Result< TaskId > render(const DocumentId &document, const MaterialDocumentTarget &material, MaterialPreviewSettings settings, IMaterialPreviewRenderer &renderer)
Validate and render a material snapshot in a unique isolated scene.
Result< void > publish(const DocumentId &document, Revision currentRevision, const TaskId &task)
Publish only a successful result matching the current document revision.
Result< void > beginInteraction(PropertyPath path)
Start one coalesced property gesture from the current live document revision.
Result< TransactionReceipt > commitInteraction()
Atomically publish the final draft value as one undoable transaction.
MaterialStudioController(DocumentId document, MaterialPublishingTarget &target, IEditorTransactionBackend &transactions, MaterialPreviewService &previews, IMaterialPreviewRenderer &renderer)
Material studio controller.
Result< void > setPreviewSettings(MaterialPreviewSettings settings)
Replace preview geometry, camera, resolution, and environment settings.
Result< void > tick(std::uint64_t monotonicMilliseconds)
Render a dirty preview when the injected monotonic time reaches the rate limit.
MaterialStudioState state() const
Return an owning snapshot suitable for any developer or in-game UI host.
Result< void > setPreviewRate(double framesPerSecond)
Set the maximum preview rate; valid range is 1 to 240 Hz.
Result< void > updateInteraction(EditorValue value)
Update the owned draft and mark its isolated preview dirty.
Result< void > refreshPreview()
Force an isolated preview of the current draft or live document.
Result< void > cancelInteraction()
Abandon the draft without changing the live material.
UI-neutral, serializable material authoring target.
PropertySchema schema(const SelectionSnapshot &selection) const override
Schema.
std::vector< EditorDiagnostic > validate() const
Validate cross-field authoring rules without mutating the target.
Result< DomainOperation > makeSet(const SelectionSnapshot &selection, const PropertyPath &path, const EditorValue &value, PropertySetMode mode) const override
Make set.
Candidate-first material operation target with live commit/undo publication.
std::uint64_t revision() const override
Revision.
MaterialDocumentTarget & authoringTarget()
Mutable authoring document used by property inspectors.
TargetId targetId() const override
Target id.
Result< void > noOp(std::vector< Diagnostic > diagnostics={})
Construct a successful void result for an operation that made no change.
eve::editing::StableId StableId
Definition EditorIds.h:36
material_editing::MaterialDocumentTarget MaterialDocumentTarget
eve::editing::TargetId TargetId
Definition EditorIds.h:29
eve::editing::RuleId RuleId
Definition EditorIds.h:32
eve::editing::TransactionId TransactionId
Definition EditorIds.h:34
PropertyDescriptorLookup find(const PropertyPath &path) const
Finds find.
SelectionItem public API.
SelectionSnapshot public API.
std::vector< SelectionItem > items
std::optional< SelectionItem > primary
TransactionSpec public API.
Camera, mesh and environment settings for an isolated material preview.
Observable state for a host-rendered real-time material studio.
std::vector< EditorDiagnostic > diagnostics