diff options
author | Tavian Barnes <tavianator@gmail.com> | 2010-11-06 02:08:32 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2010-11-06 02:08:32 -0400 |
commit | b6f1834ac17a11c38091ae0c60e53f8f6320b019 (patch) | |
tree | eb27bf99fbfa38382c3ddd07da03cfab0453deab | |
parent | 120c523adc70af185b743e955837e1fe9e9a6785 (diff) | |
download | dimension-b6f1834ac17a11c38091ae0c60e53f8f6320b019.tar.xz |
Factor out transformation code from object callbacks.
-rw-r--r-- | libdimension/csg.c | 24 | ||||
-rw-r--r-- | libdimension/cube.c | 17 | ||||
-rw-r--r-- | libdimension/cylinder.c | 12 | ||||
-rw-r--r-- | libdimension/dimension/object.h | 20 | ||||
-rw-r--r-- | libdimension/object.c | 39 | ||||
-rw-r--r-- | libdimension/plane.c | 7 | ||||
-rw-r--r-- | libdimension/prtree.c | 8 | ||||
-rw-r--r-- | libdimension/sphere.c | 10 | ||||
-rw-r--r-- | libdimension/torus.c | 8 | ||||
-rw-r--r-- | tests/libdimension/prtree.c | 1 |
10 files changed, 82 insertions, 64 deletions
diff --git a/libdimension/csg.c b/libdimension/csg.c index cfce242..58104ff 100644 --- a/libdimension/csg.c +++ b/libdimension/csg.c @@ -116,8 +116,8 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, const dmnsn_object **params = csg->ptr; dmnsn_intersection i1, i2; - bool is_i1 = (*params[0]->intersection_fn)(params[0], line, &i1); - bool is_i2 = (*params[1]->intersection_fn)(params[1], line, &i2); + bool is_i1 = dmnsn_object_intersection(params[0], line, &i1); + bool is_i2 = dmnsn_object_intersection(params[1], line, &i2); double oldt = 0.0; while (is_i1) { @@ -126,11 +126,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, oldt = i1.t + dmnsn_epsilon; dmnsn_vector point = dmnsn_line_point(i1.ray, i1.t); - if (inside2 ^ (*params[1]->inside_fn)(params[1], point)) { + if (inside2 ^ dmnsn_object_inside(params[1], point)) { dmnsn_line newline = line; newline.x0 = dmnsn_line_point(line, i1.t); newline = dmnsn_line_add_epsilon(newline); - is_i1 = (*params[0]->intersection_fn)(params[0], newline, &i1); + is_i1 = dmnsn_object_intersection(params[0], newline, &i1); } else { break; } @@ -143,11 +143,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, oldt = i2.t + dmnsn_epsilon; dmnsn_vector point = dmnsn_line_point(i2.ray, i2.t); - if (inside1 ^ (*params[0]->inside_fn)(params[0], point)) { + if (inside1 ^ dmnsn_object_inside(params[0], point)) { dmnsn_line newline = line; newline.x0 = dmnsn_line_point(line, i2.t); newline = dmnsn_line_add_epsilon(newline); - is_i2 = (*params[1]->intersection_fn)(params[1], newline, &i2); + is_i2 = dmnsn_object_intersection(params[1], newline, &i2); } else { break; } @@ -184,8 +184,8 @@ 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); + return dmnsn_object_inside(params[0], point) + && dmnsn_object_inside(params[1], point); } static void @@ -240,8 +240,8 @@ static bool dmnsn_csg_difference_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); + return dmnsn_object_inside(params[0], point) + && !dmnsn_object_inside(params[1], point); } static void @@ -293,8 +293,8 @@ static bool dmnsn_csg_merge_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); + return dmnsn_object_inside(params[0], point) + || dmnsn_object_inside(params[1], point); } static void diff --git a/libdimension/cube.c b/libdimension/cube.c index 52fff92..c70ebf6 100644 --- a/libdimension/cube.c +++ b/libdimension/cube.c @@ -51,13 +51,11 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, { /* Clip the given line against the X, Y, and Z slabs */ - dmnsn_line line_trans = dmnsn_transform_line(cube->trans_inv, line); - dmnsn_vector nmin, nmax; double tmin, tmax; - double tx1 = (-1.0 - line_trans.x0.x)/line_trans.n.x; - double tx2 = (+1.0 - line_trans.x0.x)/line_trans.n.x; + double tx1 = (-1.0 - line.x0.x)/line.n.x; + double tx2 = (+1.0 - line.x0.x)/line.n.x; if (tx1 < tx2) { tmin = tx1; @@ -74,8 +72,8 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, if (tmin > tmax) return false; - double ty1 = (-1.0 - line_trans.x0.y)/line_trans.n.y; - double ty2 = (+1.0 - line_trans.x0.y)/line_trans.n.y; + double ty1 = (-1.0 - line.x0.y)/line.n.y; + double ty2 = (+1.0 - line.x0.y)/line.n.y; if (ty1 < ty2) { if (ty1 > tmin) { @@ -100,8 +98,8 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, if (tmin > tmax) return false; - double tz1 = (-1.0 - line_trans.x0.z)/line_trans.n.z; - double tz2 = (+1.0 - line_trans.x0.z)/line_trans.n.z; + double tz1 = (-1.0 - line.x0.z)/line.n.z; + double tz2 = (+1.0 - line.x0.z)/line.n.z; if (tz1 < tz2) { if (tz1 > tmin) { @@ -134,7 +132,7 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, if (tmin >= 0.0) { intersection->ray = line; intersection->t = tmin; - intersection->normal = dmnsn_transform_normal(cube->trans, nmin); + intersection->normal = nmin; intersection->texture = cube->texture; intersection->interior = cube->interior; return true; @@ -147,7 +145,6 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, static bool dmnsn_cube_inside_fn(const dmnsn_object *cube, dmnsn_vector point) { - point = dmnsn_transform_vector(cube->trans_inv, point); return point.x > -1.0 && point.x < 1.0 && point.y > -1.0 && point.y < 1.0 && point.z > -1.0 && point.z < 1.0; diff --git a/libdimension/cylinder.c b/libdimension/cylinder.c index ba016cf..9f5b7ff 100644 --- a/libdimension/cylinder.c +++ b/libdimension/cylinder.c @@ -60,10 +60,9 @@ dmnsn_new_cylinder(double r1, double r2, bool open) /* Intersections callback for a cylinder */ static bool -dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line line, +dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line l, dmnsn_intersection *intersection) { - dmnsn_line l = dmnsn_transform_line(cylinder->trans_inv, line); const dmnsn_cylinder_payload *payload = cylinder->ptr; double r1 = payload->r1, r2 = payload->r2; @@ -128,9 +127,9 @@ dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line line, && (tcap < t || p.y <= -1.0 || p.y >= 1.0) && pcap.x*pcap.x + pcap.z*pcap.z < r*r) { - intersection->ray = line; + intersection->ray = l; intersection->t = tcap; - intersection->normal = dmnsn_transform_normal(cylinder->trans, norm); + intersection->normal = norm; intersection->texture = cylinder->texture; intersection->interior = cylinder->interior; return true; @@ -141,9 +140,9 @@ dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line line, dmnsn_vector norm = dmnsn_vector_normalize( dmnsn_new_vector(p.x, -(r2 - r1)*sqrt(p.x*p.x + p.z*p.z)/2.0, p.z) ); - intersection->ray = line; + intersection->ray = l; intersection->t = t; - intersection->normal = dmnsn_transform_normal(cylinder->trans, norm); + intersection->normal = norm; intersection->texture = cylinder->texture; intersection->interior = cylinder->interior; return true; @@ -157,7 +156,6 @@ dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line line, static bool dmnsn_cylinder_inside_fn(const dmnsn_object *cylinder, dmnsn_vector point) { - point = dmnsn_transform_vector(cylinder->trans_inv, point); const dmnsn_cylinder_payload *payload = cylinder->ptr; double r1 = payload->r1, r2 = payload->r2; double r = (point.y*(r2 - r1) + r1 + r2)/2.0; diff --git a/libdimension/dimension/object.h b/libdimension/dimension/object.h index cef1acb..56cfacd 100644 --- a/libdimension/dimension/object.h +++ b/libdimension/dimension/object.h @@ -85,22 +85,12 @@ dmnsn_object *dmnsn_new_object(void); /* Free an object */ void dmnsn_delete_object(dmnsn_object *object); +/* Initialize an object and potentially its children */ void dmnsn_object_init(dmnsn_object *object); -/* Useful function to transform a normal vector */ -DMNSN_INLINE dmnsn_vector -dmnsn_transform_normal(dmnsn_matrix trans, dmnsn_vector normal) -{ - return dmnsn_vector_normalize( - dmnsn_vector_sub( - dmnsn_transform_vector(trans, normal), - /* Optimized form of dmnsn_transform_vector(trans, dmnsn_zero) */ - dmnsn_vector_div( - dmnsn_new_vector(trans.n[0][3], trans.n[1][3], trans.n[2][3]), - trans.n[3][3] - ) - ) - ); -} +/* Helpers for invoking object callbacks with correct transformations */ +bool dmnsn_object_intersection(const dmnsn_object *object, dmnsn_line line, + dmnsn_intersection *intersection); +bool dmnsn_object_inside(const dmnsn_object *object, dmnsn_vector point); #endif /* DIMENSION_OBJECT_H */ diff --git a/libdimension/object.c b/libdimension/object.c index 768cf68..873f5ee 100644 --- a/libdimension/object.c +++ b/libdimension/object.c @@ -71,3 +71,42 @@ dmnsn_object_init(dmnsn_object *object) dmnsn_texture_init(object->texture); } } + +/* Helper function to transform a normal vector */ +static inline dmnsn_vector +dmnsn_transform_normal(dmnsn_matrix trans, dmnsn_vector normal) +{ + return dmnsn_vector_normalize( + dmnsn_vector_sub( + dmnsn_transform_vector(trans, normal), + /* Optimized form of dmnsn_transform_vector(trans, dmnsn_zero) */ + dmnsn_vector_div( + dmnsn_new_vector(trans.n[0][3], trans.n[1][3], trans.n[2][3]), + trans.n[3][3] + ) + ) + ); +} + +bool +dmnsn_object_intersection(const dmnsn_object *object, dmnsn_line line, + dmnsn_intersection *intersection) +{ + dmnsn_line line_trans = dmnsn_transform_line(object->trans_inv, line); + if ((*object->intersection_fn)(object, line_trans, intersection)) { + /* Get us back into world coordinates */ + intersection->ray = line; + intersection->normal = dmnsn_transform_normal(object->trans, + intersection->normal); + return true; + } else { + return false; + } +} + +bool +dmnsn_object_inside(const dmnsn_object *object, dmnsn_vector point) +{ + point = dmnsn_transform_vector(object->trans_inv, point); + return (*object->inside_fn)(object, point); +} diff --git a/libdimension/plane.c b/libdimension/plane.c index 93d5173..be3d91a 100644 --- a/libdimension/plane.c +++ b/libdimension/plane.c @@ -58,14 +58,13 @@ dmnsn_plane_intersection_fn(const dmnsn_object *plane, dmnsn_line line, { dmnsn_vector *normal = plane->ptr; - dmnsn_line line_trans = dmnsn_transform_line(plane->trans_inv, line); - double den = dmnsn_vector_dot(line_trans.n, *normal); + double den = dmnsn_vector_dot(line.n, *normal); if (den != 0.0) { - double t = -dmnsn_vector_dot(line_trans.x0, *normal)/den; + double t = -dmnsn_vector_dot(line.x0, *normal)/den; if (t >= 0.0) { intersection->ray = line; intersection->t = t; - intersection->normal = dmnsn_transform_normal(plane->trans, *normal); + intersection->normal = *normal; intersection->texture = plane->texture; intersection->interior = plane->interior; return true; diff --git a/libdimension/prtree.c b/libdimension/prtree.c index 3367384..73c2484 100644 --- a/libdimension/prtree.c +++ b/libdimension/prtree.c @@ -605,7 +605,7 @@ dmnsn_prtree_intersection_recursive(const dmnsn_prtree_node *node, if (dmnsn_ray_box_intersection(ray, node->bounding_boxes[i], *t)) { dmnsn_object *object = node->children[i]; dmnsn_intersection local_intersection; - if ((*object->intersection_fn)(object, ray.line, &local_intersection)) { + if (dmnsn_object_intersection(object, ray.line, &local_intersection)) { if (local_intersection.t < *t) { *intersection = local_intersection; *t = local_intersection.t; @@ -636,7 +636,7 @@ dmnsn_prtree_intersection(const dmnsn_prtree *tree, dmnsn_line ray, /* Search the unbounded objects */ DMNSN_ARRAY_FOREACH (dmnsn_object **, object, tree->unbounded) { dmnsn_intersection local_intersection; - if ((*(*object)->intersection_fn)(*object, ray, &local_intersection)) { + if (dmnsn_object_intersection(*object, ray, &local_intersection)) { if (local_intersection.t < t) { *intersection = local_intersection; t = local_intersection.t; @@ -667,7 +667,7 @@ dmnsn_prtree_inside_recursive(const dmnsn_prtree_node *node, dmnsn_vector point) if (dmnsn_bounding_box_contains(node->bounding_boxes[i], point)) { if (node->is_leaf) { dmnsn_object *object = node->children[i]; - if ((*object->inside_fn)(object, point)) + if (dmnsn_object_inside(object, point)) return true; } else { if (dmnsn_prtree_inside_recursive(node->children[i], point)) @@ -684,7 +684,7 @@ dmnsn_prtree_inside(const dmnsn_prtree *tree, dmnsn_vector point) { /* Search the unbounded objects */ DMNSN_ARRAY_FOREACH (dmnsn_object **, object, tree->unbounded) { - if ((*(*object)->inside_fn)(*object, point)) + if (dmnsn_object_inside(*object, point)) return true; } diff --git a/libdimension/sphere.c b/libdimension/sphere.c index 490074b..7ff2292 100644 --- a/libdimension/sphere.c +++ b/libdimension/sphere.c @@ -47,11 +47,9 @@ dmnsn_new_sphere() /* Returns the closest intersection of `line' with `sphere' */ static bool -dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line line, +dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line l, dmnsn_intersection *intersection) { - dmnsn_line l = dmnsn_transform_line(sphere->trans_inv, line); - /* Solve (x0 + nx*t)^2 + (y0 + ny*t)^2 + (z0 + nz*t)^2 == 1 */ double poly[3], x[2]; poly[2] = dmnsn_vector_dot(l.n, l.n); @@ -66,10 +64,9 @@ dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line line, if (n == 2) t = dmnsn_min(t, x[1]); - intersection->ray = line; + intersection->ray = l; intersection->t = t; - intersection->normal = dmnsn_transform_normal(sphere->trans, - dmnsn_line_point(l, t)); + intersection->normal = dmnsn_line_point(l, t); intersection->texture = sphere->texture; intersection->interior = sphere->interior; return true; @@ -80,6 +77,5 @@ dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line line, static bool dmnsn_sphere_inside_fn(const dmnsn_object *sphere, dmnsn_vector point) { - point = dmnsn_transform_vector(sphere->trans_inv, point); return point.x*point.x + point.y*point.y + point.z*point.z < 1.0; } diff --git a/libdimension/torus.c b/libdimension/torus.c index df78212..702404b 100644 --- a/libdimension/torus.c +++ b/libdimension/torus.c @@ -105,10 +105,9 @@ dmnsn_torus_bound_intersection(const dmnsn_torus_payload *payload, dmnsn_line l) /* Returns the closest intersection of `line' with `torus' */ static bool -dmnsn_torus_intersection_fn(const dmnsn_object *torus, dmnsn_line line, +dmnsn_torus_intersection_fn(const dmnsn_object *torus, dmnsn_line l, dmnsn_intersection *intersection) { - dmnsn_line l = dmnsn_transform_line(torus->trans_inv, line); const dmnsn_torus_payload *payload = torus->ptr; double R = payload->major, r = payload->minor; double R2 = R*R, r2 = r*r; @@ -152,9 +151,9 @@ dmnsn_torus_intersection_fn(const dmnsn_object *torus, dmnsn_line line, dmnsn_vector_normalize(dmnsn_new_vector(p.x, 0.0, p.z)) ); dmnsn_vector normal = dmnsn_vector_normalize(dmnsn_vector_sub(p, center)); - intersection->ray = line; + intersection->ray = l; intersection->t = t; - intersection->normal = dmnsn_transform_normal(torus->trans, normal); + intersection->normal = normal; intersection->texture = torus->texture; intersection->interior = torus->interior; return true; @@ -164,7 +163,6 @@ dmnsn_torus_intersection_fn(const dmnsn_object *torus, dmnsn_line line, static bool dmnsn_torus_inside_fn(const dmnsn_object *torus, dmnsn_vector point) { - point = dmnsn_transform_vector(torus->trans_inv, point); const dmnsn_torus_payload *payload = torus->ptr; double dmajor = payload->major - sqrt(point.x*point.x + point.z*point.z); return dmajor*dmajor + point.y*point.y < payload->minor*payload->minor; diff --git a/tests/libdimension/prtree.c b/tests/libdimension/prtree.c index 2cf259f..e8e9953 100644 --- a/tests/libdimension/prtree.c +++ b/tests/libdimension/prtree.c @@ -64,6 +64,7 @@ main(void) dmnsn_object *object = dmnsn_new_object(); dmnsn_randomize_bounding_box(object); object->intersection_fn = &dmnsn_fake_intersection_fn; + dmnsn_object_init(object); dmnsn_array_push(scene->objects, &object); } |