13 if (!
std::isfinite(
value)) return false;
15 if (!
std::isfinite(
value)) return false;
16 return std::isfinite(
bone.maskWeight) &&
bone.maskWeight >= 0.0 &&
bone.maskWeight <= 1.0;
19std::array<double, 3>
axis(
const std::array<double, 4>&
source,
int index) {
22 if (
length <= 1e-12)
return index == 0 ? std::array<double, 3>{1.0, 0.0, 0.0}
23 :
index == 1 ? std::array<double, 3>{0.0, 1.0, 0.0}
24 : std::array<double, 3>{0.0, 0.0, 1.0};
26 if (
index == 0)
return {1.0 - 2.0 * (
y *
y +
z *
z), 2.0 * (
x *
y +
w *
z),
27 2.0 * (
x *
z -
w *
y)};
28 if (
index == 1)
return {2.0 * (
x *
y -
w *
z), 1.0 - 2.0 * (
x *
x +
z *
z),
29 2.0 * (
y *
z +
w *
x)};
30 return {2.0 * (
x *
z +
w *
y), 2.0 * (
y *
z -
w *
x),
31 1.0 - 2.0 * (
x *
x +
y *
y)};
34std::array<double, 4>
color(
const SkeletonOverlayBone&
bone) {
35 std::array<double, 4> result{0.35, 0.7, 1.0, 1.0};
36 if (
bone.selected) result = {1.0, 0.78, 0.15, 1.0};
40 const double intensity = 0.25 + 0.75 *
bone.maskWeight;
47 editing::GizmoSnapshot result;
48 result.target = std::move(
target);
61 return failure(std::move(
target),
revision,
"editor.skeleton.overlay-empty",
62 "Skeleton overlay requires a target and at least one bone");
64 !std::isfinite(
options.jointRadius) ||
options.jointRadius <= 0.0 ||
66 return failure(std::move(
target),
revision,
"editor.skeleton.overlay-budget",
67 "Skeleton overlay exceeds its bone or geometry budget");
68 std::map<StableId, const SkeletonOverlayBone*> indexed;
71 return failure(std::move(
target),
revision,
"editor.skeleton.overlay-bone",
72 "Skeleton overlay contains duplicate, empty or non-finite bone data");
73 if (
bone.constrained &&
74 (
bone.minimumAngles[0] >
bone.maximumAngles[0] ||
75 bone.minimumAngles[1] >
bone.maximumAngles[1]))
76 return failure(std::move(
target),
revision,
"editor.skeleton.overlay-constraint",
77 "Skeleton constraint minimum exceeds maximum");
80 if (!
bone.parent.empty() && !indexed.contains(
bone.parent))
81 return failure(std::move(
target),
revision,
"editor.skeleton.overlay-parent",
82 "Skeleton bone references a missing parent: " +
bone.id.value());
83 std::set<StableId> ancestors;
86 if (!ancestors.insert(
current->id).second)
87 return failure(std::move(
target),
revision,
"editor.skeleton.overlay-cycle",
88 "Skeleton hierarchy contains a cycle");
98 result.
primitives.push_back({
bone.id.value() +
":joint",
"joint",
bone.position, {}, {},
101 if (!
bone.parent.empty()) {
104 double lengthSquared = 0.0;
109 const double length = std::sqrt(lengthSquared);
112 result.
primitives.push_back({
bone.id.value() +
":bone",
"bone-line",
118 DiagnosticSeverity::Warning,
"Bone has the same world position as its parent: " +
bone.name));
122 static const std::array<std::array<double, 4>, 3>
colors{{
123 {1.0, 0.2, 0.2, 1.0}, {0.2, 1.0, 0.2, 1.0}, {0.2, 0.45, 1.0, 1.0}}};
124 static const char* names[] = {
"x",
"y",
"z"};
128 0.0,
options.axisLength,
false});
131 result.
primitives.push_back({
bone.id.value() +
":constraint-yaw",
"constraint-arc",
133 {
bone.minimumAngles[0],
bone.maximumAngles[0], 0.0},
134 axis(
bone.rotation, 1), {1.0, 0.45, 0.1, 1.0},
135 options.axisLength, 0.0,
true});
136 result.
primitives.push_back({
bone.id.value() +
":constraint-pitch",
"constraint-arc",
138 {
bone.minimumAngles[1],
bone.maximumAngles[1], 0.0},
139 axis(
bone.rotation, 0), {0.8, 0.3, 1.0, 1.0},
140 options.axisLength, 0.0,
true});
143 result.status = EditorStatus::Applied;
std::vector< Bone > bones
std::array< float, 4 > rotation
std::array< float, 3 > position
std::vector< float > colors
RoadLaneDirection direction
const SquirrelValueOptions & options
const UnitySourceAsset & source
editing::GizmoSnapshot build(std::string target, Revision revision, const std::vector< SkeletonOverlayBone > &bones, const SkeletonOverlayOptions &options={}) const
Build a deterministic overlay or structured hierarchy/value diagnostics.
editing::Revision Revision
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
int axis(int64_t a, size_t rank)
Axis.
Immutable renderer-neutral world-space bone snapshot.
Overlay density, feature toggles and hard safety budgets.
Immutable revision-tagged overlay snapshot consumed by any viewport renderer.
std::vector< GizmoPrimitive > primitives
std::vector< Diagnostic > diagnostics