entttree 0.1.0
Hierarchical entity management for EnTT
Loading...
Searching...
No Matches
transform_hierarchy.h
Go to the documentation of this file.
1
6#pragma once
7
8#include <type_traits>
9
10#include <entttree/hierarchy.h>
11
12namespace entttree {
13
14
29template <typename HTag, typename T=double, size_t N=2, typename XTag=HTag>
31
34
35 /****************************
36 * Typed signals
37 ****************************/
38
40 entt::sigh<void(entt::entity, xfn)> on_transform_set;
42 entt::sigh<void(entt::entity, xfn)> on_transform_removed;
44 entt::sigh<void(entt::entity, xfn, xfn)> on_transform_changed;
45
46 /****************************
47 * Construction
48 ****************************/
49
50 TransformSystem(entt::registry& reg, HierarchySystem<HTag>& hierarchy):
51 _reg(reg), _hierarchy(hierarchy) {}
52
53 TransformSystem(const TransformSystem&) = delete;
54 TransformSystem& operator=(const TransformSystem&) = delete;
55
56 HierarchySystem<HTag>& hierarchy() { return _hierarchy; }
57 const HierarchySystem<HTag>& hierarchy() const { return _hierarchy; }
58
59 /****************************
60 * Mutation API
61 ****************************/
62
64 void set_transform(entt::entity eid, xfn xf) {
65 auto* old = _reg.try_get<LT>(eid);
66 if (old) {
67 xfn old_xf = old->child_to_parent;
68 old->child_to_parent = xf;
69 if (old_xf != xf) {
70 on_transform_changed.publish(eid, old_xf, xf);
71 }
72 } else {
73 _reg.emplace<LT>(eid, xf);
74 on_transform_set.publish(eid, xf);
75 }
76 }
77
79 std::optional<xfn> get_transform(entt::entity eid) const {
80 auto* lt = _reg.try_get<LT>(eid);
81 if (lt) return lt->child_to_parent;
82 return std::nullopt;
83 }
84
86 std::optional<LT> remove_transform(entt::entity eid) {
87 auto* lt = _reg.try_get<LT>(eid);
88 if (not lt) return std::nullopt;
89 LT old = *lt;
90 _reg.erase<LT>(eid);
91 on_transform_removed.publish(eid, old.child_to_parent);
92 return old;
93 }
94
95 /****************************
96 * Queries
97 ****************************/
98
100 xfn object_to_world(entt::entity node) const {
101 xfn xf;
102 entt::entity cur = node;
103 while (cur != entt::null) {
104 auto* lt = _reg.try_get<LT>(cur);
105 if (lt) {
106 xf = lt->child_to_parent * xf;
107 }
108 cur = _hierarchy.parent_of(cur);
109 }
110 return xf;
111 }
112
113
120 xfn xf_between(entt::entity from_node, entt::entity to_node) const {
121 TreePath p0 = _hierarchy.path(from_node);
122 TreePath p1 = _hierarchy.path(to_node);
123
124 int common_root_depth = -1;
125 size_t n = std::min(p0.size(), p1.size());
126 for (size_t i = 0; i < n; ++i) {
127 if (p0[i] == p1[i]) {
129 } else {
130 break;
131 }
132 }
133
135 for (int i = common_root_depth + 1; i < (int) p0.size(); ++i) {
136 auto* lt = _reg.try_get<LT>(p0[i]);
137 if (lt) xf_to_p0 *= lt->child_to_parent;
138 }
139
141 for (int i = common_root_depth + 1; i < (int) p1.size(); ++i) {
142 auto* lt = _reg.try_get<LT>(p1[i]);
143 if (lt) xf_to_p1 *= lt->child_to_parent;
144 }
145
146 return xf_to_p0 / xf_to_p1;
147 }
148
149
150 /****************************
151 * Traversal
152 ****************************/
153
161 auto traverse(entt::entity root, SiblingOrder order) const {
163 _hierarchy.traverse(root, order),
164 [](const NodeEntry& n) { return n.node_id; }
165 );
166 }
167
168
177 template <AnyTraversalConcept Traversal, typename GetId>
179 using Node = typename TraversalValue<Traversal>::Node;
180 return make_traversal(
181 t.root
182 ? std::make_optional(
184 *std::forward<Traversal>(t).root,
185 {},
186 }
187 )
188 : std::nullopt,
189 [
190 this,
191 successors = std::forward<Traversal>(t).successors,
192 get_id
193 ] (TransformedNode<Node,T,N>& parent) -> Generator<TransformedNode<Node,T,N>> {
194 for (auto g = successors(parent.node); g; ++g) {
195 auto&& n = *g;
196 entt::entity child_id = get_id(n);
197 auto* lt = _reg.try_get<LT>(child_id);
199 std::move(n),
200 lt ? (parent.node_to_root * lt->child_to_parent)
201 : parent.node_to_root
202 };
203 }
204 }
205 );
206 }
207
208
209private:
210
211 entt::registry& _reg;
212 HierarchySystem<HTag>& _hierarchy;
213
214};
215
216
234template <typename XTag=void, typename T=double, size_t N=2, typename HTag>
235auto add_transforms(entt::registry& reg, HierarchySystem<HTag>& hierarchy) {
236 using LayerTag = std::conditional_t<std::is_void_v<XTag>, HTag, XTag>;
237 return TransformSystem<HTag,T,N,LayerTag>(reg, hierarchy);
238}
239
240
241template <typename HTag, typename XTag=HTag>
242using TransformSystem2d = TransformSystem<HTag, double, 2, XTag>;
243
244template <typename HTag, typename XTag=HTag>
245using TransformSystem3d = TransformSystem<HTag, double, 3, XTag>;
246
247
248} // namespace entttree
SiblingOrder
Controls the iteration order of siblings within a parent.
Definition defs.h:43
Core hierarchy system managing parent-child relationships over EnTT entities.
A C++20 coroutine-based generator that lazily yields values of type T.
Definition generator.h:34
A system for maintaining parent-child relationships on entities.
Definition hierarchy.h:37
entt::entity parent_of(entt::entity node) const
Returns the parent of node, or entt::null if the node is a root or not in the hierarchy.
Definition hierarchy.h:300
auto traverse(entt::entity root, SiblingOrder order) const
Returns a Traversal of the hierarchy rooted at root.
Definition hierarchy.h:396
TreePath path(entt::entity node) const
Returns the path from the root to the given node.
Definition hierarchy.h:428
size_t size() const
The number of non-root nodes in the hierarchy (i.e. entities with a parent).
Definition hierarchy.h:295
A node handle yielded by hierarchy traversals and queries.
A system for maintaining local affine transforms layered on a hierarchy.
auto traverse(entt::entity root, SiblingOrder order) const
Create a traversal which yields TransformedNode<NodeEntry,T,N>.
xfn object_to_world(entt::entity node) const
Compute the cumulative transform that positions node in the space of the root.
std::optional< xfn > get_transform(entt::entity eid) const
Get the local transform for an entity, or std::nullopt if none is set.
entt::sigh< void(entt::entity, xfn, xfn)> on_transform_changed
Emitted when an existing transform changes. Args: (entity, old_xf, new_xf).
xfn xf_between(entt::entity from_node, entt::entity to_node) const
Compute the transform from from_node's space to to_node's space.
auto augment_with_transforms(Traversal &&t, GetId &&get_id) const
Convert a traversal of Node to a traversal of TransformedNode<Node,T,N>.
std::optional< LT > remove_transform(entt::entity eid)
Remove the local transform for an entity. Returns the old component if it existed.
void set_transform(entt::entity eid, xfn xf)
Set the local (child-to-parent) transform for an entity.
entt::sigh< void(entt::entity, xfn)> on_transform_set
Emitted when a transform is first set on an entity. Args: (entity, new_xf).
entt::sigh< void(entt::entity, xfn)> on_transform_removed
Emitted when a transform is removed from an entity. Args: (entity, old_xf).
A traversal node augmented with a cumulative affine transform.
A lazy description of a rooted graph traversal.
Definition traverse.h:44
A path from a root entity down to a descendant.
auto add_transforms(entt::registry &reg, HierarchySystem< HTag > &hierarchy)
Construct a TransformSystem with deduced hierarchy tag and optional overrides.
std::remove_cvref_t< T > TraversalValue
Strip references/cv to get the bare Traversal type.
Definition traverse.h:86
auto make_traversal(std::optional< Node > &&root, Successors &&successors)
Construct a Traversal from an optional root and a successor function.
Definition traverse.h:164