src/scene_node.c

changeset 95
622887f7e954
equal deleted inserted replaced
94:24bd333be668 95:622887f7e954
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 * Copyright 2023 Mike Becker. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "ascension/scene_node.h"
29 #include "ascension/context.h"
30
31 #include <cx/tree.h>
32 #include <cx/linked_list.h>
33
34 static CxTreeIterator asc_scene_node_iterator(
35 AscSceneNode *node,
36 bool visit_on_exit
37 ) {
38 return cx_tree_iterator(
39 node, visit_on_exit,
40 offsetof(AscSceneNode, children),
41 offsetof(AscSceneNode, next)
42 );
43 }
44
45 AscSceneNode *asc_scene_node_empty(void) {
46 AscSceneNode *node = calloc(1, sizeof(AscSceneNode));
47 node->render_group = ASC_RENDER_GROUP_NONE;
48 node->free_func = (asc_scene_free_func) free;
49 node->scale.x = node->scale.y = node->scale.z = 1;
50 asc_transform_identity(node->transform);
51 asc_transform_identity(node->world_transform);
52 return node;
53 }
54
55 void asc_scene_node_free(AscSceneNode *node) {
56 if (node == NULL) return;
57
58 // remove this node from its parent
59 asc_scene_node_unlink(node);
60
61 // free the entire subtree
62 CxTreeIterator iter = asc_scene_node_iterator(node, true);
63 cx_foreach(AscSceneNode*, child, iter) {
64 if (!iter.exiting) continue;
65 if (child->behaviors != NULL) {
66 cxListFree(child->behaviors);
67 }
68 if (child->free_func != NULL) {
69 child->free_func(child);
70 } else {
71 free(child);
72 }
73 }
74 }
75
76 void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) {
77 cx_tree_link(
78 parent, node,
79 offsetof(AscSceneNode, parent),
80 offsetof(AscSceneNode, children),
81 offsetof(AscSceneNode, last_child),
82 offsetof(AscSceneNode, prev),
83 offsetof(AscSceneNode, next)
84 );
85 }
86
87 void asc_scene_node_unlink(AscSceneNode *node) {
88 cx_tree_unlink(
89 node,
90 offsetof(AscSceneNode, parent),
91 offsetof(AscSceneNode, children),
92 offsetof(AscSceneNode, last_child),
93 offsetof(AscSceneNode, prev),
94 offsetof(AscSceneNode, next)
95 );
96 }
97
98 void asc_scene_add_behavior(
99 AscSceneNode *node,
100 asc_scene_update_func behavior
101 ) {
102 if (node->behaviors == NULL) {
103 node->behaviors = cxLinkedListCreateSimple(CX_STORE_POINTERS);
104 }
105 cxListAdd(node->behaviors, behavior);
106 }
107
108 void asc_scene_remove_behavior(
109 AscSceneNode *node,
110 asc_scene_update_func behavior
111 ) {
112 if (node->behaviors != NULL) {
113 cxListFindRemove(node->behaviors, behavior);
114 }
115 }
116
117 void asc_node_update(AscSceneNode *node) {
118 asc_set_flag(node->flags, ASC_SCENE_NODE_UPDATE_GRAPHICS);
119 }
120
121 void asc_node_update_transform(AscSceneNode *node) {
122 // fast skip if node is already marked
123 if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
124 return;
125 }
126
127 CxTreeIterator iter = asc_scene_node_iterator(node, false);
128 cx_foreach(AscSceneNode*, n, iter) {
129 if (asc_test_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
130 cxTreeIteratorContinue(iter);
131 }
132 asc_set_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM);
133 }
134 }

mercurial