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
|
/**
* @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"
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);
}
}
|