summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-01-07 02:30:28 -0500
committerTavian Barnes <tavianator@gmail.com>2010-01-07 02:30:28 -0500
commit2cca3158de0fbb40861a06f76bdd5043ac31f046 (patch)
tree1f90d401c2a63d66060ce52f42a5084bf2c25e09
parent21ba2912577aa7065dd92fb76142982246111687 (diff)
downloaddimension-2cca3158de0fbb40861a06f76bdd5043ac31f046.tar.xz
Clean up internal raytracing API a bit.
-rw-r--r--libdimension/raytrace.c134
1 files changed, 74 insertions, 60 deletions
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 7906df0..6d9d0d9 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -215,10 +215,16 @@ dmnsn_raytrace_scene_multithread_thread(void *ptr)
* Raytracing algorithm
*/
+typedef struct dmnsn_raytrace_state {
+ const dmnsn_scene *scene;
+ const dmnsn_intersection *intersection;
+ dmnsn_kD_splay_tree *kD_splay_tree;
+} dmnsn_raytrace_state;
+
/* Main helper for dmnsn_raytrace_scene_impl - shoot a ray */
-static dmnsn_color dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
- dmnsn_kD_splay_tree *kD_splay_tree,
- dmnsn_color color, unsigned int level);
+static dmnsn_color dmnsn_raytrace_shoot(dmnsn_raytrace_state *state,
+ dmnsn_line ray, dmnsn_color background,
+ unsigned int level);
/* Actually raytrace a scene */
static int
@@ -226,28 +232,31 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene,
dmnsn_kD_splay_tree *kD_splay_tree,
unsigned int index, unsigned int threads)
{
- unsigned int x, y;
- unsigned int width, height;
- dmnsn_line ray;
- dmnsn_color color;
+ dmnsn_raytrace_state state = {
+ .scene = scene,
+ .kD_splay_tree = kD_splay_tree
+ };
- width = scene->canvas->x;
- height = scene->canvas->y;
+ unsigned int width = scene->canvas->x;
+ unsigned int height = scene->canvas->y;
/* Iterate through each pixel */
+ unsigned int y;
for (y = index; y < height; y += threads) {
+ unsigned int x;
for (x = 0; x < width; ++x) {
/* Set the pixel to the background color */
- color = scene->background;
+ dmnsn_color color = scene->background;
if (scene->quality & DMNSN_RENDER_OBJECTS) {
/* Get the ray corresponding to the (x,y)'th pixel */
- ray = (*scene->camera->ray_fn)(scene->camera,
- ((double)x)/(scene->canvas->x - 1),
- ((double)y)/(scene->canvas->y - 1));
+ dmnsn_line ray = (*scene->camera->ray_fn)(
+ scene->camera,
+ ((double)x)/(scene->canvas->x - 1),
+ ((double)y)/(scene->canvas->y - 1)
+ );
/* Shoot a ray */
- color = dmnsn_raytrace_shoot(ray, scene, kD_splay_tree, color,
- 10);
+ color = dmnsn_raytrace_shoot(&state, ray, color, 10);
}
dmnsn_set_pixel(scene->canvas, x, y, color);
@@ -259,6 +268,7 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene,
return 0;
}
+/* Add epsilon*l.n to l.x0, to avoid self-intersections */
static dmnsn_line
dmnsn_line_add_epsilon(dmnsn_line l)
{
@@ -272,25 +282,26 @@ dmnsn_line_add_epsilon(dmnsn_line l)
}
static dmnsn_color
-dmnsn_raytrace_pigment(dmnsn_intersection *intersection, dmnsn_scene *scene)
+dmnsn_raytrace_pigment(const dmnsn_raytrace_state *state)
{
/* Default to black if there's no texture/pigment */
dmnsn_color color = dmnsn_black;
/* Use the default texture if given a NULL texture */
- const dmnsn_texture *texture = intersection->texture ? intersection->texture
- : scene->default_texture;
+ const dmnsn_texture *texture
+ = state->intersection->texture ? state->intersection->texture
+ : state->scene->default_texture;
if (texture) {
/* Use the default pigment if given a NULL pigment */
const dmnsn_pigment *pigment
= texture->pigment ? texture->pigment
- : scene->default_texture->pigment;
+ : state->scene->default_texture->pigment;
if (pigment) {
color = (*pigment->pigment_fn)(
pigment,
- dmnsn_line_point(intersection->ray, intersection->t)
+ dmnsn_line_point(state->intersection->ray, state->intersection->t)
);
}
}
@@ -300,35 +311,41 @@ dmnsn_raytrace_pigment(dmnsn_intersection *intersection, dmnsn_scene *scene)
/* Get the color of a light ray at an intersection point */
static bool
-dmnsn_raytrace_light_ray(dmnsn_intersection *intersection, dmnsn_scene *scene,
- dmnsn_kD_splay_tree *kD_splay_tree,
+dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state,
const dmnsn_light *light, dmnsn_color *color,
unsigned int level)
{
*color = dmnsn_black;
- dmnsn_vector x0 = dmnsn_line_point(intersection->ray, intersection->t);
+ dmnsn_vector x0 = dmnsn_line_point(state->intersection->ray,
+ state->intersection->t);
dmnsn_line shadow_ray = dmnsn_new_line(x0, dmnsn_vector_sub(light->x0, x0));
/* Add epsilon to avoid hitting ourselves with the shadow ray */
shadow_ray = dmnsn_line_add_epsilon(shadow_ray);
/* Search for an object in the way of the light source */
- if (dmnsn_vector_dot(shadow_ray.n, intersection->normal) < 0.0)
+ if (dmnsn_vector_dot(shadow_ray.n, state->intersection->normal) < 0.0)
return false;
*color = (*light->light_fn)(light, x0);
- dmnsn_intersection *shadow_caster;
while (level) {
--level;
- shadow_caster = dmnsn_kD_splay_search(kD_splay_tree, shadow_ray);
+
+ dmnsn_intersection *shadow_caster = dmnsn_kD_splay_search(
+ state->kD_splay_tree,
+ shadow_ray
+ );
if (!shadow_caster || shadow_caster->t > 1.0) {
dmnsn_delete_intersection(shadow_caster);
break;
}
- dmnsn_color pigment = dmnsn_raytrace_pigment(shadow_caster, scene);
+ dmnsn_raytrace_state shadow_state = *state;
+ shadow_state.intersection = shadow_caster;
+
+ dmnsn_color pigment = dmnsn_raytrace_pigment(&shadow_state);
if (pigment.filter || pigment.trans) {
*color = dmnsn_color_filter(*color, pigment);
shadow_ray.x0 = dmnsn_line_point(shadow_ray, shadow_caster->t);
@@ -347,18 +364,19 @@ dmnsn_raytrace_light_ray(dmnsn_intersection *intersection, dmnsn_scene *scene,
}
static dmnsn_color
-dmnsn_raytrace_lighting(dmnsn_intersection *intersection, dmnsn_scene *scene,
- dmnsn_kD_splay_tree *kD_splay_tree, dmnsn_color color,
+dmnsn_raytrace_lighting(const dmnsn_raytrace_state *state, dmnsn_color color,
unsigned int level)
{
/* Use the default texture if given a NULL texture */
- const dmnsn_texture *texture = intersection->texture ? intersection->texture
- : scene->default_texture;
+ const dmnsn_texture *texture
+ = state->intersection->texture ? state->intersection->texture
+ : state->scene->default_texture;
const dmnsn_finish *finish = NULL;
if (texture) {
/* Use the default finish if given a NULL finish */
- finish = texture->finish ? texture->finish : scene->default_texture->finish;
+ finish = texture->finish ? texture->finish
+ : state->scene->default_texture->finish;
}
/* The illuminated color */
@@ -366,28 +384,28 @@ dmnsn_raytrace_lighting(dmnsn_intersection *intersection, dmnsn_scene *scene,
if (finish && finish->ambient_fn)
illum = (*finish->ambient_fn)(finish, color);
- dmnsn_vector x0 = dmnsn_line_point(intersection->ray, intersection->t);
+ dmnsn_vector x0 = dmnsn_line_point(state->intersection->ray,
+ state->intersection->t);
const dmnsn_light *light;
unsigned int i;
/* Iterate over each light */
- for (i = 0; i < dmnsn_array_size(scene->lights); ++i) {
- dmnsn_array_get(scene->lights, i, &light);
+ for (i = 0; i < dmnsn_array_size(state->scene->lights); ++i) {
+ dmnsn_array_get(state->scene->lights, i, &light);
dmnsn_color light_color;
- if (dmnsn_raytrace_light_ray(intersection, scene, kD_splay_tree, light,
- &light_color, level))
- {
- if (scene->quality & DMNSN_RENDER_FINISH
+ if (dmnsn_raytrace_light_ray(state, light, &light_color, level)) {
+ if (state->scene->quality & DMNSN_RENDER_FINISH
&& finish && finish->finish_fn)
{
dmnsn_vector ray = dmnsn_vector_normalize(
dmnsn_vector_sub(light->x0, x0)
);
- dmnsn_vector normal = intersection->normal;
- dmnsn_vector viewer
- = dmnsn_vector_normalize(dmnsn_vector_negate(intersection->ray.n));
+ dmnsn_vector normal = state->intersection->normal;
+ dmnsn_vector viewer = dmnsn_vector_normalize(
+ dmnsn_vector_negate(state->intersection->ray.n)
+ );
/* Get this light's color contribution to the object */
dmnsn_color contrib = (*finish->finish_fn)(finish,
@@ -405,22 +423,24 @@ dmnsn_raytrace_lighting(dmnsn_intersection *intersection, dmnsn_scene *scene,
/* Shoot a ray, and calculate the color, using `color' as the background */
static dmnsn_color
-dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
- dmnsn_kD_splay_tree *kD_splay_tree, dmnsn_color background,
- unsigned int level)
+dmnsn_raytrace_shoot(dmnsn_raytrace_state *state, dmnsn_line ray,
+ dmnsn_color background, unsigned int level)
{
if (level <= 0)
return dmnsn_black;
--level;
- dmnsn_intersection *intersection = dmnsn_kD_splay_search(kD_splay_tree, ray);
+ dmnsn_intersection *intersection
+ = dmnsn_kD_splay_search(state->kD_splay_tree, ray);
dmnsn_color color = background;
if (intersection) {
+ state->intersection = intersection;
+
/* Get the pigment of the object */
dmnsn_color pigment = dmnsn_black;
- if (scene->quality & DMNSN_RENDER_PIGMENT) {
- pigment = dmnsn_raytrace_pigment(intersection, scene);
+ if (state->scene->quality & DMNSN_RENDER_PIGMENT) {
+ pigment = dmnsn_raytrace_pigment(state);
}
color = pigment;
color.filter = 0.0;
@@ -428,12 +448,8 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
/* Account for finishes and shadows */
dmnsn_color illum = pigment;
- if (scene->quality & DMNSN_RENDER_LIGHTS) {
- illum = dmnsn_raytrace_lighting(intersection,
- scene,
- kD_splay_tree,
- pigment,
- level);
+ if (state->scene->quality & DMNSN_RENDER_LIGHTS) {
+ illum = dmnsn_raytrace_lighting(state, pigment, level);
}
color = illum;
color.filter = 0.0;
@@ -441,7 +457,7 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
/* Account for translucency */
dmnsn_color trans = illum;
- if (scene->quality & DMNSN_RENDER_TRANSLUCENCY
+ if (state->scene->quality & DMNSN_RENDER_TRANSLUCENCY
&& (pigment.filter || pigment.trans))
{
trans = dmnsn_color_mul(1.0 - pigment.filter - pigment.trans, illum);
@@ -454,11 +470,9 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
);
trans_ray = dmnsn_line_add_epsilon(trans_ray);
- dmnsn_color rec = dmnsn_raytrace_shoot(trans_ray,
- scene,
- kD_splay_tree,
- background,
- level);
+ dmnsn_raytrace_state recursive_state = *state;
+ dmnsn_color rec
+ = dmnsn_raytrace_shoot(&recursive_state, trans_ray, background, level);
dmnsn_color filtered = dmnsn_color_filter(rec, pigment);
trans = dmnsn_color_add(trans, filtered);
}