diff options
author | Tavian Barnes <tavianator@gmail.com> | 2010-04-06 12:05:20 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2010-04-06 12:05:20 -0400 |
commit | 45e93889054cb2064b8e7ece2a7a3305cb225141 (patch) | |
tree | b7835a650e16134e3e43b3140db03a731b4bbb0b | |
parent | 9995e5e94797e7f5a1c4d825c9353a896f17e1ba (diff) | |
download | dimension-45e93889054cb2064b8e7ece2a7a3305cb225141.tar.xz |
Add CSG intersections to libdimension.
-rw-r--r-- | libdimension/csg.c | 125 | ||||
-rw-r--r-- | tests/libdimension/tests.c | 2 |
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; |