26 */ |
26 */ |
27 |
27 |
28 #include "ascension/scene.h" |
28 #include "ascension/scene.h" |
29 #include "ascension/error.h" |
29 #include "ascension/error.h" |
30 |
30 |
|
31 #include <cx/tree.h> |
|
32 |
31 #include <assert.h> |
33 #include <assert.h> |
|
34 |
|
35 #define asc_scene_node_layout \ |
|
36 offsetof(AscSceneNode, parent), offsetof(AscSceneNode, children), \ |
|
37 offsetof(AscSceneNode, prev), offsetof(AscSceneNode, next) |
32 |
38 |
33 void asc_scene_init(AscScene *scene) { |
39 void asc_scene_init(AscScene *scene) { |
34 if (scene->root != NULL) { |
40 if (scene->root != NULL) { |
35 asc_error("Scene is already initialized."); |
41 asc_error("Scene is already initialized."); |
36 return; |
42 return; |
37 } |
43 } |
38 scene->root = asc_scene_node_create(NULL); |
44 scene->root = asc_scene_node_empty(); |
39 } |
45 } |
40 |
46 |
41 void asc_scene_destroy(AscScene *scene) { |
47 void asc_scene_destroy(AscScene *scene) { |
42 asc_scene_node_free(scene->root); |
48 asc_scene_node_free(scene->root); |
43 } |
49 } |
44 |
50 |
45 AscSceneNode *asc_scene_node_create(AscSceneNode *parent) { |
51 void asc_scene_add(AscScene *scene, AscSceneNode *node) { |
|
52 asc_scene_node_link(scene->root, node); |
|
53 } |
|
54 |
|
55 static void asc_scene_draw_node(AscSceneNode *node) { |
|
56 if (node->draw_func != NULL) { |
|
57 node->draw_func(node); |
|
58 } |
|
59 if (node->children != NULL) { |
|
60 asc_scene_draw_node(node->children); |
|
61 } |
|
62 if (node->next != NULL) { |
|
63 asc_scene_draw_node(node->next); |
|
64 } |
|
65 } |
|
66 |
|
67 void asc_scene_draw(AscScene const *scene) { |
|
68 // TODO: replace with UCX tree visitor |
|
69 // TODO: don't visit the tree, visit the render groups |
|
70 // TODO: avoid recursion |
|
71 asc_scene_draw_node(scene->root); |
|
72 } |
|
73 |
|
74 AscSceneNode *asc_scene_node_empty(void) { |
46 // TODO: check if this can remain a calloc or if it's too expensive |
75 // TODO: check if this can remain a calloc or if it's too expensive |
47 AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); |
76 AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); |
48 assert(node != NULL); |
77 assert(node != NULL); |
49 asc_scene_node_link(node, parent); |
78 node->free_func = (asc_scene_free_func) free; |
50 return node; |
79 return node; |
51 } |
80 } |
52 |
81 |
53 void asc_scene_node_free(AscSceneNode *node) { |
82 void asc_scene_node_free(AscSceneNode *node) { |
54 if (node == NULL) return; |
83 if (node == NULL) return; |
|
84 |
|
85 // TODO: replace with UCX tree visitor |
|
86 // TODO: avoid recursion |
55 |
87 |
56 // free the children recursively |
88 // free the children recursively |
57 while (node->children != NULL) { |
89 while (node->children != NULL) { |
58 asc_scene_node_free(node->children); |
90 asc_scene_node_free(node->children); |
59 } |
91 } |
60 |
92 |
61 // remove this node from its parent |
93 // remove this node from its parent |
62 asc_scene_node_unlink(node); |
94 asc_scene_node_unlink(node); |
63 |
95 |
64 // free the node |
96 // free the node |
65 free(node); |
97 if (node->free_func != NULL) { |
66 } |
98 node->free_func(node); |
67 |
|
68 void asc_scene_node_link( |
|
69 AscSceneNode *node, |
|
70 AscSceneNode *parent |
|
71 ) { |
|
72 if (node->parent == parent) return; |
|
73 if (node->parent != NULL || parent == NULL) asc_scene_node_unlink(node); |
|
74 if (parent != NULL) { |
|
75 if (parent->children == NULL) { |
|
76 parent->children = node; |
|
77 } else { |
|
78 parent->children->prev = node; |
|
79 node->next = parent->children; |
|
80 } |
|
81 node->parent = parent; |
|
82 } |
99 } |
83 } |
100 } |
84 |
101 |
|
102 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) { |
|
103 cx_tree_link(parent, node, asc_scene_node_layout); |
|
104 } |
|
105 |
85 void asc_scene_node_unlink(AscSceneNode *node) { |
106 void asc_scene_node_unlink(AscSceneNode *node) { |
86 if (node->parent == NULL) return; |
107 cx_tree_unlink(node, asc_scene_node_layout); |
87 AscSceneNode *left = node->prev; |
|
88 AscSceneNode *right = node->next; |
|
89 assert(left == NULL || node->parent->children != node); |
|
90 if (left != NULL) { |
|
91 left->next = right; |
|
92 } else { |
|
93 node->parent->children = right; |
|
94 } |
|
95 if (right != NULL) right->prev = left; |
|
96 node->parent = node->prev = node->next = NULL; |
|
97 } |
108 } |