47 using xfn = AffineTransform<T,N>;
48 using vecn = Vec<T,N>;
49 using rangen = Rect<T,N>;
50 using rayn = Ray<T,N>;
72 _transforms(transforms)
75 _conn_added = entt::sink{_transforms.hierarchy().on_added}
76 .template connect<&BoundsSystem::_on_child_added>(*
this);
77 _conn_removed = entt::sink{_transforms.hierarchy().on_removed}
78 .template connect<&BoundsSystem::_on_child_removed>(*
this);
79 _conn_changed = entt::sink{_transforms.hierarchy().on_changed}
80 .template connect<&BoundsSystem::_on_reparent>(*
this);
83 _conn_xf_set = entt::sink{_transforms.on_transform_set}
84 .template connect<&BoundsSystem::_on_transform_set>(*
this);
85 _conn_xf_removed = entt::sink{_transforms.on_transform_removed}
86 .template connect<&BoundsSystem::_on_transform_removed>(*
this);
87 _conn_xf_changed = entt::sink{_transforms.on_transform_changed}
88 .template connect<&BoundsSystem::_on_transform_changed>(*
this);
95 HierarchySystem<HTag>& hierarchy() {
return _transforms.hierarchy(); }
106 auto*
old = _reg.try_get<
IB>(eid);
110 if (
old->bounds != bounds) {
111 old->bounds = bounds;
112 _dirty_ancestors(eid);
116 _reg.emplace<
IB>(eid, bounds);
117 _dirty_ancestors(eid);
126 auto*
ib = _reg.try_get<
IB>(eid);
127 if (
ib)
return ib->bounds;
134 auto*
ib = _reg.try_get<
IB>(eid);
135 if (
not ib)
return std::nullopt;
136 rangen
old =
ib->bounds;
139 if (_transforms.hierarchy().
parent_of(eid) == entt::null
143 _computed.erase(eid);
145 _dirty_ancestors(eid);
163 if (_dirty.contains(eid)) {
164 return _recompute(eid);
166 auto it = _computed.find(eid);
167 if (
it != _computed.end())
return it->second;
191 template <TransformedTraversal<T,N> Traversal>
194 return entttree::walk::map_nodes(
195 std::forward<Traversal>(
t),
197 entt::entity eid =
n.node.node_id;
199 if (_dirty.contains(eid)) {
200 computed = _recompute(eid);
202 auto it = _computed.find(eid);
203 if (it != _computed.end()) computed = it->second;
207 get_intrinsic_bounds(eid),
224 template <BoundedTraversal<T,N> Traversal>
227 return entttree::walk::exclude_if(
228 entttree::walk::map_nodes(
229 std::forward<Traversal>(
t),
231 return {
n,
p /
n.node_to_root};
235 if (
not n.computed_bounds)
return true;
236 return n.computed_bounds->contains(
n.local_point);
260 auto g = entttree::walk::dfs(
266 if (
n.intrinsic_bounds
and n.intrinsic_bounds->contains(
n.local_point)) {
282 template <BoundedTraversal<T,N> Traversal>
285 return entttree::walk::exclude_if(
286 entttree::walk::map_nodes(
287 std::forward<Traversal>(
t),
289 rayn local_ray =
ray /
n.node_to_root;
290 if (
not n.computed_bounds) {
291 return {n, local_ray, Rect<T,1>::full};
293 rangen
box = *
n.computed_bounds;
294 auto interval =
box.intersect(local_ray);
295 return {
n, local_ray, interval};
299 return not n.interval.is_empty();
322 auto g = entttree::walk::dfs(
327 if (
g->interval.is_empty())
continue;
335 entt::registry& _reg;
342 entt::scoped_connection _conn_added;
343 entt::scoped_connection _conn_removed;
344 entt::scoped_connection _conn_changed;
345 entt::scoped_connection _conn_xf_set;
346 entt::scoped_connection _conn_xf_removed;
347 entt::scoped_connection _conn_xf_changed;
350 void _dirty_ancestors(entt::entity eid) {
354 entt::entity
cur = eid;
355 while (
cur != entt::null) {
363 std::optional<rangen> _recompute(entt::entity eid) {
364 rangen b = rangen::empty;
366 auto* ib = _reg.try_get<IB>(eid);
367 if (ib) b = ib->bounds;
369 for (
auto g = _transforms.hierarchy().
children(eid, SiblingOrder::Forward); g; ++g) {
370 entt::entity child = g->node_id;
371 rangen child_bound = rangen::empty;
373 if (_dirty.contains(child)) {
374 auto cb = _recompute(child);
375 if (cb) child_bound = *cb;
378 auto it = _computed.find(child);
379 if (it != _computed.end()) child_bound = it->second;
382 if (not child_bound.is_empty()) {
383 auto xf = _transforms.get_transform(child);
385 child_bound = ((*xf) * child_bound).bounds();
391 if (not b.is_empty()) {
392 _computed.insert_or_assign(eid, b);
394 _computed.erase(eid);
397 return b.is_empty() ? std::nullopt : std::optional{b};
405 void _on_child_added(entt::entity child, ParentConnection<HTag> pc) {
406 _dirty_ancestors(pc.parent);
409 void _on_child_removed(entt::entity child, ParentConnection<HTag> old_pc) {
410 _dirty_ancestors(old_pc.parent);
411 if (_transforms.hierarchy().
child_count(child) == 0
412 and not get_intrinsic_bounds(child))
420 ParentConnection<HTag> old_val,
421 ParentConnection<HTag> new_val)
423 if (old_val.parent != new_val.parent) {
424 _dirty_ancestors(old_val.parent);
425 _dirty_ancestors(child);
429 void _on_transform_set(entt::entity eid, xfn new_xf) {
430 _dirty_parent_after_transform_edit(eid);
433 void _on_transform_removed(entt::entity eid, xfn old_xf) {
434 _dirty_parent_after_transform_edit(eid);
437 void _on_transform_changed(entt::entity eid, xfn old_xf, xfn new_xf) {
438 _dirty_parent_after_transform_edit(eid);
441 void _dirty_parent_after_transform_edit(entt::entity eid) {
443 entt::entity parent = _transforms.hierarchy().
parent_of(eid);
444 if (parent != entt::null) {
445 _dirty_ancestors(parent);