载入中...
搜索中...
未找到
SceneImportTarget.cpp
浏览该文件的文档.
2#include <algorithm>
3#include <utility>
5namespace {
6const EditorValue* field(const EditorValue& v, const char* k) {
7 auto* o = v.getIf<EditorValue::Object>();
8 if (!o) return nullptr;
9 auto i = o->find(k);
10 return i == o->end() ? nullptr : &i->second;
11}
12PropertyDescriptor prop(const char* p, PropertyType t, EditorValue d, const char* c) {
15 x.displayNameKey = std::string("editor.scene-import.") + p;
16 x.category = c;
17 x.type = t;
18 x.defaultValue = std::move(d);
19 x.flags = PropertyFlag::EditorOnly;
20 return x;
21}
22bool errors(const std::vector<EditorDiagnostic>& d) {
23 return std::any_of(d.begin(), d.end(), [](const auto& x) { return x.severity() == DiagnosticSeverity::Error; });
24}
25} // namespace
26SceneImportTarget::SceneImportTarget(std::string id) : id_(std::move(id)) {}
28 return {TargetId(id_),
29 "scene-import",
31 false,
32 {CapabilityId("eve.editor.target.scene-import-properties")}};
33}
35 return c == CapabilityId("eve.editor.target.scene-import-properties") ? static_cast<IPropertyProvider*>(this)
36 : nullptr;
37}
38bool SceneImportTarget::matches(const SelectionSnapshot& s) const {
39 return s.items.size() == 1 && s.items[0].target == TargetId(id_) && s.items[0].type == "scene-import";
40}
49 s.typeId = "scene-import";
50 s.properties = {prop("source", PropertyType::AssetRef, "", "source"),
51 prop("preset", PropertyType::Enum, "balanced", "source"),
52 prop("triangulate", PropertyType::Bool, true, "geometry"),
53 prop("generateNormals", PropertyType::Bool, true, "geometry"),
54 prop("joinVertices", PropertyType::Bool, true, "geometry"),
55 prop("flipUvs", PropertyType::Bool, true, "geometry"),
56 prop("improveCache", PropertyType::Bool, true, "geometry"),
57 prop("sharedMeshes", PropertyType::Bool, true, "runtime"),
58 prop("mipmaps", PropertyType::Bool, true, "runtime"),
59 prop("importLights", PropertyType::Bool, true, "content"),
60 prop("importCameras", PropertyType::Bool, false, "content"),
61 prop("importAnimations", PropertyType::Bool, true, "content")};
62 s.properties[0].assetTypeFilters = {"model3d", "scene"};
63 s.properties[1].enumItems = {"quality", "balanced", "mobile", "raw", "custom"};
64 return s;
65}
66EditorValue SceneImportTarget::contentValue() const {
67 return EditorValue::Object{{"source", value_.sourceAsset},
68 {"preset", value_.preset},
69 {"triangulate", value_.triangulate},
70 {"generateNormals", value_.generateNormals},
71 {"joinVertices", value_.joinVertices},
72 {"flipUvs", value_.flipUvs},
73 {"improveCache", value_.improveCache},
74 {"sharedMeshes", value_.sharedMeshes},
75 {"mipmaps", value_.mipmaps},
76 {"importLights", value_.importLights},
77 {"importCameras", value_.importCameras},
78 {"importAnimations", value_.importAnimations}};
79}
81 if (!matches(s)) return {};
82 const auto content = contentValue();
83 auto* v = field(content, p.value().c_str());
84 return v ? PropertyReadResult{PropertyReadState::Value, *v, {}} : PropertyReadResult{};
85}
87 const EditorValue& v, PropertySetMode mode) const {
88 if (mode == PropertySetMode::Reset) return makeReset(s, p);
89 auto d = schema(s).find(p);
90 if (!matches(s) || !d || mode != PropertySetMode::Absolute || !validatePropertyValue(*d, v).ok())
91 return eve::editing::failed<DomainOperation>(EditorStatus::Rejected, RuleId("editor.scene-import.set"),
92 "Scene import property edit is invalid");
93 EditorValue payload = contentValue();
94 auto& object = *payload.getIf<EditorValue::Object>();
95 object[p.value()] = v;
96 if (p == PropertyPath("preset")) {
97 const auto& name = *v.getIf<std::string>();
98 if (name != "custom") {
99 const bool raw = name == "raw", mobile = name == "mobile";
100 object["triangulate"] = true;
101 object["generateNormals"] = !raw;
102 object["joinVertices"] = !raw;
103 object["flipUvs"] = !raw;
104 object["improveCache"] = !raw;
105 object["sharedMeshes"] = !raw;
106 object["mipmaps"] = !raw;
107 object["importLights"] = !raw && !mobile;
108 object["importCameras"] = false;
109 object["importAnimations"] = !raw && !mobile;
110 }
111 } else
112 object["preset"] = "custom";
114 op.type = "scene-import.replace.v1";
115 op.inverseType = op.type;
116 op.target = TargetId(id_);
117 op.payload = std::move(payload);
118 op.inverse = contentValue();
119 op.hasInverse = true;
120 op.affectedProperties.push_back(p.value());
121 op.mergeKey = "scene-import:" + id_ + ":" + p.value();
122 return eve::editing::applied<DomainOperation>(std::move(op));
123}
125 auto d = schema(s).find(p);
126 if (!d)
127 return eve::editing::failed<DomainOperation>(EditorStatus::Unsupported, RuleId("editor.scene-import.property"),
128 "Unknown scene import property");
129 return makeSet(s, p, d->defaultValue, PropertySetMode::Absolute);
130}
131std::vector<EditorDiagnostic> SceneImportTarget::validate() const {
132 std::vector<EditorDiagnostic> d;
133 if (value_.sourceAsset.empty())
135 RuleId("editor.scene-import.source"), DiagnosticSeverity::Error, "Scene import requires a source asset"));
136 const auto presets = std::vector<std::string>{"quality", "balanced", "mobile", "raw", "custom"};
137 if (std::find(presets.begin(), presets.end(), value_.preset) == presets.end())
139 RuleId("editor.scene-import.preset"), DiagnosticSeverity::Error, "Unknown scene import preset"));
140 if (!value_.triangulate)
142 RuleId("editor.scene-import.non-triangles"), DiagnosticSeverity::Warning,
143 "Disabled triangulation may produce meshes unsupported by render backends"));
144 if (!value_.generateNormals)
146 RuleId("editor.scene-import.normals"), DiagnosticSeverity::Warning,
147 "Missing source normals will remain missing"));
148 return d;
149}
151 if (op.target != TargetId(id_) || op.type != "scene-import.replace.v1" || !op.payload.isWithinLimits(3, 32, 4096))
152 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.scene-import.operation"),
153 "Scene import operation is invalid");
155 const auto * s = field(op.payload, "source"), *p = field(op.payload, "preset");
156 auto* ss = s ? s->getIf<std::string>() : nullptr;
157 auto* ps = p ? p->getIf<std::string>() : nullptr;
158 if (!ss || !ps)
159 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.scene-import.payload"),
160 "Scene import source or preset is invalid");
161 v.sourceAsset = *ss;
162 v.preset = *ps;
163 bool* dst[] = {&v.triangulate, &v.generateNormals, &v.joinVertices, &v.flipUvs, &v.improveCache,
164 &v.sharedMeshes, &v.mipmaps, &v.importLights, &v.importCameras, &v.importAnimations};
165 const char* keys[] = {"triangulate", "generateNormals", "joinVertices", "flipUvs", "improveCache",
166 "sharedMeshes", "mipmaps", "importLights", "importCameras", "importAnimations"};
167 for (int i = 0; i < 10; ++i) {
168 auto* x = field(op.payload, keys[i]);
169 auto* b = x ? x->getIf<bool>() : nullptr;
170 if (!b)
171 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.scene-import.boolean"),
172 "Scene import option is invalid");
173 *dst[i] = *b;
174 }
175 SceneImportTarget c(id_);
176 c.value_ = v;
177 if (errors(c.validate()))
178 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.scene-import.invalid"),
179 "Scene import settings validation failed");
180 value_ = std::move(v);
181 bumpRevision();
182 widenDirty(0, 0);
183 return eve::editing::applied<void>();
184}
185std::unique_ptr<IDomainOperationTarget> SceneImportTarget::cloneDomainState() const {
186 return std::make_unique<SceneImportTarget>(*this);
187}
188Result<void> SceneImportTarget::commitDomainState(std::unique_ptr<IDomainOperationTarget> c) {
189 auto* t = dynamic_cast<SceneImportTarget*>(c.get());
190 if (!t || t->id_ != id_)
191 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.scene-import.candidate"),
192 "Scene import candidate mismatch");
193 *this = *t;
194 return eve::editing::applied<void>();
195}
197 return EditorValue::Object{{"schemaVersion", int64_t{1}}, {"content", contentValue()}};
198}
200 auto *v = field(s, "schemaVersion"), *c = field(s, "content");
201 auto* n = v ? v->getIf<int64_t>() : nullptr;
202 if (!n || *n != 1 || !c)
203 return eve::editing::failed<void>(EditorStatus::Unsupported, RuleId("editor.scene-import.snapshot"),
204 "Unsupported scene import snapshot");
206 op.target = TargetId(id_);
207 op.type = "scene-import.replace.v1";
208 op.payload = *c;
209 auto result = applyDomainOperation(op);
210 if (result.ok()) clearDirtyRegion();
211 return result;
212}
213} // namespace eve::sceneloader_editing
Value::Object payload
float x
Definition AnimClip.cpp:738
const std::string & s
glm::vec4 p[6]
glm::vec3 n
Definition Grass.cpp:63
float v
std::int32_t c
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
std::uint32_t mobile
std::string id
Definition PlayHost.cpp:108
float d
float t
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
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
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
void bumpRevision()
Advance the revision without touching the dirty region.
Revision revisionValue() const noexcept
Return the revision as the shared protocol revision type.
void widenDirty()
Mark an unknown area dirty without advancing the revision.
virtual void clearDirtyRegion()=0
Clears dirty region.
UI-independent property access for an immutable selection snapshot.
Dotted property path (layout.size) compared and persisted as text.
Definition EditingIds.h:78
Deterministic owning value tree shared by authoring hosts.
bool isWithinLimits(size_t maxDepth, size_t maxElements, size_t maxStringBytes) const
Validate nesting, element count and approximate string byte limits.
std::map< std::string, Value > Object
const T * getIf() const
Return an immediately borrowed typed value.
EVENGINE_API_ORCHESTRATION public API.
PropertySchema schema(const SelectionSnapshot &) const override
Schema.
Result< DomainOperation > makeReset(const SelectionSnapshot &, const PropertyPath &) const override
Make reset.
eve::Result< eve::Revision > currentRevision(const SelectionSnapshot &) const override
Current revision.
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget >) override
Commits domain state.
Result< void > loadSnapshot(const EditorValue &)
Loads snapshot.
void * queryCapability(const CapabilityId &) override
Query an optional stable editing capability.
TargetDescriptor describe() const override
Describe.
Result< void > applyDomainOperation(const DomainOperation &) override
Applies domain operation.
Result< DomainOperation > makeSet(const SelectionSnapshot &, const PropertyPath &, const EditorValue &, PropertySetMode) const override
Make set.
SceneImportTarget(std::string id)
Scene import target.
std::vector< EditorDiagnostic > validate() const
Validate.
PropertyReadResult read(const SelectionSnapshot &, const PropertyPath &) const override
Reads .
std::unique_ptr< IDomainOperationTarget > cloneDomainState() const override
Clones domain state.
EditorValue snapshotValue() const
Snapshot value.
editing::PropertyDescriptor PropertyDescriptor
editing::PropertyPath PropertyPath
StrongId< TargetIdTag > TargetId
Definition EditingIds.h:57
PropertyType
PropertyType public API.
StrongId< RuleIdTag > RuleId
Definition EditingIds.h:60
PropertySetMode
PropertySetMode public API.
StrongId< CapabilityIdTag > CapabilityId
Definition EditingIds.h:61
Result< void > validatePropertyValue(const PropertyDescriptor &descriptor, const Value &value)
Validate property value.
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
const EditorValue * field(const EditorValue &value, const char *name)
DomainOperation public API.
std::vector< std::string > affectedProperties
PropertyReadResult public API.
EVENGINE_API_PLATFORM public API.
PropertyDescriptorLookup find(const PropertyPath &path) const
Finds find.
SelectionSnapshot public API.
Stable discovery metadata exposed by every editable target.
Renderer-neutral persisted scene importer settings.