8#include <glm/gtc/matrix_transform.hpp>
9#include <glm/gtc/quaternion.hpp>
14glm::mat4 localMatrix(
const SceneNode &
n) {
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));
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));
24 m = glm::scale(
m, glm::vec3(
n.sx,
n.sy,
n.sz));
28void updateNode(SceneHost::Tree &tree,
int nodeIndex,
const glm::mat4 &parentWorld) {
30 n.world = parentWorld * localMatrix(
n);
32 for (
int c =
n.firstChild;
c >= 0;
c = tree.nodes[size_t(
c)].nextSibling) {
33 updateNode(tree,
c,
n.world);
38void pullTargets(SceneHost *
host) {
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;
48 host->markSubtreeDirty(
int(i));
54void pushTarget(
const SceneNode &
n,
const SceneLink &l);
55void updateNodeIncremental(SceneHost::Tree &tree,
int nodeIndex,
56 const glm::mat4 &parentWorld,
bool force) {
58 const bool need = force ||
n.subtreeDirty;
60 n.world = parentWorld * localMatrix(
n);
62 n.subtreeDirty =
false;
63 for (
auto &l :
n.links) {
64 if (l.syncMode == 0) pushTarget(
n, l);
67 for (
int c =
n.firstChild;
c >= 0;
c = tree.nodes[size_t(
c)].nextSibling) {
68 updateNodeIncremental(tree,
c,
n.world, need);
73void pushTarget(
const SceneNode &
n,
const SceneLink &l) {
74 if (!l.target)
return;
79void syncLinks(SceneHost *
host) {
81 auto t =
host->tree();
83 for (
auto &l :
n.links) {
84 if (l.syncMode == 0) pushTarget(
n, l);
94bool linkTargetAlive(
const SceneLink &l) {
95 if (!l.target)
return false;
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)) {
108 it =
n.links.erase(it);
118 auto t =
host->tree();
119 if (
t->root < 0 ||
t->nodes.empty()) {
120 t->transformDirty =
false;
128 bool legacy =
t->transformDirty;
130 for (
const auto &
n :
t->nodes) {
131 if (
n.localDirty && !
n.subtreeDirty) {
139 if (
t->nodes[
index].parent < 0) updateNode(*
t,
static_cast<int>(
index), glm::mat4(1.f));
141 for (
auto &
n :
t->nodes) {
142 n.localDirty =
false;
143 n.subtreeDirty =
false;
145 t->transformDirty =
false;
150 bool anySubtree =
false;
151 for (
const auto &
n :
t->nodes) {
152 if (
n.subtreeDirty) {
158 t->transformDirty =
false;
162 if (
t->nodes[
index].parent < 0) updateNodeIncremental(*
t,
static_cast<int>(
index), glm::mat4(1.f),
false);
163 t->transformDirty =
false;
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;
173 if (!meta->entity)
continue;
#define EV_PROFILE_MODULE(module, name)
Profile the enclosing scope, tagged with a module for grouping.
ECS mount point for one scene graph (full scene or nested subtree root). Isomorphic to eve::ui::UIHos...
const LinkOps * linkOps(int kindId)
Link ops.
void(* pushWorld)(const SceneNode &node, void *target)
Void.
void(* pullWorld)(SceneNode &node, void *target)
Void.
bool(* alive)(const void *target)
Bool.