summaryrefslogtreecommitdiffstats
path: root/libdimension/model/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdimension/model/object.c')
-rw-r--r--libdimension/model/object.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/libdimension/model/object.c b/libdimension/model/object.c
new file mode 100644
index 0000000..0473f54
--- /dev/null
+++ b/libdimension/model/object.c
@@ -0,0 +1,110 @@
+/*************************************************************************
+ * Copyright (C) 2009-2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Objects.
+ */
+
+#include "internal.h"
+#include "dimension/model.h"
+#include <stdlib.h>
+
+// Allocate a dummy object
+dmnsn_object *
+dmnsn_new_object(dmnsn_pool *pool)
+{
+ dmnsn_object *object = DMNSN_PALLOC(pool, dmnsn_object);
+ dmnsn_init_object(object);
+ return object;
+}
+
+// Initialize a dmnsn_object field
+void
+dmnsn_init_object(dmnsn_object *object)
+{
+ object->vtable = NULL;
+ object->texture = NULL;
+ object->interior = NULL;
+ object->trans = dmnsn_identity_matrix();
+ object->intrinsic_trans = dmnsn_identity_matrix();
+ object->children = NULL;
+ object->split_children = false;
+ object->precomputed = false;
+}
+
+/// Recursively precompute objects.
+static void
+dmnsn_object_precompute_recursive(dmnsn_object *object, dmnsn_matrix pigment_trans)
+{
+ dmnsn_assert(!object->precomputed, "Object double-precomputed.");
+ object->precomputed = true;
+
+ const dmnsn_object_vtable *vtable = object->vtable;
+ dmnsn_assert(vtable->intersection_fn, "Missing intersection function.");
+ dmnsn_assert(vtable->inside_fn, "Missing inside function.");
+ dmnsn_assert(vtable->bounding_fn || vtable->precompute_fn, "Missing bounding and precompute function.");
+
+ // Initialize the texture
+ if (!object->texture->initialized) {
+ dmnsn_texture_initialize(object->texture);
+ }
+
+ dmnsn_matrix total_trans = dmnsn_matrix_mul(object->trans, object->intrinsic_trans);
+
+ // Precompute the object's children
+ if (object->children) {
+ DMNSN_ARRAY_FOREACH (dmnsn_object **, child, object->children) {
+ dmnsn_matrix saved_trans = (*child)->trans;
+ (*child)->trans = dmnsn_matrix_mul(total_trans, saved_trans);
+
+ dmnsn_matrix child_pigment_trans;
+ if ((*child)->texture == NULL || (*child)->texture->pigment == NULL) {
+ // Don't transform cascaded pigments with the child object
+ child_pigment_trans = pigment_trans;
+ } else {
+ child_pigment_trans = dmnsn_matrix_inverse((*child)->trans);
+ }
+
+ dmnsn_texture_cascade(object->texture, &(*child)->texture);
+ dmnsn_interior_cascade(object->interior, &(*child)->interior);
+ dmnsn_object_precompute_recursive(*child, child_pigment_trans);
+ (*child)->trans = saved_trans;
+ }
+ }
+
+ // Precalculate object values
+ object->pigment_trans = pigment_trans;
+ object->trans_inv = dmnsn_matrix_inverse(total_trans);
+ if (vtable->bounding_fn) {
+ object->aabb = vtable->bounding_fn(object, total_trans);
+ }
+ if (vtable->precompute_fn) {
+ vtable->precompute_fn(object);
+ }
+}
+
+// Precompute object properties
+void
+dmnsn_object_precompute(dmnsn_object *object)
+{
+ dmnsn_matrix pigment_trans = dmnsn_matrix_inverse(object->trans);
+ dmnsn_object_precompute_recursive(object, pigment_trans);
+}