载入中...
搜索中...
未找到
SceneHost.cpp
浏览该文件的文档.
1#include "scene/SceneHost.h"
2
3#include "scene/NodeDesc.h"
4
5#include <vector>
6
7namespace eve::scene {
8namespace {
9
10uint32_t g_anonHostSeq = 0;
11
12bool isAncestor(const SceneHost::Tree &tree, int ancestor, int node) {
13 for (int p = node; p >= 0; p = tree.nodes[size_t(p)].parent) {
14 if (p == ancestor) return true;
15 }
16 return false;
17}
18
19void unlinkFromParent(SceneHost::Tree &tree, int childIndex) {
20 SceneNode &child = tree.nodes[size_t(childIndex)];
21 const int parent = child.parent;
22 if (parent < 0) return;
23 SceneNode &p = tree.nodes[size_t(parent)];
24 if (p.firstChild == childIndex) {
25 p.firstChild = child.nextSibling;
26 } else {
27 for (int c = p.firstChild; c >= 0; c = tree.nodes[size_t(c)].nextSibling) {
28 if (tree.nodes[size_t(c)].nextSibling == childIndex) {
29 tree.nodes[size_t(c)].nextSibling = child.nextSibling;
30 break;
31 }
32 }
33 }
34 child.nextSibling = -1;
35 child.parent = -1;
36}
37
38void linkAsLastChild(SceneHost::Tree &tree, int parentIndex, int childIndex) {
39 SceneNode &parent = tree.nodes[size_t(parentIndex)];
40 SceneNode &child = tree.nodes[size_t(childIndex)];
41 child.parent = parentIndex;
42 child.nextSibling = -1;
43 if (parent.firstChild < 0) {
44 parent.firstChild = childIndex;
45 return;
46 }
47 int c = parent.firstChild;
48 while (tree.nodes[size_t(c)].nextSibling >= 0) c = tree.nodes[size_t(c)].nextSibling;
49 tree.nodes[size_t(c)].nextSibling = childIndex;
50}
51
53bool setLink(SceneNode &n, int kind, void *target, int syncMode) {
54 for (auto &l : n.links) {
55 if (l.kind == kind) {
56 l.target = target;
57 l.syncMode = syncMode;
58 return true;
59 }
60 }
61 n.links.push_back(SceneLink{kind, target, syncMode});
62 return true;
63}
64
65void forEachDepthFirstImpl(SceneHost *host, int nodeIndex, void (*fn)(SceneHost *, int, void *),
66 void *user) {
67 if (!host || nodeIndex < 0) return;
68 fn(host, nodeIndex, user);
69 auto t = host->tree();
70 for (int c = t->nodes[size_t(nodeIndex)].firstChild; c >= 0;
71 c = t->nodes[size_t(c)].nextSibling) {
72 forEachDepthFirstImpl(host, c, fn, user);
73 }
74}
75
76void walkDepthFirstImpl(SceneHost *host, int nodeIndex, const SceneHost::NodeVisitFn &fn) {
77 if (!host || nodeIndex < 0 || !fn) return;
78 auto t = host->tree();
79 if (nodeIndex >= int(t->nodes.size())) return;
80 fn(host, nodeIndex, t->nodes[size_t(nodeIndex)]);
81 for (int c = t->nodes[size_t(nodeIndex)].firstChild; c >= 0;
82 c = t->nodes[size_t(c)].nextSibling) {
83 walkDepthFirstImpl(host, c, fn);
84 }
85}
86
87void walkBreadthFirstImpl(SceneHost *host, int nodeIndex, const SceneHost::NodeVisitFn &fn) {
88 if (!host || nodeIndex < 0 || !fn) return;
89 auto t = host->tree();
90 if (nodeIndex >= int(t->nodes.size())) return;
91 std::vector<int> queue;
92 queue.push_back(nodeIndex);
93 for (size_t i = 0; i < queue.size(); ++i) {
94 const int idx = queue[i];
95 fn(host, idx, t->nodes[size_t(idx)]);
96 for (int c = t->nodes[size_t(idx)].firstChild; c >= 0;
97 c = t->nodes[size_t(c)].nextSibling) {
98 queue.push_back(c);
99 }
100 }
101}
102
103std::vector<std::string> splitPath(const std::string &path) {
104 std::vector<std::string> parts;
105 std::string cur;
106 for (char ch : path) {
107 if (ch == '/') {
108 if (!cur.empty()) {
109 parts.push_back(cur);
110 cur.clear();
111 }
112 } else {
113 cur.push_back(ch);
114 }
115 }
116 if (!cur.empty()) parts.push_back(cur);
117 return parts;
118}
119
120} // namespace
121
123 SceneHost *h = SceneHost::create();
124 h->meta()->entity = h;
125 if (name.empty()) {
126 h->meta()->name = "host" + std::to_string(++g_anonHostSeq);
127 } else {
128 h->meta()->name = name;
129 }
130 return h;
131}
132
133void SceneHost::setName(const std::string &name) { meta()->name = name; }
134
135const std::string &SceneHost::getName() { return meta()->name; }
136
137void SceneHost::setTree(NodeDesc root) { applyTree(this, std::move(root)); }
138
139bool SceneHost::setTreeReconcile(NodeDesc root) { return applyTreeReconcile(this, std::move(root)); }
140
141SceneNode *SceneHost::findById(const std::string &id) {
142 if (id.empty()) return nullptr;
143 auto t = tree();
144 for (auto &n : t->nodes) {
145 if (n.id == id) return &n;
146 }
147 return nullptr;
148}
149
150SceneNode *SceneHost::findByKey(const std::string &key) {
151 if (key.empty()) return nullptr;
152 auto t = tree();
153 for (auto &n : t->nodes) {
154 if (n.key == key) return &n;
155 }
156 return nullptr;
157}
158
160 const int idx = findIndexByName(name);
161 if (idx < 0) return nullptr;
162 return &tree()->nodes[size_t(idx)];
163}
164
165SceneNode *SceneHost::findByPath(const std::string &path) {
166 const int idx = findIndexByPath(path);
167 if (idx < 0) return nullptr;
168 return &tree()->nodes[size_t(idx)];
169}
170
171int SceneHost::findIndexById(const std::string &id) {
172 if (id.empty()) return -1;
173 auto t = tree();
174 if (!t->indexValid) {
175 t->idIndex.clear();
176 for (int i = 0; i < int(t->nodes.size()); ++i) {
177 const auto &nid = t->nodes[size_t(i)].id;
178 if (!nid.empty()) t->idIndex[nid] = i;
179 }
180 t->indexValid = true;
181 }
182 auto it = t->idIndex.find(id);
183 return it != t->idIndex.end() ? it->second : -1;
184}
185
186int SceneHost::findIndexByKey(const std::string &key) {
187 if (key.empty()) return -1;
188 auto t = tree();
189 for (int i = 0; i < int(t->nodes.size()); ++i) {
190 if (t->nodes[size_t(i)].key == key) return i;
191 }
192 return -1;
193}
194
195int SceneHost::findIndexByName(const std::string &name) {
196 if (name.empty()) return -1;
197 int found = -1;
198 walkDepthFirst([&](SceneHost *, int index, SceneNode &n) {
199 if (found >= 0) return;
200 if (n.name == name) found = index;
201 });
202 return found;
203}
204
205int SceneHost::findIndexByPath(const std::string &path) {
206 auto parts = splitPath(path);
207 if (parts.empty()) return -1;
208 auto t = tree();
209 if (t->root < 0) return -1;
210
211 int idx = t->root;
212 size_t start = 0;
213 if (t->nodes[size_t(idx)].id == parts[0] || t->nodes[size_t(idx)].name == parts[0]) {
214 start = 1;
215 }
216 for (size_t p = start; p < parts.size(); ++p) {
217 const std::string &want = parts[p];
218 int match = -1;
219 for (int child = t->nodes[size_t(idx)].firstChild; child >= 0;
220 child = t->nodes[size_t(child)].nextSibling) {
221 const SceneNode &n = t->nodes[size_t(child)];
222 if (n.id == want || n.name == want) {
223 match = child;
224 break;
225 }
226 }
227 if (match < 0) return -1;
228 idx = match;
229 }
230 return idx;
231}
232
233bool SceneHost::hasNode(const std::string &id) { return findIndexById(id) >= 0; }
234
235int SceneHost::getNodeCount() { return int(tree()->nodes.size()); }
236
237int SceneHost::getRootIndex() { return tree()->root; }
238
240 const int r = tree()->root;
241 if (r < 0) return nullptr;
242 return &tree()->nodes[size_t(r)];
243}
244
246 auto t = tree();
247 if (index < 0 || index >= int(t->nodes.size())) return nullptr;
248 return &t->nodes[size_t(index)];
249}
250
251int SceneHost::getParentIndex(int nodeIndex) {
252 auto t = tree();
253 if (nodeIndex < 0 || nodeIndex >= int(t->nodes.size())) return -1;
254 return t->nodes[size_t(nodeIndex)].parent;
255}
256
257SceneNode *SceneHost::getParent(int nodeIndex) { return getNode(getParentIndex(nodeIndex)); }
258
259SceneNode *SceneHost::getParentById(const std::string &id) { return getParent(findIndexById(id)); }
260
261int SceneHost::getChildCount(int nodeIndex) {
262 auto t = tree();
263 if (nodeIndex < 0 || nodeIndex >= int(t->nodes.size())) return 0;
264 int count = 0;
265 for (int c = t->nodes[size_t(nodeIndex)].firstChild; c >= 0;
266 c = t->nodes[size_t(c)].nextSibling) {
267 ++count;
268 }
269 return count;
270}
271
272int SceneHost::getChildCountById(const std::string &id) { return getChildCount(findIndexById(id)); }
273
274int SceneHost::getChildIndexAt(int parentIndex, int childOrdinal) {
275 if (childOrdinal < 0) return -1;
276 auto t = tree();
277 if (parentIndex < 0 || parentIndex >= int(t->nodes.size())) return -1;
278 int i = 0;
279 for (int c = t->nodes[size_t(parentIndex)].firstChild; c >= 0;
280 c = t->nodes[size_t(c)].nextSibling) {
281 if (i == childOrdinal) return c;
282 ++i;
283 }
284 return -1;
285}
286
287SceneNode *SceneHost::getChildAt(int parentIndex, int childOrdinal) {
288 return getNode(getChildIndexAt(parentIndex, childOrdinal));
289}
290
291SceneNode *SceneHost::getChildAtById(const std::string &parentId, int childOrdinal) {
292 return getChildAt(findIndexById(parentId), childOrdinal);
293}
294
295std::vector<int> SceneHost::getChildIndices(int nodeIndex) {
296 std::vector<int> out;
297 auto t = tree();
298 if (nodeIndex < 0 || nodeIndex >= int(t->nodes.size())) return out;
299 for (int c = t->nodes[size_t(nodeIndex)].firstChild; c >= 0;
300 c = t->nodes[size_t(c)].nextSibling) {
301 out.push_back(c);
302 }
303 return out;
304}
305
306std::vector<SceneNode *> SceneHost::getChildren(int nodeIndex) {
307 std::vector<SceneNode *> out;
308 for (int c : getChildIndices(nodeIndex)) out.push_back(&tree()->nodes[size_t(c)]);
309 return out;
310}
311
312std::vector<std::string> SceneHost::getChildIds(const std::string &parentId) {
313 std::vector<std::string> out;
314 for (SceneNode *n : getChildren(findIndexById(parentId))) {
315 if (n) out.push_back(n->id);
316 }
317 return out;
318}
319
320std::string SceneHost::getPath(int nodeIndex) {
321 auto t = tree();
322 if (nodeIndex < 0 || nodeIndex >= int(t->nodes.size())) return {};
323 std::vector<std::string> parts;
324 for (int i = nodeIndex; i >= 0; i = t->nodes[size_t(i)].parent) {
325 parts.push_back(t->nodes[size_t(i)].id);
326 }
327 std::string path;
328 for (int i = int(parts.size()) - 1; i >= 0; --i) {
329 if (!path.empty()) path += '/';
330 path += parts[size_t(i)];
331 }
332 return path;
333}
334
335std::string SceneHost::getPathById(const std::string &id) { return getPath(findIndexById(id)); }
336
337bool SceneHost::isAncestorOf(int ancestorIndex, int nodeIndex) {
338 auto t = tree();
339 if (ancestorIndex < 0 || nodeIndex < 0) return false;
340 if (ancestorIndex >= int(t->nodes.size()) || nodeIndex >= int(t->nodes.size())) return false;
341 return isAncestor(*t, ancestorIndex, nodeIndex);
342}
343
344bool SceneHost::isAncestorOfById(const std::string &ancestorId, const std::string &nodeId) {
345 return isAncestorOf(findIndexById(ancestorId), findIndexById(nodeId));
346}
347
348bool SceneHost::isDescendantOf(int nodeIndex, int ancestorIndex) {
349 return isAncestorOf(ancestorIndex, nodeIndex);
350}
351
352bool SceneHost::isDescendantOfById(const std::string &nodeId, const std::string &ancestorId) {
353 return isAncestorOfById(ancestorId, nodeId);
354}
355
356bool SceneHost::setParent(int childIndex, int parentIndex) {
357 auto t = tree();
358 if (childIndex < 0 || childIndex >= int(t->nodes.size())) return false;
359 if (parentIndex < -1 || parentIndex >= int(t->nodes.size())) return false;
360 if (childIndex == parentIndex) return false;
361 if (parentIndex >= 0 && isAncestor(*t, childIndex, parentIndex)) return false;
362
363 unlinkFromParent(*t, childIndex);
364 if (parentIndex < 0) {
365 t->nodes[size_t(childIndex)].parent = -1;
366 t->nodes[size_t(childIndex)].nextSibling = -1;
367 markSubtreeDirty(childIndex);
368 fireEvent("node_moved", t->nodes[size_t(childIndex)].id, "");
369 return true;
370 }
371 linkAsLastChild(*t, parentIndex, childIndex);
372 markSubtreeDirty(childIndex);
373 markSubtreeDirty(parentIndex);
374 fireEvent("node_moved", t->nodes[size_t(childIndex)].id,
375 t->nodes[size_t(parentIndex)].id);
376 return true;
377}
378
379bool SceneHost::addChild(int parentIndex, int childIndex) { return setParent(childIndex, parentIndex); }
380
381bool SceneHost::removeChild(int parentIndex, int childIndex) {
382 auto t = tree();
383 if (childIndex < 0 || childIndex >= int(t->nodes.size())) return false;
384 if (t->nodes[size_t(childIndex)].parent != parentIndex) return false;
385 unlinkFromParent(*t, childIndex);
386 markSubtreeDirty(childIndex);
387 markSubtreeDirty(parentIndex);
388 fireEvent("node_moved", t->nodes[size_t(childIndex)].id, "");
389 return true;
390}
391
392void SceneHost::markSubtreeDirty(int nodeIndex) {
393 auto t = tree();
394 if (nodeIndex < 0 || nodeIndex >= int(t->nodes.size())) return;
395 t->nodes[size_t(nodeIndex)].subtreeDirty = true;
396 t->nodes[size_t(nodeIndex)].localDirty = true;
397}
398
399void SceneHost::fireEvent(const std::string &action, const std::string &nodeId,
400 const std::string &parentId) {
401 if (eventHandler_) eventHandler_(this, action, nodeId, parentId);
402}
403
404void SceneHost::forEachDepthFirst(int nodeIndex, void (*fn)(SceneHost *, int, void *), void *user) {
405 forEachDepthFirstImpl(this, nodeIndex, fn, user);
406}
407
409
411 walkDepthFirstImpl(this, nodeIndex, fn);
412}
413
415 walkBreadthFirstFrom(tree()->root, std::move(fn));
416}
417
419 walkBreadthFirstImpl(this, nodeIndex, fn);
420}
421
422void SceneHost::walkChildren(int parentIndex, NodeVisitFn fn) {
423 if (!fn) return;
424 for (int c : getChildIndices(parentIndex)) {
425 fn(this, c, tree()->nodes[size_t(c)]);
426 }
427}
428
430 if (!fn) return;
431 auto t = tree();
432 if (nodeIndex < 0 || nodeIndex >= int(t->nodes.size())) return;
433 for (int p = t->nodes[size_t(nodeIndex)].parent; p >= 0; p = t->nodes[size_t(p)].parent) {
434 fn(this, p, t->nodes[size_t(p)]);
435 }
436}
437
438SceneNode *SceneHost::findIf(NodePredFn pred) { return findIfFrom(tree()->root, std::move(pred)); }
439
441 if (!pred) return nullptr;
442 SceneNode *found = nullptr;
443 walkDepthFirstFrom(nodeIndex, [&](SceneHost *host, int index, SceneNode &node) {
444 if (found) return;
445 if (pred(host, index, node)) found = &node;
446 });
447 return found;
448}
449
450std::vector<SceneNode *> SceneHost::filter(NodePredFn pred) {
451 return filterFrom(tree()->root, std::move(pred));
452}
453
454std::vector<SceneNode *> SceneHost::filterFrom(int nodeIndex, NodePredFn pred) {
455 std::vector<SceneNode *> out;
456 if (!pred) return out;
457 walkDepthFirstFrom(nodeIndex, [&](SceneHost *host, int index, SceneNode &node) {
458 if (pred(host, index, node)) out.push_back(&node);
459 });
460 return out;
461}
462
463std::vector<int> SceneHost::filterIndices(NodePredFn pred) {
464 return filterIndicesFrom(tree()->root, std::move(pred));
465}
466
467std::vector<int> SceneHost::filterIndicesFrom(int nodeIndex, NodePredFn pred) {
468 std::vector<int> out;
469 if (!pred) return out;
470 walkDepthFirstFrom(nodeIndex, [&](SceneHost *host, int index, SceneNode &node) {
471 if (pred(host, index, node)) out.push_back(index);
472 });
473 return out;
474}
475
476std::vector<SceneNode *> SceneHost::findAllByName(const std::string &name) {
477 return filter([&](SceneHost *, int, const SceneNode &n) { return n.name == name; });
478}
479
480std::vector<SceneNode *> SceneHost::findAllByKey(const std::string &key) {
481 return filter([&](SceneHost *, int, const SceneNode &n) { return n.key == key; });
482}
483
484std::vector<SceneNode *> SceneHost::findAllVisible(bool visible) {
485 return filter([&](SceneHost *, int, const SceneNode &n) { return n.visible == visible; });
486}
487
488std::vector<SceneNode *> SceneHost::findAllBySpace(const std::string &space) {
489 return filter([&](SceneHost *, int, const SceneNode &n) { return n.space == space; });
490}
491
492std::vector<SceneNode *> SceneHost::findAllLinked() {
493 return filter([&](SceneHost *, int, const SceneNode &n) {
494 return !n.links.empty();
495 });
496}
497
498std::vector<std::string> SceneHost::collectIds() { return collectIdsFrom(tree()->root); }
499
500std::vector<std::string> SceneHost::collectIdsFrom(int nodeIndex) {
501 std::vector<std::string> out;
502 walkDepthFirstFrom(nodeIndex, [&](SceneHost *, int, SceneNode &n) { out.push_back(n.id); });
503 return out;
504}
505
506std::vector<std::string> SceneHost::collectIdsWhere(NodePredFn pred) {
507 std::vector<std::string> out;
508 for (SceneNode *n : filter(std::move(pred))) {
509 if (n) out.push_back(n->id);
510 }
511 return out;
512}
513
514std::vector<std::string> SceneHost::collectIdsByName(const std::string &name) {
515 return collectIdsWhere([&](SceneHost *, int, const SceneNode &n) { return n.name == name; });
516}
517
518std::vector<std::string> SceneHost::collectIdsVisible(bool visible) {
519 return collectIdsWhere([&](SceneHost *, int, const SceneNode &n) { return n.visible == visible; });
520}
521
522bool SceneHost::link(const std::string &nodeId, int kind, void *target, int syncMode) {
523 if (!linkOps(kind)) return false; // kind's module is not in this build
524 SceneNode *n = findById(nodeId);
525 return n ? setLink(*n, kind, target, syncMode) : false;
526}
527
528// The typed helpers resolve their kind by name, so they return false rather
529// than crashing when the module that registers it was trimmed out.
530bool SceneHost::linkRenderable2D(const std::string &nodeId, graphics::Renderable2D *r) {
531 return link(nodeId, findLinkKind("renderable2d"), r, 0);
532}
533
534bool SceneHost::linkRenderable3D(const std::string &nodeId, graphics::Renderable3D *r) {
535 return link(nodeId, findLinkKind("renderable3d"), r, 0);
536}
537
538bool SceneHost::linkPhysics2D(const std::string &nodeId, physics::Body *b, int syncMode) {
539 return link(nodeId, findLinkKind("physics2d"), b, syncMode);
540}
541
542bool SceneHost::linkPhysics3D(const std::string &nodeId, physics::Body3D *b, int syncMode) {
543 return link(nodeId, findLinkKind("physics3d"), b, syncMode);
544}
545
546bool SceneHost::linkCamera3D(const std::string &nodeId, graphics::Camera3D *c) {
547 return link(nodeId, findLinkKind("camera3d"), c, 0);
548}
549
550bool SceneHost::linkAudio3D(const std::string &nodeId, audio::Source *s) {
551 return link(nodeId, findLinkKind("audio3d"), s, 0);
552}
553
554bool SceneHost::unlink(const std::string &nodeId, int kind) {
555 SceneNode *n = findById(nodeId);
556 if (!n) return false;
557 for (auto it = n->links.begin(); it != n->links.end(); ++it) {
558 if (it->kind == kind) {
559 n->links.erase(it);
560 return true;
561 }
562 }
563 return false;
564}
565
566bool SceneHost::unlink(const std::string &nodeId) {
567 SceneNode *n = findById(nodeId);
568 if (!n) return false;
569 n->links.clear();
570 return true;
571}
572
574 if (!node) return nullptr;
575 for (auto &l : node->links) {
576 if (l.kind == kind) return &l;
577 }
578 return nullptr;
579}
580
582 if (!node) return nullptr;
583 for (const auto &l : node->links) {
584 if (l.kind == kind) return &l;
585 }
586 return nullptr;
587}
588
589int SceneHost::linkCount(const std::string &nodeId) {
590 SceneNode *n = findById(nodeId);
591 return n ? int(n->links.size()) : 0;
592}
593
594bool SceneHost::setParentById(const std::string &childId, const std::string &parentId) {
595 const int childIndex = findIndexById(childId);
596 if (childIndex < 0) return false;
597 const int parentIndex = parentId.empty() ? -1 : findIndexById(parentId);
598 if (parentIndex < 0 && !parentId.empty()) return false;
599 return setParent(childIndex, parentIndex);
600}
601
602bool SceneHost::removeChildById(const std::string &parentId, const std::string &childId) {
603 const int parentIndex = findIndexById(parentId);
604 const int childIndex = findIndexById(childId);
605 if (parentIndex < 0 || childIndex < 0) return false;
606 return removeChild(parentIndex, childIndex);
607}
608
609bool SceneHost::addTag(SceneNode *node, const std::string &tag) {
610 if (!node || tag.empty()) return false;
611 for (const auto &t : node->tags) {
612 if (t == tag) return false;
613 }
614 node->tags.push_back(tag);
615 return true;
616}
617
618bool SceneHost::removeTag(SceneNode *node, const std::string &tag) {
619 if (!node) return false;
620 for (auto it = node->tags.begin(); it != node->tags.end(); ++it) {
621 if (*it == tag) {
622 node->tags.erase(it);
623 return true;
624 }
625 }
626 return false;
627}
628
629bool SceneHost::hasTag(const SceneNode *node, const std::string &tag) const {
630 if (!node) return false;
631 for (const auto &t : node->tags) {
632 if (t == tag) return true;
633 }
634 return false;
635}
636
637std::vector<SceneNode *> SceneHost::findAllByTag(const std::string &tag) {
638 return filter([&](SceneHost *, int, const SceneNode &n) {
639 for (const auto &t : n.tags) {
640 if (t == tag) return true;
641 }
642 return false;
643 });
644}
645
646} // namespace eve::scene
Tok kind
glm::vec3 n
Definition Grass.cpp:64
int h
uint32_t b
uint32_t c
int idx
glm::vec4 p[6]
const char * name
Definition RockMesh.cpp:21
std::string filter
SettlementPipeline::Stage fn
int parent
Definition TreeMesh.cpp:175
uint32_t s
Definition Weather.cpp:28
A playable audio source (static buffer or streaming decoder). Not thread-safe for playback control ex...
Definition Source.h:30
Default renderable entity for declarative 2D sprites / solid quads.
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create sh...
Definition Body3D.h:16
2D rigid body (Box2D) in pixel-space coordinates. Owned by a World; create shapes with newRectangleFi...
Definition Body.h:16
ECS mount point for one scene graph (full scene or nested subtree root). Isomorphic to eve::ui::UIHos...
Definition SceneHost.h:80
bool isDescendantOf(int nodeIndex, int ancestorIndex)
bool isAncestorOfById(const std::string &ancestorId, const std::string &nodeId)
std::vector< SceneNode * > getChildren(int nodeIndex)
void walkBreadthFirstFrom(int nodeIndex, NodeVisitFn fn)
bool isDescendantOfById(const std::string &nodeId, const std::string &ancestorId)
int findIndexByName(const std::string &name)
int findIndexById(const std::string &id)
void walkDepthFirstFrom(int nodeIndex, NodeVisitFn fn)
bool setParent(int childIndex, int parentIndex)
Imperative parent link. Returns false on invalid indices or cycle. Prefer declarative NodeDesc + reco...
void setTree(NodeDesc root)
Full replace.
bool removeChild(int parentIndex, int childIndex)
bool link(const std::string &nodeId, int kind, void *target, int syncMode=0)
Attach an external object to a node id. Survives reconcile/rebuild by id. After TransformSystem the l...
std::vector< int > filterIndices(NodePredFn pred)
bool removeChildById(const std::string &parentId, const std::string &childId)
int getChildIndexAt(int parentIndex, int childOrdinal)
Child ordinal 0..count-1; -1 if out of range.
bool setTreeReconcile(NodeDesc root)
Key-aware patch when structure matches; else full replace.
std::vector< SceneNode * > findAllBySpace(const std::string &space)
int getChildCountById(const std::string &id)
bool linkRenderable3D(const std::string &nodeId, graphics::Renderable3D *r)
bool linkPhysics3D(const std::string &nodeId, physics::Body3D *b, int syncMode=0)
bool isAncestorOf(int ancestorIndex, int nodeIndex)
std::vector< int > filterIndicesFrom(int nodeIndex, NodePredFn pred)
SceneNode * getChildAt(int parentIndex, int childOrdinal)
std::vector< std::string > collectIdsVisible(bool visible=true)
std::vector< SceneNode * > filterFrom(int nodeIndex, NodePredFn pred)
std::vector< std::string > getChildIds(const std::string &parentId)
std::function< bool(SceneHost *host, int index, const SceneNode &node)> NodePredFn
Definition SceneHost.h:190
std::vector< std::string > collectIdsFrom(int nodeIndex)
std::vector< std::string > collectIdsWhere(NodePredFn pred)
std::vector< std::string > collectIdsByName(const std::string &name)
void forEachDepthFirst(int nodeIndex, void(*fn)(SceneHost *, int, void *), void *user)
Depth-first visit of arena indices under nodeIndex (inclusive). C callback.
SceneNode * findIf(NodePredFn pred)
First DFS match; nullptr if none.
std::vector< SceneNode * > findAllLinked()
void setName(const std::string &name)
bool linkPhysics2D(const std::string &nodeId, physics::Body *b, int syncMode=0)
SceneNode * getParentById(const std::string &id)
std::string getPathById(const std::string &id)
int getParentIndex(int nodeIndex)
SceneNode * findByName(const std::string &name)
First node whose name equals name (DFS from root).
std::vector< int > getChildIndices(int nodeIndex)
void markSubtreeDirty(int nodeIndex)
Mark a node's subtree for world recompute (recompute it + descendants).
bool addChild(int parentIndex, int childIndex)
int findIndexByKey(const std::string &key)
bool addTag(SceneNode *node, const std::string &tag)
std::vector< std::string > collectIds()
SceneNode * findById(const std::string &id)
std::vector< SceneNode * > findAllVisible(bool visible=true)
static SceneHost * createHost(const std::string &name="")
void walkAncestors(int nodeIndex, NodeVisitFn fn)
Parent chain upward, excluding self.
std::vector< SceneNode * > filter(NodePredFn pred)
int findIndexByPath(const std::string &path)
std::vector< SceneNode * > findAllByTag(const std::string &tag)
SceneNode * getParent(int nodeIndex)
int linkCount(const std::string &nodeId)
bool hasTag(const SceneNode *node, const std::string &tag) const
SceneNode * findIfFrom(int nodeIndex, NodePredFn pred)
bool linkAudio3D(const std::string &nodeId, audio::Source *s)
SceneNode * findByKey(const std::string &key)
bool removeTag(SceneNode *node, const std::string &tag)
const std::string & getName()
bool unlink(const std::string &nodeId, int kind)
Remove all links of a kind; returns true if a link was removed.
std::string getPath(int nodeIndex)
Id path "a/b/c" from root to node; empty if invalid.
std::vector< SceneNode * > findAllByKey(const std::string &key)
void walkChildren(int parentIndex, NodeVisitFn fn)
Direct children only.
bool linkCamera3D(const std::string &nodeId, graphics::Camera3D *c)
std::function< void(SceneHost *host, int index, SceneNode &node)> NodeVisitFn
Definition SceneHost.h:189
void walkDepthFirst(NodeVisitFn fn)
DFS from root (or from nodeIndex), inclusive.
void walkBreadthFirst(NodeVisitFn fn)
BFS from root (or from nodeIndex), inclusive.
bool hasNode(const std::string &id)
SceneNode * findByPath(const std::string &path)
Path of ids joined by '/', e.g. "root/player/weapon". Relative to host root.
bool linkRenderable2D(const std::string &nodeId, graphics::Renderable2D *r)
std::vector< SceneNode * > findAllByName(const std::string &name)
SceneNode * getRoot()
SceneLink * findLink(SceneNode *node, int kind)
int getChildCount(int nodeIndex)
SceneNode * getChildAtById(const std::string &parentId, int childOrdinal)
SceneNode * getNode(int index)
void fireEvent(const std::string &action, const std::string &nodeId, const std::string &parentId={})
Fire "node_added" / "node_removed" / "node_moved" / "node_changed".
bool setParentById(const std::string &childId, const std::string &parentId)
Reparent by id; empty parentId detaches (parent = -1). Cycle-safe.
bool applyTreeReconcile(SceneHost *host, NodeDesc root)
Key-aware patch when structure matches; else full replace. Returns true if full rebuild.
Definition NodeDesc.cpp:294
NodeDesc node(std::string id, std::vector< NodeDesc > children, std::string name)
Definition NodeDesc.cpp:214
const LinkOps * linkOps(int kindId)
Definition SceneLink.cpp:47
int findLinkKind(const char *kind)
Definition SceneLink.cpp:39
void applyTree(SceneHost *host, NodeDesc root)
Definition NodeDesc.cpp:241
WidgetDesc child(std::string id, std::vector< WidgetDesc > children, float width, float height)
Scrollable child region with an explicit size.
Definition Widget.cpp:387
Declarative scene-node description (build once / on dirty → flatten into SceneHost::Tree)....
Definition NodeDesc.h:15
std::vector< std::string > tags
Definition NodeDesc.h:23
Retained scene node (arena). Conceptual GameObject; isomorphic to eve::ui::UINode.
Definition SceneHost.h:39