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