reprap: Added c3, a small scene graph lib
[simavr] / examples / board_reprap / src / c3 / c3object.c
diff --git a/examples/board_reprap/src/c3/c3object.c b/examples/board_reprap/src/c3/c3object.c
new file mode 100644 (file)
index 0000000..0b1d31c
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+       c3object.c
+
+       Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
+
+       This file is part of simavr.
+
+       simavr is free software: you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 3 of the License, or
+       (at your option) any later version.
+
+       simavr is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "c3/c3object.h"
+
+void
+_c3object_clear(
+               c3object_driver_p d)
+{
+       c3object_p o = d->object;
+       for (int oi = 0; oi < o->transform.count; oi++) {
+               o->transform.e[oi]->object = NULL;
+               c3transform_dispose(o->transform.e[oi]);
+       }
+       for (int oi = 0; oi < o->geometry.count; oi++) {
+               o->geometry.e[oi]->object = NULL;       // don't try to detach
+               c3geometry_dispose(o->geometry.e[oi]);
+       }
+       for (int oi = 0; oi < o->objects.count; oi++) {
+               o->objects.e[oi]->parent = NULL;        // don't try to detach
+               c3object_dispose(o->objects.e[oi]);
+       }
+       c3object_array_free(&o->objects);
+       c3geometry_array_free(&o->geometry);
+       c3transform_array_free(&o->transform);
+}
+
+void
+_c3object_dispose(
+               c3object_driver_p d)
+{
+       c3object_p o = d->object;
+       if (o->parent) {
+               for (int oi = 0; oi < o->parent->objects.count; oi++)
+                       if (o->parent->objects.e[oi] == o) {
+                               c3object_array_delete(&o->parent->objects, oi, 1);
+                               c3object_set_dirty(o->parent, true);
+                               break;
+                       }
+               o->parent = NULL;
+       }
+       //C3O_DRIVER_INHERITED(dispose, d);
+       /*
+        * free the driver chain
+        */
+       c3object_driver_p driver = o->driver;
+       while (driver) {
+               c3object_driver_p n = driver->next;
+               free(n);
+               driver = n;
+       }
+       free(o);
+}
+
+void
+_c3object_get_geometry(
+               c3object_driver_p d,
+               c3geometry_array_p out)
+{
+       c3object_p o = d->object;
+       for (int oi = 0; oi < o->geometry.count; oi++)
+               c3geometry_array_add(out, o->geometry.e[oi]);
+       for (int oi = 0; oi < o->objects.count; oi++)
+               c3object_get_geometry(o->objects.e[oi], out);
+}
+
+void
+_c3object_project(
+               c3object_driver_p d,
+               c3mat4p m)
+{
+       c3object_p o = d->object;
+       if (!o->dirty)
+               return;
+
+       c3mat4 identity = identity3D();
+       c3mat4 p = *m;
+       for (int pi = 0; pi < o->transform.count; pi++)
+               p = c3mat4_mul(&p, &o->transform.e[pi]->matrix);
+       bool is_identity = c3mat4_equal(m, &identity);
+
+       for (int gi = 0; gi < o->geometry.count; gi++) {
+               c3geometry_p g = o->geometry.e[gi];
+               c3vertex_array_clear(&g->projected);
+               if (1) {
+                       c3vertex_array_realloc(&g->projected, g->vertice.count);
+                       g->projected.count = g->vertice.count;
+                       for (int vi = 0; vi < g->vertice.count; vi++)
+                               g->projected.e[vi] = c3mat4_mulv3(&p, g->vertice.e[vi]);
+               }
+       }
+       for (int oi = 0; oi < o->objects.count; oi++)
+               c3object_project(o->objects.e[oi], &p);
+       o->dirty = false;
+}
+
+const c3object_driver_t c3object_base_driver = {
+       .clear = _c3object_clear,
+       .dispose = _c3object_dispose,
+       .get_geometry = _c3object_get_geometry,
+       .project = _c3object_project,
+};
+
+c3object_p
+c3object_init(
+               c3object_p o /* = NULL */,
+               c3object_p parent)
+{
+       memset(o, 0, sizeof(*o));
+       o->parent = parent;
+       o->driver = malloc(sizeof(c3object_driver_t));
+       *o->driver = c3object_base_driver;
+       o->driver->object = o;
+       if (parent)
+               c3object_array_add(&parent->objects, o);
+       return o;
+}
+
+c3object_p
+c3object_new(
+               c3object_p o /* = NULL */)
+{
+       c3object_p res = malloc(sizeof(*o));
+       return c3object_init(res, o);
+}
+
+void
+c3object_clear(
+               c3object_p o)
+{
+       C3O_DRIVER(o, clear);
+}
+
+void
+c3object_dispose(
+               c3object_p o)
+{
+       c3object_clear(o);
+       C3O_DRIVER(o, dispose);
+}
+
+void
+c3object_set_dirty(
+               c3object_p o,
+               bool dirty)
+{
+       if (dirty) {
+               while (o) {
+                       o->dirty = true;
+                       o = o->parent;
+               }
+       } else {
+               for (int oi = 0; oi < o->objects.count; oi++)
+                       if (o->objects.e[oi]->dirty)
+                               c3object_set_dirty(o->objects.e[oi], false);
+               o->dirty = false;
+       }
+}
+
+void
+c3object_add_object(
+               c3object_p o,
+               c3object_p sub)
+{
+       if (sub->parent == o)
+               return;
+       if (sub->parent) {
+               for (int oi = 0; oi < sub->parent->objects.count; oi++) {
+                       if (sub->parent->objects.e[oi] == sub) {
+                               c3object_array_delete(&sub->parent->objects, oi, 1);
+                               c3object_set_dirty(sub->parent, true);
+                               break;
+                       }
+               }
+               sub->parent = NULL;
+       }
+       sub->parent = o;
+       if (o) {
+               c3object_array_add(&o->objects, sub);
+               c3object_set_dirty(o, true);
+       }
+}
+
+void
+c3object_add_geometry(
+               c3object_p o,
+               c3geometry_p g)
+{
+       if (g->object == o)
+               return;
+       if (g->object) {
+               for (int oi = 0; oi < g->object->geometry.count; oi++) {
+                       if (g->object->geometry.e[oi] == g) {
+                               c3geometry_array_delete(&g->object->geometry, oi, 1);
+                               c3object_set_dirty(g->object, true);
+                               break;
+                       }
+               }
+               g->object = NULL;
+       }
+       g->object = o;
+       if (o) {
+               c3geometry_array_add(&o->geometry, g);
+               c3object_set_dirty(o, true);
+       }
+}
+
+void
+c3object_get_geometry(
+               c3object_p o,
+               c3geometry_array_p array )
+{
+       C3O_DRIVER(o, get_geometry, array);
+}
+
+void
+c3object_project(
+               c3object_p o,
+               const c3mat4p m)
+{
+       C3O_DRIVER(o, project, m);
+}