From 45e93889054cb2064b8e7ece2a7a3305cb225141 Mon Sep 17 00:00:00 2001 From: Tavian Barnes 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/csg.c') 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