载入中...
搜索中...
未找到
SceneEditingCommands.cpp
浏览该文件的文档.
3
4#include <cstdint>
5#include <set>
6
7namespace eve::scene_editing {
8namespace {
9
10const editing::Value* field(const editing::Value& value, const char* key) {
11 const auto* object = value.getIf<editing::Value::Object>();
12 if (!object) return nullptr;
13 const auto found = object->find(key);
14 return found == object->end() ? nullptr : &found->second;
15}
16
17bool assignVector3(const editing::Value& payload, const char* key, double& x, double& y, double& z) {
18 const editing::Value* entry = field(payload, key);
19 if (!entry) return true;
20 const auto* values = entry->getIf<editing::Value::Array>();
21 if (!values || values->size() != 3) return false;
22 const auto number = [](const editing::Value& value, double& output) {
23 if (const auto* real = value.getIf<double>()) {
24 output = *real;
25 return true;
26 }
27 if (const auto* integer = value.getIf<std::int64_t>()) {
28 output = static_cast<double>(*integer);
29 return true;
30 }
31 return false;
32 };
33 return number((*values)[0], x) && number((*values)[1], y) && number((*values)[2], z);
34}
35
36} // namespace
37
40 descriptor.id = editing::CommandId("scene.transform.set.v1");
41 descriptor.ownerModule = "scene_editing";
42 descriptor.displayName = "Set scene transform";
43 descriptor.category = "Scene";
44 descriptor.automationAllowed = true;
45 auto transformRegistered = registry.registerPlannedCommand(
47 auto* capability =
49 const editing::Value* objectValue = field(request.payload, "object");
50 const auto* object = objectValue ? objectValue->getIf<std::string>() : nullptr;
51 if (!capability || !object)
52 return eve::editing::failed<editing::CommandPlan>(
53 editing::Status::Rejected, editing::RuleId("scene.editing.transform-payload"),
54 "Scene transform requires a transform target and object id");
55 auto current = capability->readTransform(editing::ObjectId(*object));
56 if (!current.ok())
57 return eve::editing::failed<editing::CommandPlan>(current.code(),
58 editing::RuleId("scene.editing.transform-object"),
59 "Scene object transform is unavailable");
60 SceneTransformValue transform = current.value();
61 if (!assignVector3(request.payload, "position", transform.x, transform.y, transform.z) ||
62 !assignVector3(request.payload, "rotation", transform.rotationX, transform.rotationY,
63 transform.rotationZ) ||
64 !assignVector3(request.payload, "scale", transform.scaleX, transform.scaleY, transform.scaleZ))
65 return eve::editing::failed<editing::CommandPlan>(
66 editing::Status::Rejected, editing::RuleId("scene.editing.transform-vector"),
67 "Position, rotation and scale must contain three numbers");
68 auto operation = capability->makeSetTransform(editing::ObjectId(*object), transform);
69 if (!operation.ok())
70 return eve::editing::failed<editing::CommandPlan>(operation.code(),
71 editing::RuleId("scene.editing.transform-operation"),
72 "Scene target rejected the transform");
74 plan.operations.push_back(std::move(operation.value()));
75 plan.summary = editing::Value::Object{{"object", *object}};
76 return eve::editing::applied<editing::CommandPlan>(std::move(plan));
77 });
78 if (!transformRegistered.ok()) return transformRegistered;
80 batchTransform.id = editing::CommandId("scene.transform.batch.set.v1");
81 batchTransform.ownerModule = "scene_editing";
82 batchTransform.displayName = "Set scene transforms";
83 batchTransform.category = "Scene";
84 batchTransform.automationAllowed = true;
85 auto batchRegistered = registry.registerPlannedCommand(
86 std::move(batchTransform), [](editing::IEditableTarget& target, const editing::CommandRequest& request) {
87 auto capability = target.capability<ITransformEditTarget>();
88 const auto* values = field(request.payload, "transforms");
89 const auto* transforms = values ? values->getIf<editing::Value::Array>() : nullptr;
90 if (!capability || !transforms || transforms->empty())
91 return eve::editing::failed<editing::CommandPlan>(
92 editing::Status::Rejected, editing::RuleId("scene.editing.batch-transform-payload"),
93 "Batch transform requires a nonempty transforms array");
95 std::set<editing::ObjectId> ids;
96 for (const auto& value : *transforms) {
97 const auto* objectValue = field(value, "object");
98 const auto* object = objectValue ? objectValue->getIf<std::string>() : nullptr;
99 if (!object || object->empty() || !ids.emplace(*object).second)
100 return eve::editing::failed<editing::CommandPlan>(
101 editing::Status::Rejected, editing::RuleId("scene.editing.batch-transform-object"),
102 "Batch transform object ids must be nonempty and unique");
103 auto current = capability->get().readTransform(editing::ObjectId(*object));
105 auto transform = current.value();
106 if (!assignVector3(value, "position", transform.x, transform.y, transform.z) ||
107 !assignVector3(value, "rotation", transform.rotationX, transform.rotationY, transform.rotationZ) ||
108 !assignVector3(value, "scale", transform.scaleX, transform.scaleY, transform.scaleZ))
109 return eve::editing::failed<editing::CommandPlan>(
110 editing::Status::Rejected, editing::RuleId("scene.editing.batch-transform-vector"),
111 "Batch TRS vectors must contain three numbers");
112 auto operation = capability->get().makeSetTransform(editing::ObjectId(*object), transform);
114 plan.operations.push_back(std::move(operation.value()));
115 }
116 plan.summary = editing::Value::Object{{"count", static_cast<std::int64_t>(transforms->size())}};
117 return editing::applied<editing::CommandPlan>(std::move(plan));
118 });
119 if (!batchRegistered.ok()) return batchRegistered;
120 for (const std::string action : {"create", "delete", "rename", "reparent"}) {
122 entry.id = editing::CommandId("scene.object." + action + ".v1");
123 entry.ownerModule = "scene_editing";
124 entry.displayName = "Scene object " + action;
125 entry.category = "Scene";
126 auto registered = registry.registerPlannedCommand(
128 auto hierarchy = target.capability<ISceneHierarchyEditTarget>();
129 if (!hierarchy)
130 return eve::editing::failed<editing::CommandPlan>(
131 editing::Status::Unsupported, editing::RuleId("scene.editing.hierarchy-unavailable"),
132 "Target does not support scene hierarchy editing");
133 const auto* idValue = field(request.payload, "object");
134 const auto* id = idValue ? idValue->getIf<std::string>() : nullptr;
135 if (!id || id->empty())
136 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
137 editing::RuleId("scene.editing.object-required"),
138 "A nonempty object id is required");
139 const auto* nameValue = field(request.payload, "name");
140 const auto* name = nameValue ? nameValue->getIf<std::string>() : nullptr;
141 const auto* parentValue = field(request.payload, "parent");
142 const auto* parent = parentValue ? parentValue->getIf<std::string>() : nullptr;
143 if ((nameValue && !name) || (parentValue && !parent) || (action == "rename" && !name) ||
144 (action == "reparent" && !parent))
145 return eve::editing::failed<editing::CommandPlan>(
146 editing::Status::Rejected, editing::RuleId("scene.editing.hierarchy-payload"),
147 "Name and parent must be strings");
149 if (action == "delete") return hierarchy->get().makeDelete(editing::ObjectId(*id));
150 if (action == "rename") return hierarchy->get().makeRename(editing::ObjectId(*id), *name);
151 if (action == "reparent")
152 return hierarchy->get().makeReparent(editing::ObjectId(*id), editing::ObjectId(*parent));
154 create.id = editing::ObjectId(*id);
155 create.name = name ? *name : *id;
157 auto& t = create.transform;
158 if (!assignVector3(request.payload, "position", t.x, t.y, t.z) ||
159 !assignVector3(request.payload, "rotation", t.rotationX, t.rotationY, t.rotationZ) ||
160 !assignVector3(request.payload, "scale", t.scaleX, t.scaleY, t.scaleZ))
161 return eve::editing::failed<editing::DomainOperation>(
162 editing::Status::Rejected, editing::RuleId("scene.editing.create-vector"),
163 "TRS vectors require three numbers");
164 return hierarchy->get().makeCreate(create);
165 }();
168 plan.operations.push_back(std::move(operation.value()));
169 return editing::applied<editing::CommandPlan>(std::move(plan));
170 });
171 if (!registered.ok()) return registered;
172 }
174 update.id = editing::CommandId("scene.object.update.v1");
175 update.ownerModule = "scene_editing";
176 update.displayName = "Edit scene object properties";
177 update.category = "Scene";
178 auto updated = registry.registerPlannedCommand(
179 std::move(update),
182 auto hierarchy = target.capability<ISceneHierarchyEditTarget>();
183 auto transforms = target.capability<ITransformEditTarget>();
184 const auto* idValue = field(request.payload, "object");
185 const auto* id = idValue ? idValue->getIf<std::string>() : nullptr;
186 if (!hierarchy || !transforms || !id)
187 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
188 editing::RuleId("scene.editing.update-payload"),
189 "Scene object and editing capabilities are required");
190 auto current = transforms->get().readTransform(editing::ObjectId(*id));
192 auto t = current.value();
193 if (!assignVector3(request.payload, "position", t.x, t.y, t.z) ||
194 !assignVector3(request.payload, "rotation", t.rotationX, t.rotationY, t.rotationZ) ||
195 !assignVector3(request.payload, "scale", t.scaleX, t.scaleY, t.scaleZ))
196 return eve::editing::failed<editing::CommandPlan>(
197 editing::Status::Rejected, editing::RuleId("scene.editing.update-vector"), "Invalid TRS vector");
198 auto transform = transforms->get().makeSetTransform(editing::ObjectId(*id), t);
199 if (!transform.ok()) return editing::Result<editing::CommandPlan>::failure(transform.status());
201 plan.operations.push_back(std::move(transform.value()));
202 for (const auto* key : {"name", "parent"}) {
203 const auto* value = field(request.payload, key);
204 if (!value) continue;
205 const auto* text = value->getIf<std::string>();
206 if (!text)
207 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
208 editing::RuleId("scene.editing.update-text"),
209 "Name and parent must be strings");
210 auto operation = std::string_view(key) == "name"
211 ? hierarchy->get().makeRename(editing::ObjectId(*id), *text)
212 : hierarchy->get().makeReparent(editing::ObjectId(*id), editing::ObjectId(*text));
214 plan.operations.push_back(std::move(operation.value()));
215 }
216 return editing::applied<editing::CommandPlan>(std::move(plan));
217 });
218 if (!updated.ok()) return updated;
220 restore.id = editing::CommandId("scene.snapshot.restore.v1");
221 restore.ownerModule = "scene_editing";
222 restore.displayName = "Restore scene hierarchy and transforms";
223 restore.category = "Scene";
224 return registry.registerPlannedCommand(
225 std::move(restore),
228 auto* scene = dynamic_cast<SceneTargetBase*>(&value);
229 if (!scene)
230 return eve::editing::failed<editing::CommandPlan>(editing::Status::Unsupported,
231 editing::RuleId("scene.restore.target"),
232 "Target does not support scene snapshots");
233 auto operation = scene->makeRestore(request.payload);
236 plan.operations.push_back(std::move(operation.value()));
237 return editing::applied<editing::CommandPlan>(std::move(plan));
238 });
239}
240
241} // namespace eve::scene_editing
LogicalId target
ActionParameterOperation operation
double value
Value::Object payload
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
std::string output
std::string descriptor
std::map< std::string, Var > values
const GltfImportRequest & request
std::uint32_t key
glm::uvec4 ids
std::string text
std::int32_t parent
std::string name
std::array< std::uint64_t, kPixelChunkSize *kPixelChunkSize > updated
std::string action
Definition PlayHost.cpp:117
std::string id
Definition PlayHost.cpp:108
std::weak_ptr< PrimitiveScene > scene
float t
double number
bool found
double current
Json object
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
IEditableTarget public API.
Lower-layer registration boundary implemented by an editor or runtime editing host.
virtual Result< void > registerPlannedCommand(EditingCommandDescriptor descriptor, EditingCommandPlanner planner)=0
Register or replace one domain-owned planned command.
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.
Stable hierarchy capability implemented by document and runtime targets.
Definition SceneTarget.h:35
Capability implemented by document and live scene targets.
static editing::CapabilityId editingCapabilityId()
Editing capability id.
Shared in-memory scene target implementation for document/runtime adapters.
Definition SceneTarget.h:86
StrongId< ObjectIdTag > ObjectId
Definition EditingIds.h:65
StrongId< CommandIdTag > CommandId
Definition EditingIds.h:58
const EditorValue * field(const EditorValue &value, const char *name)
editing::Result< void > registerEditingCommands(editing::IEditingCommandRegistry &registry)
Register Scene-owned commands with a generic editing host.
CommandPlan public API.
std::vector< DomainOperation > operations
CommandRequest public API.
Domain-owned metadata for one planned editing command.
Request used to create a scene object in either backend.
Definition SceneTarget.h:27
Serializable transform exchanged across the scene editing boundary.