9#include "ecs/component/core/hierarchy.h"
10#include "ecs/component/core/transform.h"
12namespace Vkm::Engine::HierarchyOperations {
26void setParent(Scene& scene, EntityId child, EntityId parent, EntityId before = {});
36void removeFromParent(Scene& scene, EntityId entity);
47glm::mat4 computeWorldMatrix(
const Scene& scene, EntityId entity);
55constexpr uint32_t MAX_DEPTH = 32;
66void warnWalkBound(
const char* walk,
size_t bound);
83 SearchQueue(
const SearchQueue& other) =
delete;
84 SearchQueue& operator=(
const SearchQueue& other) =
delete;
86 SearchQueue(SearchQueue && other) =
delete;
87 SearchQueue& operator=(SearchQueue && other) =
delete;
90 std::vector<EntityId>& entries() {
return m_queue; }
93 std::vector<EntityId> m_queue;
110void forEachChild(
const Scene& scene, EntityId parent, Fn&& fn) {
111 const Hierarchy* node = scene.tryGet<Hierarchy>(parent);
114 const size_t bound = scene.entityCount();
116 for (EntityId child = node->firstChild; child; ++step) {
118 warnWalkBound(
"sibling-list walk", bound);
122 const Hierarchy* held = scene.tryGet<Hierarchy>(child);
123 const EntityId next = held ? held->nextSibling : EntityId{};
141void forSelfAndAncestors(
const Scene& scene, EntityId entity, Fn&& fn) {
142 EntityId at = entity;
143 for (uint32_t step = 0; at; ++step) {
144 if (step >= MAX_DEPTH) {
145 warnWalkBound(
"ancestor walk", MAX_DEPTH);
149 const Hierarchy* node = scene.tryGet<Hierarchy>(at);
166template<
typename Match>
167EntityId findInSelfOrDescendantsIf(
const Scene& scene, EntityId root, Match match) {
168 if (!root)
return {};
169 if (match(root))
return root;
171 detail::SearchQueue queue;
172 std::vector<EntityId>& pending = queue.entries();
173 pending.push_back(root);
174 const size_t bound = scene.entityCount();
175 for (
size_t i = 0; i < pending.size(); ++i) {
176 if (pending.size() > bound) {
177 warnWalkBound(
"breadth-first search", bound);
181 forEachChild(scene, pending[i], [&](EntityId child) {
182 if (!found && match(child)) found = child;
183 pending.push_back(child);
185 if (found)
return found;
201EntityId findInSelfOrDescendants(
const Scene& scene, EntityId root) {
202 return findInSelfOrDescendantsIf(scene, root, [&](EntityId
id) {
return scene.has<T>(id); });
214EntityId findInSelfOrAncestors(
const Scene& scene, EntityId leaf) {
216 forSelfAndAncestors(scene, leaf, [&](EntityId at) {
217 if (scene.has<T>(at)) found = at;
234inline bool isAncestorOf(
const Scene& scene, EntityId ancestor, EntityId node) {
235 if (!ancestor || !node || ancestor == node)
return false;
237 const Hierarchy* at = scene.tryGet<Hierarchy>(node);
238 for (
size_t step = 0; at && at->parent && step < scene.entityCount(); ++step) {
239 if (at->parent == ancestor)
return true;
240 at = scene.tryGet<Hierarchy>(at->parent);
253void destroyHierarchy(Scene& scene, EntityId entity);
267std::vector<EntityId> collectSubtree(
const Scene& scene, EntityId root);