summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-04-06 12:05:20 -0400
committerTavian Barnes <tavianator@gmail.com>2010-04-06 12:05:20 -0400
commit45e93889054cb2064b8e7ece2a7a3305cb225141 (patch)
treeb7835a650e16134e3e43b3140db03a731b4bbb0b
parent9995e5e94797e7f5a1c4d825c9353a896f17e1ba (diff)
downloaddimension-45e93889054cb2064b8e7ece2a7a3305cb225141.tar.xz
Add CSG intersections to libdimension.
-rw-r--r--libdimension/csg.c125
-rw-r--r--tests/libdimension/tests.c2
2 files changed, 126 insertions, 1 deletions
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;
+}
diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c
index 47d9b7c..e00e8ff 100644
--- a/tests/libdimension/tests.c
+++ b/tests/libdimension/tests.c
@@ -143,7 +143,7 @@ dmnsn_new_default_scene()
cube->trans = dmnsn_rotation_matrix(dmnsn_new_vector(0.75, 0.0, 0.0));
- dmnsn_object *csg = dmnsn_new_csg_union(sphere, cube);
+ dmnsn_object *csg = dmnsn_new_csg_intersection(sphere, cube);
if (!csg) {
dmnsn_delete_scene(scene);
return NULL;