载入中...
搜索中...
未找到
TransformSystem.cpp
浏览该文件的文档.
2
3#include "scene/SceneHost.h"
4#include "scene/SceneLink.h"
5
6#include <cmath>
7#include <glm/gtc/matrix_transform.hpp>
8#include <glm/gtc/quaternion.hpp>
9
10namespace eve::scene {
11namespace {
12
13glm::mat4 localMatrix(const SceneNode &n) {
14 glm::mat4 m(1.f);
15 m = glm::translate(m, glm::vec3(n.x, n.y, n.z));
16 if (n.space == "2d") {
17 m = glm::rotate(m, n.roll, glm::vec3(0.f, 0.f, 1.f));
18 } else {
19 m = glm::rotate(m, n.yaw, glm::vec3(0.f, 1.f, 0.f));
20 m = glm::rotate(m, n.pitch, glm::vec3(1.f, 0.f, 0.f));
21 m = glm::rotate(m, n.roll, glm::vec3(0.f, 0.f, 1.f));
22 }
23 m = glm::scale(m, glm::vec3(n.sx, n.sy, n.sz));
24 return m;
25}
26
27void updateNode(SceneHost::Tree &tree, int nodeIndex, const glm::mat4 &parentWorld) {
28 SceneNode &n = tree.nodes[size_t(nodeIndex)];
29 n.world = parentWorld * localMatrix(n);
30 n.localDirty = false;
31 for (int c = n.firstChild; c >= 0; c = tree.nodes[size_t(c)].nextSibling) {
32 updateNode(tree, c, n.world);
33 }
34}
35
37void pullTargets(SceneHost *host) {
38 if (!host) return;
39 auto t = host->tree();
40 for (size_t i = 0; i < t->nodes.size(); ++i) {
41 SceneNode &n = t->nodes[i];
42 for (auto &l : n.links) {
43 if (l.syncMode != 1 || !l.target) continue;
44 const LinkOps *ops = linkOps(l.kind);
45 if (!ops || !ops->pullWorld) continue;
46 ops->pullWorld(n, l.target);
47 host->markSubtreeDirty(int(i));
48 }
49 }
50}
51
53void pushTarget(const SceneNode &n, const SceneLink &l);
54void updateNodeIncremental(SceneHost::Tree &tree, int nodeIndex,
55 const glm::mat4 &parentWorld, bool force) {
56 SceneNode &n = tree.nodes[size_t(nodeIndex)];
57 const bool need = force || n.subtreeDirty;
58 if (need) {
59 n.world = parentWorld * localMatrix(n);
60 n.localDirty = false;
61 n.subtreeDirty = false;
62 for (auto &l : n.links) {
63 if (l.syncMode == 0) pushTarget(n, l);
64 }
65 }
66 for (int c = n.firstChild; c >= 0; c = tree.nodes[size_t(c)].nextSibling) {
67 updateNodeIncremental(tree, c, n.world, need);
68 }
69}
70
72void pushTarget(const SceneNode &n, const SceneLink &l) {
73 if (!l.target) return;
74 const LinkOps *ops = linkOps(l.kind);
75 if (ops) ops->pushWorld(n, l.target);
76}
77
78void syncLinks(SceneHost *host) {
79 if (!host) return;
80 auto t = host->tree();
81 for (auto &n : t->nodes) {
82 for (auto &l : n.links) {
83 if (l.syncMode == 0) pushTarget(n, l);
84 }
85 }
86}
87
93bool linkTargetAlive(const SceneLink &l) {
94 if (!l.target) return false;
95 const LinkOps *ops = linkOps(l.kind);
96 if (!ops || !ops->alive) return true;
97 return ops->alive(l.target);
98}
99
101void purgeDeadLinks(SceneHost::Tree &tree) {
102 for (auto &n : tree.nodes) {
103 for (auto it = n.links.begin(); it != n.links.end();) {
104 if (linkTargetAlive(*it)) {
105 ++it;
106 } else {
107 it = n.links.erase(it);
108 }
109 }
110 }
111}
112
113} // namespace
114
116 if (!host) return;
117 auto t = host->tree();
118 if (t->root < 0 || t->nodes.empty()) {
119 t->transformDirty = false;
120 return;
121 }
122 purgeDeadLinks(*t);
123 pullTargets(host);
124
125 // Legacy coarse path: tree-level transformDirty or direct localDirty writes
126 // without subtree marking → full recompute + full link sync.
127 bool legacy = t->transformDirty;
128 if (!legacy) {
129 for (const auto &n : t->nodes) {
130 if (n.localDirty && !n.subtreeDirty) {
131 legacy = true;
132 break;
133 }
134 }
135 }
136 if (legacy) {
137 updateNode(*t, t->root, glm::mat4(1.f));
138 syncLinks(host);
139 for (auto &n : t->nodes) {
140 n.localDirty = false;
141 n.subtreeDirty = false;
142 }
143 t->transformDirty = false;
144 return;
145 }
146
147 // Incremental: only dirty subtrees recomputed, only their links synced.
148 bool anySubtree = false;
149 for (const auto &n : t->nodes) {
150 if (n.subtreeDirty) {
151 anySubtree = true;
152 break;
153 }
154 }
155 if (!anySubtree) {
156 t->transformDirty = false;
157 return; // fully clean tree: zero work
158 }
159 updateNodeIncremental(*t, t->root, glm::mat4(1.f), false);
160 t->transformDirty = false;
161}
162
164 if (ecs::current()->getManager<SceneHost>() == nullptr) return;
165 auto view = ecs::View<SceneHost, SceneHost::Meta, SceneHost::Tree>();
166 for (auto it = view.begin(); it != view.end(); ++it) {
167 auto [meta, tree] = *it;
168 (void)tree;
169 if (!meta->entity) continue;
170 updateHost(meta->entity);
171 }
172}
173
174} // namespace eve::scene
glm::vec3 n
Definition Grass.cpp:64
uint32_t c
glm::mat4 view
float m[16]
ECS mount point for one scene graph (full scene or nested subtree root). Isomorphic to eve::ui::UIHos...
Definition SceneHost.h:80
static void updateHost(SceneHost *host)
const LinkOps * linkOps(int kindId)
Definition SceneLink.cpp:47
void(* pushWorld)(const SceneNode &node, void *target)
Definition SceneLink.h:32
void(* pullWorld)(SceneNode &node, void *target)
Definition SceneLink.h:38
bool(* alive)(const void *target)
Definition SceneLink.h:44