载入中...
搜索中...
未找到
DomainGizmoPreview.cpp
浏览该文件的文档.
2
6
7#include <algorithm>
8#include <cmath>
9
11namespace {
12
13const EditorValue* property(const EditorValue& snapshot, const char* path) {
14 const auto* root = snapshot.getIf<EditorValue::Object>();
15 if (!root) return nullptr;
16 const auto properties = root->find("properties");
17 if (properties == root->end()) return nullptr;
18 const auto* object = properties->second.getIf<EditorValue::Object>();
19 if (!object) return nullptr;
20 const auto found = object->find(path);
21 return found == object->end() ? nullptr : &found->second;
22}
23
24bool vector3(const EditorValue* value, std::array<double, 3>& output) {
25 const auto* array = value ? value->getIf<EditorValue::Array>() : nullptr;
26 if (!array || (array->size() != 2 && array->size() != 3)) return false;
27 output = {0.0, 0.0, 0.0};
28 for (std::size_t index = 0; index < array->size(); ++index) {
29 const auto* number = (*array)[index].getIf<double>();
30 if (!number || !std::isfinite(*number)) return false;
32 }
33 return true;
34}
35
36EditorGizmoSnapshot failure(const std::string& target, Revision revision,
37 const char* rule, std::string message) {
39 result.target = target; result.targetRevision = revision;
41 eve::DiagnosticCode::InvalidArgument, RuleId(rule), DiagnosticSeverity::Error,
42 std::move(message)));
43 return result;
44}
45
46} // namespace
47
50 result.target = target.targetId().value(); result.targetRevision = target.revision();
51 const EditorValue snapshot = target.snapshotValue();
52 const auto* kindValue = property(snapshot, "shape.kind");
53 const auto* kind = kindValue ? kindValue->getIf<std::string>() : nullptr;
54 EditorGizmoPrimitive primitive;
55 primitive.id = "collider";
56 if (!kind || !vector3(property(snapshot, "shape.offset"), primitive.position) ||
57 !vector3(property(snapshot, "shape.size"), primitive.size))
58 return failure(result.target, result.targetRevision, "editor.gizmo.invalid-collider",
59 "Collider snapshot lacks kind, offset or size");
60 const auto* sensorValue = property(snapshot, "shape.sensor");
61 const auto* sensor = sensorValue ? sensorValue->getIf<bool>() : nullptr;
62 primitive.color = sensor && *sensor ? std::array<double, 4>{0.2, 0.8, 1.0, 1.0}
63 : std::array<double, 4>{0.2, 1.0, 0.35, 1.0};
64 primitive.dashed = sensor && *sensor;
65 if (*kind == "box") primitive.kind = primitive.size[2] == 0.0 ? "wire-rect" : "wire-box";
66 else if (*kind == "circle" || *kind == "sphere") {
67 primitive.kind = *kind == "circle" ? "wire-circle" : "wire-sphere";
68 const auto* radius = property(snapshot, "shape.radius");
69 const auto* number = radius ? radius->getIf<double>() : nullptr;
70 if (!number) return failure(result.target, result.targetRevision, "editor.gizmo.invalid-radius", "Collider radius is invalid");
71 primitive.radius = *number;
72 } else if (*kind == "capsule") {
73 primitive.kind = "wire-capsule";
74 const auto* radiusValue = property(snapshot, "shape.radius"); const auto* heightValue = property(snapshot, "shape.capsule-height");
75 const auto* radius = radiusValue ? radiusValue->getIf<double>() : nullptr; const auto* height = heightValue ? heightValue->getIf<double>() : nullptr;
76 if (!radius || !height) return failure(result.target, result.targetRevision, "editor.gizmo.invalid-capsule", "Capsule dimensions are invalid");
77 primitive.radius = *radius; primitive.length = *height;
78 } else {
79 result.status = EditorStatus::Unsupported;
81 eve::DiagnosticCode::Unsupported, RuleId("editor.gizmo.complex-collider-asset"),
82 DiagnosticSeverity::Warning,
83 "Complex collider gizmo requires resolved asset geometry: " + *kind));
84 return result;
85 }
86 result.primitives.push_back(std::move(primitive)); result.status = EditorStatus::Applied;
87 return result;
88}
89
91 const ObjectPositionResolver& bodies) const {
92 EditorGizmoSnapshot result; result.target = target.targetId().value(); result.targetRevision = target.revision();
93 const EditorValue snapshot = target.snapshotValue();
94 const auto* bodyAValue = property(snapshot, "body.a"); const auto* bodyBValue = property(snapshot, "body.b");
95 const auto* bodyA = bodyAValue ? bodyAValue->getIf<std::string>() : nullptr;
96 const auto* bodyB = bodyBValue ? bodyBValue->getIf<std::string>() : nullptr;
97 std::array<double, 3> localA, localB, axis;
98 if (!bodyA || bodyA->empty() || !bodyB || bodyB->empty() || !bodies ||
99 !vector3(property(snapshot, "anchor.a"), localA) ||
100 !vector3(property(snapshot, "anchor.b"), localB) ||
101 !vector3(property(snapshot, "joint.axis"), axis))
102 return failure(result.target, result.targetRevision, "editor.gizmo.invalid-joint",
103 "Joint gizmo requires body references, anchors, axis and a position resolver");
104 auto originA = bodies(*bodyA); auto originB = bodies(*bodyB);
105 if (!originA.ok() || !originB.ok())
106 return failure(result.target, result.targetRevision, "editor.gizmo.joint-body-not-found",
107 "Joint gizmo could not resolve both body positions");
108 std::array<double, 3> anchorA, anchorB, line;
109 for (std::size_t i = 0; i < 3; ++i) {
110 anchorA[i] = originA.value().at(i) + localA[i];
111 anchorB[i] = originB.value().at(i) + localB[i];
112 line[i] = anchorB[i] - anchorA[i];
113 }
114 const double length = std::sqrt(line[0] * line[0] + line[1] * line[1] + line[2] * line[2]);
115 if (length > 1e-12) for (double& component : line) component /= length;
116 result.primitives.push_back({"anchor-a", "wire-sphere", anchorA, {}, {}, {1.0, 0.3, 0.2, 1.0}, 0.12, 0.0, false});
117 result.primitives.push_back({"anchor-b", "wire-sphere", anchorB, {}, {}, {0.2, 0.6, 1.0, 1.0}, 0.12, 0.0, false});
118 result.primitives.push_back({"joint-line", "line", anchorA, {}, line, {1.0, 0.85, 0.2, 1.0}, 0.0, length, false});
119 result.primitives.push_back({"joint-axis", "arrow", anchorA, {}, axis, {0.4, 1.0, 0.4, 1.0}, 0.0, 1.0, false});
120 const auto* enabledValue = property(snapshot, "limit.enabled"); const auto* enabled = enabledValue ? enabledValue->getIf<bool>() : nullptr;
121 if (enabled && *enabled) {
122 const auto* minimumValue = property(snapshot, "limit.minimum"); const auto* maximumValue = property(snapshot, "limit.maximum");
123 const auto* minimum = minimumValue ? minimumValue->getIf<double>() : nullptr; const auto* maximum = maximumValue ? maximumValue->getIf<double>() : nullptr;
124 if (minimum && maximum) result.primitives.push_back({"joint-limit", "arc", anchorA,
125 {*minimum, *maximum, 0.0}, axis, {1.0, 0.45, 0.1, 1.0}, 1.0, 0.0, true});
126 }
127 result.status = EditorStatus::Applied; return result;
128}
129
131 EditorGizmoSnapshot result; result.target = target.targetId().value(); result.targetRevision = target.revision();
132 const EditorValue snapshot = target.snapshotValue(); std::array<double, 3> position, direction;
133 const auto* referenceValue = property(snapshot, "spatial.reference-distance");
134 const auto* maximumValue = property(snapshot, "spatial.maximum-distance");
135 const auto* reference = referenceValue ? referenceValue->getIf<double>() : nullptr;
136 const auto* maximum = maximumValue ? maximumValue->getIf<double>() : nullptr;
137 if (!reference || !maximum || !vector3(property(snapshot, "spatial.position"), position) ||
138 !vector3(property(snapshot, "spatial.direction"), direction))
139 return failure(result.target, result.targetRevision, "editor.gizmo.invalid-audio-source",
140 "Audio source attenuation or transform is invalid");
141 result.primitives.push_back({"reference-distance", "wire-sphere", position, {}, {},
142 {0.2, 1.0, 0.5, 1.0}, *reference, 0.0, false});
143 result.primitives.push_back({"maximum-distance", "wire-sphere", position, {}, {},
144 {1.0, 0.55, 0.15, 0.75}, *maximum, 0.0, true});
145 result.primitives.push_back({"direction", "arrow", position, {}, direction,
146 {0.3, 0.7, 1.0, 1.0}, 0.0, std::max(1.0, *reference), false});
147 result.status = EditorStatus::Applied; return result;
148}
149
151 EditorGizmoSnapshot result; result.target = target.targetId().value(); result.targetRevision = target.revision();
152 const EditorValue snapshot = target.snapshotValue(); std::array<double, 3> position, direction;
153 const auto* typeValue = property(snapshot, "light.type"); const auto* type = typeValue ? typeValue->getIf<std::string>() : nullptr;
154 const auto* colorValue = property(snapshot, "light.color"); const auto* color = colorValue ? colorValue->getIf<EditorValue::Array>() : nullptr;
155 if (!type || !color || color->size() != 4 || !vector3(property(snapshot, "transform.position"), position) ||
156 !vector3(property(snapshot, "transform.direction"), direction))
157 return failure(result.target, result.targetRevision, "editor.gizmo.invalid-light", "Light type, color or transform is invalid");
158 std::array<double, 4> rgba;
159 for (std::size_t i = 0; i < 4; ++i) { const auto* number = (*color)[i].getIf<double>(); if (!number) return failure(result.target, result.targetRevision, "editor.gizmo.invalid-light-color", "Light color is invalid"); rgba[i] = *number; }
160 if (*type == "point") {
161 const auto* radiusValue = property(snapshot, "light.radius"); const auto* radius = radiusValue ? radiusValue->getIf<double>() : nullptr;
162 if (!radius) return failure(result.target, result.targetRevision, "editor.gizmo.invalid-light-radius", "Point light radius is invalid");
163 result.primitives.push_back({"light-volume", "wire-sphere", position, {}, {}, rgba, *radius, 0.0, false});
164 } else {
165 result.primitives.push_back({"light-direction", "arrow", position, {}, direction, rgba, 0.0, 4.0, false});
166 }
167 result.status = EditorStatus::Applied; return result;
168}
169
170} // namespace eve::domain_gizmo_editing
LogicalId target
double value
int root
Definition AnimSmr.cpp:119
std::string output
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
float length
Definition CaveMesh.cpp:94
std::string message
float maximum[3]
float minimum[3]
std::uint32_t height
TokenKind kind
std::array< float, 3 > position
std::map< std::string, PropertyRule > properties
std::uint64_t revision
float radius
std::string path
Definition PlayHost.cpp:110
RoadLaneDirection direction
double number
bool found
uint32_t index
Serializable audio-source authoring target independent of OpenAL handles.
Definition AudioTarget.h:19
std::function< Result< std::array< double, 3 > >(const std::string &)> ObjectPositionResolver
EditorGizmoSnapshot audioSource(const AudioSourceTarget &target) const
Build reference/max-distance spheres and source direction arrow.
EditorGizmoSnapshot light(const Light3DDocumentTarget &target) const
Build point-light radius or directional-light arrow overlay.
EditorGizmoSnapshot joint(const PhysicsJointTarget &target, const ObjectPositionResolver &bodies) const
Build body-anchor, connecting-line, axis and limit overlays for a joint.
EditorGizmoSnapshot collider(const PhysicsColliderTarget &target) const
Build a collider wire shape and sensor/body-state coloring.
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.
Serializable property target matching graphics::Light3D.
Serializable, backend-neutral 2D/3D collider authoring target.
Serializable joint authoring target using stable body references.
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
bool enabled
Renderer-neutral wire primitive for authoring viewport overlays.
std::array< double, 3 > size
std::array< double, 3 > position
std::array< double, 4 > color
Immutable revision-tagged overlay snapshot consumed by any viewport renderer.
std::vector< GizmoPrimitive > primitives
std::vector< Diagnostic > diagnostics
glm::vec4 color