1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
/**
* @file transform_hierarchy.h
*/
#pragma once
#include "transform_hierarchy.h"
#include <stdlib.h>
#include <string.h>
#include "log.h"
#include "maths.h"
#include "maths_types.h"
#include "render_types.h"
#include "core.h"
struct transform_hierarchy {
transform_node root;
};
transform_hierarchy* transform_hierarchy_create() {
transform_hierarchy* tfh = malloc(sizeof(transform_hierarchy));
tfh->root = (transform_node){ .model = { ABSENT_MODEL_HANDLE },
.tf = TRANSFORM_DEFAULT,
.local_matrix_tf = mat4_ident(),
.world_matrix_tf = mat4_ident(),
.parent = NULL,
.children = { 0 },
.n_children = 0,
.tfh = tfh };
return tfh;
}
bool free_node(transform_node* node, void* _ctx_data) {
if (!node) return true; // leaf node
if (node == &node->tfh->root) {
WARN("You can't free the root node!");
return false;
}
printf("Freed node\n");
free(node);
return true;
}
void transform_hierarchy_free(transform_hierarchy* tfh) {
transform_hierarchy_dfs(&tfh->root, free_node, false, NULL);
free(tfh);
}
transform_node* transform_hierarchy_root_node(transform_hierarchy* tfh) { return &tfh->root; }
void transform_hierarchy_add_node(transform_node* parent, model_handle model, transform tf) {
if (!parent) {
WARN("You tried to add a node to a bad parent (NULL?)");
return;
}
transform_node* node = malloc(sizeof(transform_node));
node->model = model;
node->tf = tf;
node->local_matrix_tf = mat4_ident();
node->world_matrix_tf = mat4_ident();
node->parent = parent;
memset(node->children, 0, sizeof(node->children));
node->n_children = 0;
node->tfh = parent->tfh;
// push into parent's children array
u32 next_index = parent->n_children;
if (next_index == MAX_TF_NODE_CHILDREN) {
ERROR("This transform hierarchy node already has MAX children. Dropping.");
free(node);
} else {
parent->children[next_index] = node;
parent->n_children++;
}
}
void transform_hierarchy_delete_node(transform_node* node) {
// delete all children
for (u32 i = 0; i < node->n_children; i++) {
transform_node* child = node->children[i];
transform_hierarchy_dfs(child, free_node, false, NULL);
}
if (node->parent) {
for (u32 i = 0; i < node->parent->n_children; i++) {
transform_node* child = node->parent->children[i];
if (child == node) {
node->parent->children[i] = NULL; // HACK: this will leave behind empty slots in the
// children array of the parent. oh well.
}
}
}
free(node);
}
void transform_hierarchy_dfs(transform_node* start_node,
bool (*visit_node)(transform_node* node, void* ctx_data),
bool is_pre_order, void* ctx_data) {
if (!start_node) return;
bool continue_traversal = true;
if (is_pre_order) {
continue_traversal = visit_node(start_node, ctx_data);
}
if (continue_traversal) {
for (u32 i = 0; i < start_node->n_children; i++) {
transform_node* child = start_node->children[i];
transform_hierarchy_dfs(child, visit_node, is_pre_order, ctx_data);
}
}
if (!is_pre_order) {
// post-order
visit_node(start_node, ctx_data);
}
}
// Update matrix for the current node
bool update_matrix(transform_node* node, void* _ctx_data) {
if (!node) return true; // leaf node
if (node->parent->tf.is_dirty) {
node->tf.is_dirty = true;
}
if (node->tf.is_dirty) {
// invalidates children
mat4 updated_local_transform = transform_to_mat(&node->tf);
node->local_matrix_tf = updated_local_transform;
if (node->parent) {
mat4 updated_world_transform =
mat4_mult(node->parent->world_matrix_tf, updated_local_transform);
node->world_matrix_tf = updated_world_transform;
}
}
return true;
}
void transform_hierarchy_propagate_transforms(transform_hierarchy* tfh) {
// kickoff traversal
transform_hierarchy_dfs(&tfh->root, update_matrix, false, NULL);
}
void print_node(transform_node* node, void* _ctx_data) {
// Grab the model
model m = core->models->data[start_node->model.raw];
printf("Node %s\n", m.name.buf);
}
struct print_ctx {
core* core;
u32 indentation_lvl;
};
void transform_hierarchy_debug_print(transform_node* start_node, core* core) {
}
|