From 45e93889054cb2064b8e7ece2a7a3305cb225141 Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@gmail.com>
Date: Tue, 6 Apr 2010 12:05:20 -0400
Subject: Add CSG intersections to libdimension.

---
 libdimension/csg.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

(limited to 'libdimension')

diff --git a/libdimension/csg.c b/libdimension/csg.c
index 5b3cf9a..758929e 100644
--- a/libdimension/csg.c
+++ b/libdimension/csg.c
@@ -141,3 +141,128 @@ dmnsn_new_csg_union(dmnsn_object *A, dmnsn_object *B)
 
   return NULL;
 }
+
+/* Intersections */
+
+static dmnsn_intersection *
+dmnsn_csg_intersection_intersection_fn(const dmnsn_object *csg, dmnsn_line line)
+{
+  const dmnsn_object **params = csg->ptr;
+
+  dmnsn_line line1 = dmnsn_matrix_line_mul(params[0]->trans_inv, line);
+  dmnsn_line line2 = dmnsn_matrix_line_mul(params[1]->trans_inv, line);
+  dmnsn_intersection *i1 = (*params[0]->intersection_fn)(params[0], line1);
+  dmnsn_intersection *i2 = (*params[1]->intersection_fn)(params[1], line2);
+
+  if (i1) {
+    i1->ray = line;
+    i1->normal = dmnsn_vector_normalize(
+      dmnsn_vector_sub(
+        dmnsn_matrix_vector_mul(params[0]->trans, i1->normal),
+        dmnsn_matrix_vector_mul(params[0]->trans, dmnsn_zero)
+      )
+    );
+
+    if (!i1->texture)
+      i1->texture = csg->texture;
+    if (!i1->interior)
+      i1->interior = csg->interior;
+
+    dmnsn_vector point = dmnsn_line_point(i1->ray, i1->t);
+    point = dmnsn_matrix_vector_mul(params[1]->trans_inv, point);
+    if (!(*params[1]->inside_fn)(params[1], point)) {
+      dmnsn_delete_intersection(i1);
+      i1 = NULL;
+    }
+  }
+
+  if (i2) {
+    i2->ray = line;
+    i2->normal = dmnsn_vector_normalize(
+      dmnsn_vector_sub(
+        dmnsn_matrix_vector_mul(params[1]->trans, i2->normal),
+        dmnsn_matrix_vector_mul(params[1]->trans, dmnsn_zero)
+      )
+    );
+
+    if (!i2->texture)
+      i2->texture = csg->texture;
+    if (!i2->interior)
+      i2->interior = csg->interior;
+
+    dmnsn_vector point = dmnsn_line_point(i2->ray, i2->t);
+    point = dmnsn_matrix_vector_mul(params[0]->trans_inv, point);
+    if (!(*params[0]->inside_fn)(params[0], point)) {
+      dmnsn_delete_intersection(i2);
+      i2 = NULL;
+    }
+  }
+
+  if (!i1)
+    return i2;
+  if (!i2)
+    return i1;
+
+  if (i1->t > i2->t) {
+    dmnsn_delete_intersection(i2);
+    return i1;
+  } else {
+    dmnsn_delete_intersection(i1);
+    return i2;
+  }
+}
+
+static bool
+dmnsn_csg_intersection_inside_fn(const dmnsn_object *csg, dmnsn_vector point)
+{
+  dmnsn_object **params = csg->ptr;
+  return (*params[0]->inside_fn)(params[0], point)
+      && (*params[1]->inside_fn)(params[1], point);
+}
+
+dmnsn_object *
+dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B)
+{
+  if (A && B) {
+    A->trans_inv = dmnsn_matrix_inverse(A->trans);
+    B->trans_inv = dmnsn_matrix_inverse(B->trans);
+
+    dmnsn_object *csg = dmnsn_new_object();
+    if (csg) {
+      dmnsn_object **params = malloc(2*sizeof(dmnsn_object *));
+      if (!params) {
+        dmnsn_delete_object(csg);
+        dmnsn_delete_object(B);
+        dmnsn_delete_object(A);
+        errno = ENOMEM;
+        return NULL;
+      }
+
+      params[0] = A;
+      params[1] = B;
+
+      csg->ptr             = params;
+      csg->intersection_fn = &dmnsn_csg_intersection_intersection_fn;
+      csg->inside_fn       = &dmnsn_csg_intersection_inside_fn;
+      csg->free_fn         = &dmnsn_csg_free_fn;
+
+      dmnsn_bounding_box Abox
+        = dmnsn_matrix_bounding_box_mul(A->trans, A->bounding_box);
+      dmnsn_bounding_box Bbox
+        = dmnsn_matrix_bounding_box_mul(B->trans, B->bounding_box);
+      csg->bounding_box.min = dmnsn_vector_min(Abox.min, Bbox.min);
+      csg->bounding_box.max = dmnsn_vector_max(Abox.max, Bbox.max);
+
+      return csg;
+    } else {
+      dmnsn_delete_object(B);
+      dmnsn_delete_object(A);
+    }
+  } else if (A) {
+    dmnsn_delete_object(B);
+  } else if (B) {
+    dmnsn_delete_object(A);
+  }
+
+  return NULL;
+}
-- 
cgit v1.2.3