载入中...
搜索中...
未找到
DecalRuntime.cpp
浏览该文件的文档.
2
4
5#include <algorithm>
6#include <utility>
7
8namespace eve::decal_editing {
9namespace {
10
11double number(const DecalDocumentTarget& document, const char* path) {
12 return *document.value(path)->getIf<double>();
13}
14
15const EditorValue::Array& array(const DecalDocumentTarget& document, const char* path) {
16 return *document.value(path)->getIf<EditorValue::Array>();
17}
18
19Result<graphics::Texture*> resolve(const DecalDocumentTarget& document,
20 const IDecalRuntimeAssetResolver* assets, const char* path) {
21 const auto& name = *document.value(path)->getIf<std::string>();
22 if (name.empty()) return eve::editing::applied<graphics::Texture*>(nullptr);
23 if (!assets)
24 return eve::editing::failed<graphics::Texture*>(EditorStatus::Rejected, RuleId("editor.decal.assets"),
25 "Decal texture resolver is required");
26 return assets->texture(name);
27}
28
29} // namespace
30
32 if (!manager_)
33 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.decal.manager"),
34 "Live DecalManager is required");
35 const auto diagnostics = document.validate();
36 if (std::any_of(diagnostics.begin(), diagnostics.end(),
37 [](const auto& diagnostic) { return diagnostic.severity() == DiagnosticSeverity::Error; }))
38 return Result<void>::failure(eve::Status(EditorStatus::Rejected, diagnostics));
39
40 auto albedo = resolve(document, assets_, "texture.albedo");
41 if (!albedo.ok()) return Result<void>::failure(albedo.status());
42 auto normal = resolve(document, assets_, "texture.normal");
43 if (!normal.ok()) return Result<void>::failure(normal.status());
44 auto params = resolve(document, assets_, "texture.params");
45 if (!params.ok()) return Result<void>::failure(params.status());
46
47 decal::DecalInstance candidate;
48 const auto& position = array(document, "transform.position");
49 const auto& direction = array(document, "transform.normal");
50 const auto& uv = array(document, "texture.uvRect");
51 candidate.x = static_cast<float>(*position[0].getIf<double>());
52 candidate.y = static_cast<float>(*position[1].getIf<double>());
53 candidate.z = static_cast<float>(*position[2].getIf<double>());
54 candidate.nx = static_cast<float>(*direction[0].getIf<double>());
55 candidate.ny = static_cast<float>(*direction[1].getIf<double>());
56 candidate.nz = static_cast<float>(*direction[2].getIf<double>());
57 candidate.yaw = static_cast<float>(number(document, "transform.yaw"));
58 candidate.size = static_cast<float>(number(document, "projection.size"));
59 candidate.depth = static_cast<float>(number(document, "projection.depth"));
60 candidate.kind = *document.value("decal.kind")->getIf<std::string>();
61 candidate.albedo = albedo.value();
62 candidate.normal = normal.value();
63 candidate.params = params.value();
64 for (int index = 0; index < 4; ++index)
65 candidate.uvRect[index] = static_cast<float>(*uv[index].getIf<double>());
66 candidate.normalStrength = static_cast<float>(number(document, "channel.normal"));
67 candidate.roughnessStrength = static_cast<float>(number(document, "channel.roughness"));
68 candidate.metalStrength = static_cast<float>(number(document, "channel.metal"));
69 candidate.emissiveStrength = static_cast<float>(number(document, "channel.emissive"));
70 candidate.blendMode = *document.value("blend.mode")->getIf<std::string>() == "add" ? 1 : 0;
71 const auto& projectionMode = *document.value("projection.mode")->getIf<std::string>();
72 candidate.projectionMode = projectionMode == "triplanar" ? 1 : projectionMode == "spherical" ? 2 :
73 projectionMode == "world" ? 3 : 0;
74 candidate.blendSharpness = static_cast<float>(number(document, "projection.blendSharpness"));
75 candidate.parallaxScale = static_cast<float>(number(document, "projection.parallaxScale"));
76 candidate.parallaxMinLayers = static_cast<float>(number(document, "projection.parallaxMinLayers"));
77 candidate.parallaxMaxLayers = static_cast<float>(number(document, "projection.parallaxMaxLayers"));
78 candidate.edgeFadeWidth = static_cast<float>(number(document, "projection.edgeFadeWidth"));
79 candidate.lifetime = static_cast<float>(number(document, "lifetime.seconds"));
80 candidate.fadeIn = static_cast<float>(number(document, "lifetime.fadeIn"));
81 candidate.fadeOut = static_cast<float>(number(document, "lifetime.fadeOut"));
82
83 const int next = manager_->replace(runtimeId_, std::move(candidate));
84 if (next == 0)
85 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.decal.replace"),
86 "Decal runtime generation is stale or invalid");
87 runtimeId_ = next;
88 return eve::editing::applied<void>(diagnostics);
89}
90
92 if (runtimeId_ == 0) return eve::editing::noOp();
93 if (!manager_ || !manager_->remove(runtimeId_))
94 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.decal.runtime-stale"),
95 "Published decal generation no longer exists");
96 runtimeId_ = 0;
97 return eve::editing::applied<void>();
98}
99
101 if (staging_) return document_.applyDomainOperation(operation);
102 auto candidate = cloneDomainState();
103 auto applied = candidate->applyDomainOperation(operation);
104 if (!applied.ok()) return applied;
105 return commitDomainState(std::move(candidate));
106}
107
108std::unique_ptr<IDomainOperationTarget> DecalPublishingTarget::cloneDomainState() const {
109 auto candidate = std::make_unique<DecalPublishingTarget>(*this);
110 candidate->staging_ = true;
111 return candidate;
112}
113
115 std::unique_ptr<IDomainOperationTarget> candidate) {
116 auto* typed = dynamic_cast<DecalPublishingTarget*>(candidate.get());
117 if (!typed || typed->targetId() != targetId() || typed->sink_ != sink_ || !typed->staging_)
118 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.decal.publish-candidate"),
119 "Decal publishing candidate mismatch");
120 if (!sink_)
121 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.decal.publish-sink"),
122 "Decal publishing target requires a runtime sink");
123 auto published = sink_->publish(typed->document_);
124 if (!published.ok()) return published;
125 document_ = typed->document_;
126 return eve::editing::applied<void>();
127}
128
129} // namespace eve::decal_editing
ActionParameterOperation operation
float uv
graphics::Texture * albedo
std::array< float, 3 > position
std::string name
Texture * normal
std::string path
Definition PlayHost.cpp:110
RoadLaneDirection direction
double number
uint32_t index
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
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
int replace(int previousId, DecalInstance candidate)
Atomically install a fully configured instance and remove a previous generation.
bool remove(int id)
Removes .
Stable, serializable authoring document for one projected decal.
Definition DecalTarget.h:33
const EditorValue * value(const std::string &path) const
Read a renderer-neutral property by stable path.
Result< void > applyDomainOperation(const DomainOperation &operation) override
Applies domain operation.
std::vector< EditorDiagnostic > validate() const
Validate projection geometry, fades, UVs and texture-channel rules.
Candidate-first operation target synchronizing author state and a live decal.
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget > candidate) override
Commits domain state.
Result< void > applyDomainOperation(const DomainOperation &operation) override
Applies domain operation.
std::unique_ptr< IDomainOperationTarget > cloneDomainState() const override
Clones domain state.
TargetId targetId() const override
Target id.
Result< void > publish(const DecalDocumentTarget &document) override
Publish a complete replacement; failure preserves the previous generation.
Result< void > clear()
Remove the currently published generation, if any.
virtual Result< void > publish(const DecalDocumentTarget &document)=0
Publish a candidate while preserving runtime state on rejection.
std::vector< Value > Array
const T * getIf() const
Return an immediately borrowed typed value.
std::vector< ParamSpec > params
Result< void > noOp(std::vector< Diagnostic > diagnostics={})
Construct a successful void result for an operation that made no change.
One live decal instance (CPU-side state; GPU draw happens per frame).
graphics::Texture * normal
graphics::Texture * albedo
graphics::Texture * params
DomainOperation public API.