0b1d31c48dc1756f6d6a0a3647bb75d6dba47815
[simavr] / examples / board_reprap / src / c3 / c3object.c
1 /*
2         c3object.c
3
4         Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "c3/c3object.h"
24
25 void
26 _c3object_clear(
27                 c3object_driver_p d)
28 {
29         c3object_p o = d->object;
30         for (int oi = 0; oi < o->transform.count; oi++) {
31                 o->transform.e[oi]->object = NULL;
32                 c3transform_dispose(o->transform.e[oi]);
33         }
34         for (int oi = 0; oi < o->geometry.count; oi++) {
35                 o->geometry.e[oi]->object = NULL;       // don't try to detach
36                 c3geometry_dispose(o->geometry.e[oi]);
37         }
38         for (int oi = 0; oi < o->objects.count; oi++) {
39                 o->objects.e[oi]->parent = NULL;        // don't try to detach
40                 c3object_dispose(o->objects.e[oi]);
41         }
42         c3object_array_free(&o->objects);
43         c3geometry_array_free(&o->geometry);
44         c3transform_array_free(&o->transform);
45 }
46
47 void
48 _c3object_dispose(
49                 c3object_driver_p d)
50 {
51         c3object_p o = d->object;
52         if (o->parent) {
53                 for (int oi = 0; oi < o->parent->objects.count; oi++)
54                         if (o->parent->objects.e[oi] == o) {
55                                 c3object_array_delete(&o->parent->objects, oi, 1);
56                                 c3object_set_dirty(o->parent, true);
57                                 break;
58                         }
59                 o->parent = NULL;
60         }
61         //C3O_DRIVER_INHERITED(dispose, d);
62         /*
63          * free the driver chain
64          */
65         c3object_driver_p driver = o->driver;
66         while (driver) {
67                 c3object_driver_p n = driver->next;
68                 free(n);
69                 driver = n;
70         }
71         free(o);
72 }
73
74 void
75 _c3object_get_geometry(
76                 c3object_driver_p d,
77                 c3geometry_array_p out)
78 {
79         c3object_p o = d->object;
80         for (int oi = 0; oi < o->geometry.count; oi++)
81                 c3geometry_array_add(out, o->geometry.e[oi]);
82         for (int oi = 0; oi < o->objects.count; oi++)
83                 c3object_get_geometry(o->objects.e[oi], out);
84 }
85
86 void
87 _c3object_project(
88                 c3object_driver_p d,
89                 c3mat4p m)
90 {
91         c3object_p o = d->object;
92         if (!o->dirty)
93                 return;
94
95         c3mat4 identity = identity3D();
96         c3mat4 p = *m;
97         for (int pi = 0; pi < o->transform.count; pi++)
98                 p = c3mat4_mul(&p, &o->transform.e[pi]->matrix);
99         bool is_identity = c3mat4_equal(m, &identity);
100
101         for (int gi = 0; gi < o->geometry.count; gi++) {
102                 c3geometry_p g = o->geometry.e[gi];
103                 c3vertex_array_clear(&g->projected);
104                 if (1) {
105                         c3vertex_array_realloc(&g->projected, g->vertice.count);
106                         g->projected.count = g->vertice.count;
107                         for (int vi = 0; vi < g->vertice.count; vi++)
108                                 g->projected.e[vi] = c3mat4_mulv3(&p, g->vertice.e[vi]);
109                 }
110         }
111         for (int oi = 0; oi < o->objects.count; oi++)
112                 c3object_project(o->objects.e[oi], &p);
113         o->dirty = false;
114 }
115
116 const c3object_driver_t c3object_base_driver = {
117         .clear = _c3object_clear,
118         .dispose = _c3object_dispose,
119         .get_geometry = _c3object_get_geometry,
120         .project = _c3object_project,
121 };
122
123 c3object_p
124 c3object_init(
125                 c3object_p o /* = NULL */,
126                 c3object_p parent)
127 {
128         memset(o, 0, sizeof(*o));
129         o->parent = parent;
130         o->driver = malloc(sizeof(c3object_driver_t));
131         *o->driver = c3object_base_driver;
132         o->driver->object = o;
133         if (parent)
134                 c3object_array_add(&parent->objects, o);
135         return o;
136 }
137
138 c3object_p
139 c3object_new(
140                 c3object_p o /* = NULL */)
141 {
142         c3object_p res = malloc(sizeof(*o));
143         return c3object_init(res, o);
144 }
145
146 void
147 c3object_clear(
148                 c3object_p o)
149 {
150         C3O_DRIVER(o, clear);
151 }
152
153 void
154 c3object_dispose(
155                 c3object_p o)
156 {
157         c3object_clear(o);
158         C3O_DRIVER(o, dispose);
159 }
160
161 void
162 c3object_set_dirty(
163                 c3object_p o,
164                 bool dirty)
165 {
166         if (dirty) {
167                 while (o) {
168                         o->dirty = true;
169                         o = o->parent;
170                 }
171         } else {
172                 for (int oi = 0; oi < o->objects.count; oi++)
173                         if (o->objects.e[oi]->dirty)
174                                 c3object_set_dirty(o->objects.e[oi], false);
175                 o->dirty = false;
176         }
177 }
178
179 void
180 c3object_add_object(
181                 c3object_p o,
182                 c3object_p sub)
183 {
184         if (sub->parent == o)
185                 return;
186         if (sub->parent) {
187                 for (int oi = 0; oi < sub->parent->objects.count; oi++) {
188                         if (sub->parent->objects.e[oi] == sub) {
189                                 c3object_array_delete(&sub->parent->objects, oi, 1);
190                                 c3object_set_dirty(sub->parent, true);
191                                 break;
192                         }
193                 }
194                 sub->parent = NULL;
195         }
196         sub->parent = o;
197         if (o) {
198                 c3object_array_add(&o->objects, sub);
199                 c3object_set_dirty(o, true);
200         }
201 }
202
203 void
204 c3object_add_geometry(
205                 c3object_p o,
206                 c3geometry_p g)
207 {
208         if (g->object == o)
209                 return;
210         if (g->object) {
211                 for (int oi = 0; oi < g->object->geometry.count; oi++) {
212                         if (g->object->geometry.e[oi] == g) {
213                                 c3geometry_array_delete(&g->object->geometry, oi, 1);
214                                 c3object_set_dirty(g->object, true);
215                                 break;
216                         }
217                 }
218                 g->object = NULL;
219         }
220         g->object = o;
221         if (o) {
222                 c3geometry_array_add(&o->geometry, g);
223                 c3object_set_dirty(o, true);
224         }
225 }
226
227 void
228 c3object_get_geometry(
229                 c3object_p o,
230                 c3geometry_array_p array )
231 {
232         C3O_DRIVER(o, get_geometry, array);
233 }
234
235 void
236 c3object_project(
237                 c3object_p o,
238                 const c3mat4p m)
239 {
240         C3O_DRIVER(o, project, m);
241 }