summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdimension/bvst.c33
-rw-r--r--libdimension/canvas_pigment.c2
-rw-r--r--libdimension/csg.c131
-rw-r--r--libdimension/cube.c35
-rw-r--r--libdimension/dimension/object.h4
-rw-r--r--libdimension/dimension/texture.h11
-rw-r--r--libdimension/object.c25
-rw-r--r--libdimension/sphere.c18
-rw-r--r--libdimension/texture.c21
9 files changed, 149 insertions, 131 deletions
diff --git a/libdimension/bvst.c b/libdimension/bvst.c
index 9f9e94b..c0888bb 100644
--- a/libdimension/bvst.c
+++ b/libdimension/bvst.c
@@ -101,10 +101,9 @@ static void dmnsn_bvst_node_swallow(dmnsn_bvst_node *node,
void
dmnsn_bvst_insert(dmnsn_bvst *tree, dmnsn_object *object)
{
- dmnsn_bvst_node *node = dmnsn_new_bvst_node(), *parent = tree->root;
+ dmnsn_object_precompute(object);
- /* Store the inverse of the transformation matrix */
- object->trans_inv = dmnsn_matrix_inverse(object->trans);
+ dmnsn_bvst_node *node = dmnsn_new_bvst_node(), *parent = tree->root;
node->contains = NULL;
node->container = NULL;
@@ -112,8 +111,7 @@ dmnsn_bvst_insert(dmnsn_bvst *tree, dmnsn_object *object)
node->object = object;
/* Calculate the new bounding box */
- node->bounding_box = dmnsn_matrix_bounding_box_mul(object->trans,
- object->bounding_box);
+ node->bounding_box = object->bounding_box;
/* Now insert the node */
@@ -283,7 +281,6 @@ static bool dmnsn_ray_box_intersection(dmnsn_line ray, dmnsn_bounding_box box,
static dmnsn_bvst_search_result
dmnsn_bvst_search_recursive(dmnsn_bvst_node *node, dmnsn_line ray, double t)
{
- dmnsn_line ray_trans;
dmnsn_bvst_search_result result_temp, result = {
.node = NULL,
.intersected = false
@@ -303,14 +300,11 @@ dmnsn_bvst_search_recursive(dmnsn_bvst_node *node, dmnsn_line ray, double t)
if (dmnsn_bounding_box_contains(node->bounding_box, ray.x0)
|| dmnsn_ray_box_intersection(ray, node->bounding_box, t))
{
- /* Transform the ray according to the object */
- ray_trans = dmnsn_matrix_line_mul(node->object->trans_inv, ray);
-
- if (dmnsn_bounding_box_contains(node->object->bounding_box, ray_trans.x0)
- || dmnsn_ray_box_intersection(ray_trans, node->object->bounding_box, t))
+ if (dmnsn_bounding_box_contains(node->object->bounding_box, ray.x0)
+ || dmnsn_ray_box_intersection(ray, node->object->bounding_box, t))
{
result_temp.intersected =
- (*node->object->intersection_fn)(node->object, ray_trans,
+ (*node->object->intersection_fn)(node->object, ray,
&result_temp.intersection);
if (result_temp.intersected
@@ -319,21 +313,6 @@ dmnsn_bvst_search_recursive(dmnsn_bvst_node *node, dmnsn_line ray, double t)
result.intersected = true;
result.intersection = result_temp.intersection;
t = result.intersection.t;
-
- /* Transform the intersection back to the observer's view */
- result.intersection.ray = ray;
- result.intersection.normal = dmnsn_vector_normalize(
- dmnsn_vector_sub(
- dmnsn_matrix_vector_mul(
- node->object->trans,
- result.intersection.normal
- ),
- dmnsn_matrix_vector_mul(
- node->object->trans,
- dmnsn_zero
- )
- )
- );
}
}
diff --git a/libdimension/canvas_pigment.c b/libdimension/canvas_pigment.c
index b4c6823..ad68fe1 100644
--- a/libdimension/canvas_pigment.c
+++ b/libdimension/canvas_pigment.c
@@ -40,6 +40,8 @@ dmnsn_new_canvas_pigment(dmnsn_canvas *canvas)
static dmnsn_color
dmnsn_canvas_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v)
{
+ v = dmnsn_matrix_vector_mul(pigment->trans_inv, v);
+
dmnsn_canvas *canvas = pigment->ptr;
int x = v.x*(canvas->x - 1) + 0.5;
diff --git a/libdimension/csg.c b/libdimension/csg.c
index f5156f3..14f2980 100644
--- a/libdimension/csg.c
+++ b/libdimension/csg.c
@@ -36,25 +36,15 @@ dmnsn_csg_union_intersection_fn(const dmnsn_object *csg,
dmnsn_line line,
dmnsn_intersection *intersection)
{
- const dmnsn_object **params = csg->ptr;
+ dmnsn_line line_trans = dmnsn_matrix_line_mul(csg->trans_inv, line);
- dmnsn_line line1 = dmnsn_matrix_line_mul(params[0]->trans_inv, line);
- dmnsn_line line2 = dmnsn_matrix_line_mul(params[1]->trans_inv, line);
+ const dmnsn_object **params = csg->ptr;
dmnsn_intersection i1, i2;
- bool is_i1 = (*params[0]->intersection_fn)(params[0], line1, &i1);
- bool is_i2 = (*params[1]->intersection_fn)(params[1], line2, &i2);
+ bool is_i1 = (*params[0]->intersection_fn)(params[0], line_trans, &i1);
+ bool is_i2 = (*params[1]->intersection_fn)(params[1], line_trans, &i2);
if (is_i1) {
- /* Transform the intersection back to the observer's view */
- 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)
@@ -62,14 +52,6 @@ dmnsn_csg_union_intersection_fn(const dmnsn_object *csg,
}
if (is_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)
@@ -87,6 +69,10 @@ dmnsn_csg_union_intersection_fn(const dmnsn_object *csg,
} else {
*intersection = i2;
}
+
+ intersection->ray = line;
+ intersection->normal = dmnsn_matrix_normal_mul(csg->trans,
+ intersection->normal);
return true;
}
@@ -101,8 +87,8 @@ dmnsn_csg_union_inside_fn(const dmnsn_object *csg, dmnsn_vector point)
dmnsn_object *
dmnsn_new_csg_union(dmnsn_object *A, dmnsn_object *B)
{
- A->trans_inv = dmnsn_matrix_inverse(A->trans);
- B->trans_inv = dmnsn_matrix_inverse(B->trans);
+ dmnsn_object_precompute(A);
+ dmnsn_object_precompute(B);
dmnsn_object *csg = dmnsn_new_object();
@@ -115,12 +101,10 @@ dmnsn_new_csg_union(dmnsn_object *A, dmnsn_object *B)
csg->inside_fn = &dmnsn_csg_union_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);
+ csg->bounding_box.min
+ = dmnsn_vector_min(A->bounding_box.min, B->bounding_box.min);
+ csg->bounding_box.max
+ = dmnsn_vector_max(A->bounding_box.max, B->bounding_box.max);
return csg;
}
@@ -131,29 +115,22 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line,
dmnsn_intersection *intersection,
bool inside1, bool inside2)
{
- /* inside1 is whether the first object is allowed inside the second object;
+ /* inside1 is whether the second object is allowed inside the first object;
respectively for inside2 */
- const dmnsn_object **params = csg->ptr;
+ dmnsn_line line_trans = dmnsn_matrix_line_mul(csg->trans_inv, line);
- dmnsn_line line1 = dmnsn_matrix_line_mul(params[0]->trans_inv, line);
- dmnsn_line line2 = dmnsn_matrix_line_mul(params[1]->trans_inv, line);
+ const dmnsn_object **params = csg->ptr;
dmnsn_intersection i1, i2;
- bool is_i1 = (*params[0]->intersection_fn)(params[0], line1, &i1);
- bool is_i2 = (*params[1]->intersection_fn)(params[1], line2, &i2);
+ bool is_i1 = (*params[0]->intersection_fn)(params[0], line_trans, &i1);
+ bool is_i2 = (*params[1]->intersection_fn)(params[1], line_trans, &i2);
double oldt = 0.0;
while (is_i1) {
- i1.ray = line;
+ i1.ray = line_trans;
i1.t += oldt;
oldt = i1.t + dmnsn_epsilon;
- 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;
@@ -161,11 +138,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line,
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 (inside1 ^ (*params[1]->inside_fn)(params[1], point)) {
- line1.x0 = dmnsn_line_point(line1, i1.t);
- line1 = dmnsn_line_add_epsilon(line1);
- is_i1 = (*params[0]->intersection_fn)(params[0], line1, &i1);
+ if (inside2 ^ (*params[1]->inside_fn)(params[1], point)) {
+ dmnsn_line newline = line_trans;
+ newline.x0 = dmnsn_line_point(line_trans, i1.t);
+ newline = dmnsn_line_add_epsilon(newline);
+ is_i1 = (*params[0]->intersection_fn)(params[0], newline, &i1);
} else {
break;
}
@@ -173,15 +150,9 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line,
oldt = 0.0;
while (is_i2) {
- i2.ray = line;
+ i2.ray = line_trans;
i2.t += oldt;
oldt = i2.t + dmnsn_epsilon;
- 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;
@@ -189,11 +160,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line,
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 (inside2 ^ (*params[0]->inside_fn)(params[0], point)) {
- line2.x0 = dmnsn_line_point(line2, i2.t);
- line2 = dmnsn_line_add_epsilon(line2);
- is_i2 = (*params[1]->intersection_fn)(params[1], line2, &i2);
+ if (inside1 ^ (*params[0]->inside_fn)(params[0], point)) {
+ dmnsn_line newline = line_trans;
+ newline.x0 = dmnsn_line_point(line_trans, i2.t);
+ newline = dmnsn_line_add_epsilon(newline);
+ is_i2 = (*params[1]->intersection_fn)(params[1], newline, &i2);
} else {
break;
}
@@ -210,6 +181,10 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line,
} else {
*intersection = i2;
}
+
+ intersection->ray = line;
+ intersection->normal = dmnsn_matrix_normal_mul(csg->trans,
+ intersection->normal);
return true;
}
@@ -234,8 +209,8 @@ dmnsn_csg_intersection_inside_fn(const dmnsn_object *csg, dmnsn_vector point)
dmnsn_object *
dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B)
{
- A->trans_inv = dmnsn_matrix_inverse(A->trans);
- B->trans_inv = dmnsn_matrix_inverse(B->trans);
+ dmnsn_object_precompute(A);
+ dmnsn_object_precompute(B);
dmnsn_object *csg = dmnsn_new_object();
@@ -248,12 +223,10 @@ dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B)
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_max(Abox.min, Bbox.min);
- csg->bounding_box.max = dmnsn_vector_min(Abox.max, Bbox.max);
+ csg->bounding_box.min
+ = dmnsn_vector_max(A->bounding_box.min, B->bounding_box.min);
+ csg->bounding_box.max
+ = dmnsn_vector_min(A->bounding_box.max, B->bounding_box.max);
return csg;
}
@@ -265,7 +238,7 @@ dmnsn_csg_difference_intersection_fn(const dmnsn_object *csg,
dmnsn_line line,
dmnsn_intersection *intersection)
{
- return dmnsn_csg_intersection_fn(csg, line, intersection, false, true);
+ return dmnsn_csg_intersection_fn(csg, line, intersection, true, false);
}
static bool
@@ -279,8 +252,8 @@ dmnsn_csg_difference_inside_fn(const dmnsn_object *csg, dmnsn_vector point)
dmnsn_object *
dmnsn_new_csg_difference(dmnsn_object *A, dmnsn_object *B)
{
- A->trans_inv = dmnsn_matrix_inverse(A->trans);
- B->trans_inv = dmnsn_matrix_inverse(B->trans);
+ dmnsn_object_precompute(A);
+ dmnsn_object_precompute(B);
dmnsn_object *csg = dmnsn_new_object();
@@ -292,7 +265,7 @@ dmnsn_new_csg_difference(dmnsn_object *A, dmnsn_object *B)
csg->intersection_fn = &dmnsn_csg_difference_intersection_fn;
csg->inside_fn = &dmnsn_csg_difference_inside_fn;
csg->free_fn = &dmnsn_csg_free_fn;
- csg->bounding_box = dmnsn_matrix_bounding_box_mul(A->trans, A->bounding_box);
+ csg->bounding_box = A->bounding_box;
return csg;
}
@@ -318,8 +291,8 @@ dmnsn_csg_merge_inside_fn(const dmnsn_object *csg, dmnsn_vector point)
dmnsn_object *
dmnsn_new_csg_merge(dmnsn_object *A, dmnsn_object *B)
{
- A->trans_inv = dmnsn_matrix_inverse(A->trans);
- B->trans_inv = dmnsn_matrix_inverse(B->trans);
+ dmnsn_object_precompute(A);
+ dmnsn_object_precompute(B);
dmnsn_object *csg = dmnsn_new_object();
@@ -332,12 +305,10 @@ dmnsn_new_csg_merge(dmnsn_object *A, dmnsn_object *B)
csg->inside_fn = &dmnsn_csg_merge_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);
+ csg->bounding_box.min
+ = dmnsn_vector_min(A->bounding_box.min, B->bounding_box.min);
+ csg->bounding_box.max
+ = dmnsn_vector_max(A->bounding_box.max, B->bounding_box.max);
return csg;
}
diff --git a/libdimension/cube.c b/libdimension/cube.c
index 19c67b9..dfd1757 100644
--- a/libdimension/cube.c
+++ b/libdimension/cube.c
@@ -49,15 +49,17 @@ static bool
dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
dmnsn_intersection *intersection)
{
+ dmnsn_line line_trans = dmnsn_matrix_line_mul(cube->trans_inv, line);
+
double t = -1.0, t_temp;
dmnsn_vector p, normal;
/* Six ray-plane intersection tests (x, y, z) = +/- 1.0 */
- if (line.n.x != 0.0) {
+ if (line_trans.n.x != 0.0) {
/* x = -1.0 */
- t_temp = (-1.0 - line.x0.x)/line.n.x;
- p = dmnsn_line_point(line, t_temp);
+ t_temp = (-1.0 - line_trans.x0.x)/line_trans.n.x;
+ p = dmnsn_line_point(line_trans, t_temp);
if (p.y >= -1.0 && p.y <= 1.0 && p.z >= -1.0 && p.z <= 1.0
&& t_temp >= 0.0 && (t < 0.0 || t_temp < t))
{
@@ -66,8 +68,8 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
}
/* x = 1.0 */
- t_temp = (1.0 - line.x0.x)/line.n.x;
- p = dmnsn_line_point(line, t_temp);
+ t_temp = (1.0 - line_trans.x0.x)/line_trans.n.x;
+ p = dmnsn_line_point(line_trans, t_temp);
if (p.y >= -1.0 && p.y <= 1.0 && p.z >= -1.0 && p.z <= 1.0
&& t_temp >= 0.0 && (t < 0.0 || t_temp < t))
{
@@ -76,10 +78,10 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
}
}
- if (line.n.y != 0.0) {
+ if (line_trans.n.y != 0.0) {
/* y = -1.0 */
- t_temp = (-1.0 - line.x0.y)/line.n.y;
- p = dmnsn_line_point(line, t_temp);
+ t_temp = (-1.0 - line_trans.x0.y)/line_trans.n.y;
+ p = dmnsn_line_point(line_trans, t_temp);
if (p.x >= -1.0 && p.x <= 1.0 && p.z >= -1.0 && p.z <= 1.0
&& t_temp >= 0.0 && (t < 0.0 || t_temp < t))
{
@@ -88,8 +90,8 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
}
/* y = 1.0 */
- t_temp = (1.0 - line.x0.y)/line.n.y;
- p = dmnsn_line_point(line, t_temp);
+ t_temp = (1.0 - line_trans.x0.y)/line_trans.n.y;
+ p = dmnsn_line_point(line_trans, t_temp);
if (p.x >= -1.0 && p.x <= 1.0 && p.z >= -1.0 && p.z <= 1.0
&& t_temp >= 0.0 && (t < 0.0 || t_temp < t))
{
@@ -98,10 +100,10 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
}
}
- if (line.n.z != 0.0) {
+ if (line_trans.n.z != 0.0) {
/* z = -1.0 */
- t_temp = (-1.0 - line.x0.z)/line.n.z;
- p = dmnsn_line_point(line, t_temp);
+ t_temp = (-1.0 - line_trans.x0.z)/line_trans.n.z;
+ p = dmnsn_line_point(line_trans, t_temp);
if (p.x >= -1.0 && p.x <= 1.0 && p.y >= -1.0 && p.y <= 1.0
&& t_temp >= 0.0 && (t < 0.0 || t_temp < t))
{
@@ -110,8 +112,8 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
}
/* z = 1.0 */
- t_temp = (1.0 - line.x0.z)/line.n.z;
- p = dmnsn_line_point(line, t_temp);
+ t_temp = (1.0 - line_trans.x0.z)/line_trans.n.z;
+ p = dmnsn_line_point(line_trans, t_temp);
if (p.x >= -1.0 && p.x <= 1.0 && p.y >= -1.0 && p.y <= 1.0
&& t_temp >= 0.0 && (t < 0.0 || t_temp < t))
{
@@ -123,7 +125,7 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line,
if (t >= 0.0) {
intersection->ray = line;
intersection->t = t;
- intersection->normal = normal;
+ intersection->normal = dmnsn_matrix_normal_mul(cube->trans, normal);
intersection->texture = cube->texture;
intersection->interior = cube->interior;
return true;
@@ -136,6 +138,7 @@ 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_matrix_vector_mul(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/dimension/object.h b/libdimension/dimension/object.h
index f0395cd..1d5f580 100644
--- a/libdimension/dimension/object.h
+++ b/libdimension/dimension/object.h
@@ -41,6 +41,8 @@ typedef struct dmnsn_intersection {
const dmnsn_interior *interior;
} dmnsn_intersection;
+dmnsn_vector dmnsn_matrix_normal_mul(dmnsn_matrix trans, dmnsn_vector normal);
+
/* Forward-declare dmnsn_object */
typedef struct dmnsn_object dmnsn_object;
@@ -80,4 +82,6 @@ dmnsn_object *dmnsn_new_object();
/* Free an object */
void dmnsn_delete_object(dmnsn_object *object);
+void dmnsn_object_precompute(dmnsn_object *object);
+
#endif /* DIMENSION_OBJECT_H */
diff --git a/libdimension/dimension/texture.h b/libdimension/dimension/texture.h
index 70cfdc5..91dda23 100644
--- a/libdimension/dimension/texture.h
+++ b/libdimension/dimension/texture.h
@@ -42,6 +42,9 @@ struct dmnsn_pigment {
dmnsn_pigment_fn *pigment_fn;
dmnsn_free_fn *free_fn;
+ /* Transformation matrix */
+ dmnsn_matrix trans, trans_inv;
+
/* Generic pointer */
void *ptr;
};
@@ -49,6 +52,8 @@ struct dmnsn_pigment {
dmnsn_pigment *dmnsn_new_pigment();
void dmnsn_delete_pigment(dmnsn_pigment *pigment);
+void dmnsn_pigment_precompute(dmnsn_pigment *pigment);
+
/*
* Finishes
*/
@@ -91,11 +96,17 @@ void dmnsn_delete_finish(dmnsn_finish *finish);
*/
typedef struct {
+ /* Texture components */
dmnsn_pigment *pigment;
dmnsn_finish *finish;
+
+ /* Transformation matrix */
+ dmnsn_matrix trans, trans_inv;
} dmnsn_texture;
dmnsn_texture *dmnsn_new_texture();
void dmnsn_delete_texture(dmnsn_texture *texture);
+void dmnsn_texture_precompute(dmnsn_texture *texture);
+
#endif /* DIMENSION_TEXTURE_H */
diff --git a/libdimension/object.c b/libdimension/object.c
index 890d0e0..3cf68c7 100644
--- a/libdimension/object.c
+++ b/libdimension/object.c
@@ -20,6 +20,17 @@
#include "dimension.h"
+dmnsn_vector
+dmnsn_matrix_normal_mul(dmnsn_matrix trans, dmnsn_vector normal)
+{
+ return dmnsn_vector_normalize(
+ dmnsn_vector_sub(
+ dmnsn_matrix_vector_mul(trans, normal),
+ dmnsn_matrix_vector_mul(trans, dmnsn_zero)
+ )
+ );
+}
+
/* Allocate a dummy object */
dmnsn_object *
dmnsn_new_object()
@@ -45,3 +56,17 @@ dmnsn_delete_object(dmnsn_object *object)
free(object);
}
}
+
+/* Precompute object properties */
+void
+dmnsn_object_precompute(dmnsn_object *object)
+{
+ object->bounding_box
+ = dmnsn_matrix_bounding_box_mul(object->trans, object->bounding_box);
+ object->trans_inv = dmnsn_matrix_inverse(object->trans);
+ if (object->texture) {
+ object->texture->trans
+ = dmnsn_matrix_mul(object->trans, object->texture->trans);
+ dmnsn_texture_precompute(object->texture);
+ }
+}
diff --git a/libdimension/sphere.c b/libdimension/sphere.c
index 09b6767..94ae44e 100644
--- a/libdimension/sphere.c
+++ b/libdimension/sphere.c
@@ -19,7 +19,7 @@
*************************************************************************/
#include "dimension.h"
-#include <math.h> /* For sqrt */
+#include <math.h> /* For sqrt */
/*
* Sphere
@@ -50,13 +50,13 @@ static bool
dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line line,
dmnsn_intersection *intersection)
{
- double a, b, c, t;
-
+ dmnsn_line l = dmnsn_matrix_line_mul(sphere->trans_inv, line);
+
/* Solve (x0 + nx*t)^2 + (y0 + ny*t)^2 + (z0 + nz*t)^2 == 1 */
-
- a = line.n.x*line.n.x + line.n.y*line.n.y + line.n.z*line.n.z;
- b = 2.0*(line.n.x*line.x0.x + line.n.y*line.x0.y + line.n.z*line.x0.z);
- c = line.x0.x*line.x0.x + line.x0.y*line.x0.y + line.x0.z*line.x0.z - 1.0;
+ double a, b, c, t;
+ a = l.n.x*l.n.x + l.n.y*l.n.y + l.n.z*l.n.z;
+ b = 2.0*(l.n.x*l.x0.x + l.n.y*l.x0.y + l.n.z*l.x0.z);
+ c = l.x0.x*l.x0.x + l.x0.y*l.x0.y + l.x0.z*l.x0.z - 1.0;
if (b*b - 4.0*a*c >= 0) {
t = (-b - sqrt(b*b - 4.0*a*c))/(2*a);
@@ -67,7 +67,8 @@ dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line line,
if (t >= 0.0) {
intersection->ray = line;
intersection->t = t;
- intersection->normal = dmnsn_line_point(line, t);
+ intersection->normal = dmnsn_matrix_normal_mul(sphere->trans,
+ dmnsn_line_point(l, t));
intersection->texture = sphere->texture;
intersection->interior = sphere->interior;
return true;
@@ -81,5 +82,6 @@ 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_matrix_vector_mul(sphere->trans_inv, point);
return point.x*point.x + point.y*point.y + point.z*point.z < 1.0;
}
diff --git a/libdimension/texture.c b/libdimension/texture.c
index e08d595..d1047b7 100644
--- a/libdimension/texture.c
+++ b/libdimension/texture.c
@@ -26,6 +26,7 @@ dmnsn_new_pigment()
{
dmnsn_pigment *pigment = dmnsn_malloc(sizeof(dmnsn_pigment));
pigment->free_fn = NULL;
+ pigment->trans = dmnsn_identity_matrix();
return pigment;
}
@@ -41,6 +42,13 @@ dmnsn_delete_pigment(dmnsn_pigment *pigment)
}
}
+/* Precompute pigment properties */
+void
+dmnsn_pigment_precompute(dmnsn_pigment *pigment)
+{
+ pigment->trans_inv = dmnsn_matrix_inverse(pigment->trans);
+}
+
/* Allocate a dummy finish */
dmnsn_finish *
dmnsn_new_finish()
@@ -73,6 +81,7 @@ dmnsn_new_texture()
dmnsn_texture *texture = dmnsn_malloc(sizeof(dmnsn_texture));
texture->pigment = NULL;
texture->finish = NULL;
+ texture->trans = dmnsn_identity_matrix();
return texture;
}
@@ -86,3 +95,15 @@ dmnsn_delete_texture(dmnsn_texture *texture)
free(texture);
}
}
+
+/* Calculate matrix inverses */
+void
+dmnsn_texture_precompute(dmnsn_texture *texture)
+{
+ texture->trans_inv = dmnsn_matrix_inverse(texture->trans);
+ if (texture->pigment) {
+ texture->pigment->trans
+ = dmnsn_matrix_mul(texture->trans, texture->pigment->trans);
+ dmnsn_pigment_precompute(texture->pigment);
+ }
+}