diff options
-rw-r--r-- | libdimension/Makefile.am | 1 | ||||
-rw-r--r-- | libdimension/dimension.h | 1 | ||||
-rw-r--r-- | libdimension/dimension/raytrace.h | 27 | ||||
-rw-r--r-- | libdimension/raytrace.c | 153 | ||||
-rw-r--r-- | tests/raytrace.c | 9 |
5 files changed, 122 insertions, 69 deletions
diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am index 2bdc0e9..d73f1e7 100644 --- a/libdimension/Makefile.am +++ b/libdimension/Makefile.am @@ -28,6 +28,7 @@ nobase_include_HEADERS = dimension.h \ dimension/png.h \ dimension/progress.h \ dimension/object.h \ + dimension/raytrace.h \ dimension/scene.h \ dimension/sphere.h diff --git a/libdimension/dimension.h b/libdimension/dimension.h index bdf298e..5820200 100644 --- a/libdimension/dimension.h +++ b/libdimension/dimension.h @@ -37,6 +37,7 @@ extern "C" { #include <dimension/cube.h> #include <dimension/camera.h> #include <dimension/scene.h> +#include <dimension/raytrace.h> #include <dimension/png.h> #ifdef __cplusplus diff --git a/libdimension/dimension/raytrace.h b/libdimension/dimension/raytrace.h new file mode 100644 index 0000000..a69bb72 --- /dev/null +++ b/libdimension/dimension/raytrace.h @@ -0,0 +1,27 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes <tavianator@gmail.com> * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * <http://www.gnu.org/licenses/>. * + *************************************************************************/ + +#ifndef DIMENSION_RAYTRACE_H +#define DIMENSION_RAYTRACE_H + +void dmnsn_raytrace_scene(dmnsn_scene *scene); +dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene); + +#endif /* DIMENSION_RAYTRACE_H */ diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c index 8a01f23..bd423c2 100644 --- a/libdimension/raytrace.c +++ b/libdimension/raytrace.c @@ -22,98 +22,117 @@ #include <unistd.h> /* For sysconf */ typedef struct { + dmnsn_progress *progress; dmnsn_scene *scene; - unsigned int i, n; -} dmnsn_raytrace_thread_payload; +} dmnsn_raytrace_payload; -static void *dmnsn_raytrace_scene_thread(void *arg); +static void *dmnsn_raytrace_scene_thread(void *ptr); void dmnsn_raytrace_scene(dmnsn_scene *scene) { - long n = sysconf(_SC_NPROCESSORS_ONLN); - unsigned int i; - pthread_t thread; - dmnsn_raytrace_thread_payload payload; - dmnsn_array *threads, *payloads; - - threads = dmnsn_new_array(sizeof(pthread_t)); - payloads = dmnsn_new_array(sizeof(dmnsn_raytrace_thread_payload)); - - if (n <= 0) n = 1; - - payload.scene = scene; - payload.n = n; - for (i = 0; i < n; ++i) { - payload.i = i; - dmnsn_array_push(payloads, &payload); - - pthread_create(&thread, NULL, &dmnsn_raytrace_scene_thread, - dmnsn_array_at(payloads, i)); - dmnsn_array_push(threads, &thread); - } + dmnsn_progress *progress = dmnsn_raytrace_scene_async(scene); + dmnsn_finish_progress(progress); +} + +dmnsn_progress * +dmnsn_raytrace_scene_async(dmnsn_scene *scene) +{ + dmnsn_progress *progress = dmnsn_new_progress(); + dmnsn_raytrace_payload *payload; + + if (progress) { + payload = malloc(sizeof(dmnsn_raytrace_payload)); + if (!payload) { + dmnsn_delete_progress(progress); + return NULL; + } - for (i = 0; i < n; ++i) { - dmnsn_array_get(threads, i, &thread); - pthread_join(thread, NULL); + payload->progress = progress; + payload->scene = scene; + + if (pthread_create(&progress->thread, NULL, &dmnsn_raytrace_scene_thread, + payload) + != 0) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Creating raytracing worker thread failed."); + dmnsn_delete_progress(progress); + return NULL; + } } - dmnsn_delete_array(payloads); - dmnsn_delete_array(threads); + return progress; } -/* Raytrace a scene */ +static void dmnsn_raytrace_scene_impl(dmnsn_progress *progress, + dmnsn_scene *scene); + static void * -dmnsn_raytrace_scene_thread(void *arg) +dmnsn_raytrace_scene_thread(void *ptr) +{ + dmnsn_raytrace_payload *payload = ptr; + int *retval = malloc(sizeof(int)); + if (retval) { + dmnsn_raytrace_scene_impl(payload->progress, payload->scene); + *retval = 0; + } + dmnsn_progress_done(payload->progress); + return retval; +} + +/* Actually raytrace a scene */ +static void +dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene) { unsigned int i, j, k, l; + unsigned int width, height; double t, t_temp; dmnsn_object *object; dmnsn_line ray, ray_trans; - dmnsn_raytrace_thread_payload *payload = (dmnsn_raytrace_thread_payload *)arg; - dmnsn_scene *scene = payload->scene; dmnsn_array *intersections; dmnsn_color color; dmnsn_sRGB sRGB; - /* Iterate through each pixel */ - for (i = 0; i < scene->canvas->x; ++i) { - for (j = 0; j < scene->canvas->y; ++j) { - /* Only do the pixels assigned to this thread */ - if ((j*scene->canvas->x + i)%payload->n == payload->i) { - /* Set the pixel to the background color */ - color = scene->background; - t = 0.0; - - /* Get the ray corresponding to the (i,j)th pixel */ - ray = (*scene->camera->ray_fn)(scene->camera, scene->canvas, i, j); - - for (k = 0; k < dmnsn_array_size(scene->objects); ++k) { - dmnsn_array_get(scene->objects, k, &object); - - /* Transform the ray according to the object */ - ray_trans = dmnsn_matrix_line_mul(object->trans, ray); - - /* Test for intersections with objects */ - intersections = (*object->intersections_fn)(object, ray_trans); - for (l = 0; l < dmnsn_array_size(intersections); ++l) { - dmnsn_array_get(intersections, l, &t_temp); - if (t_temp < t || t == 0.0) t = t_temp; - } - dmnsn_delete_array(intersections); - } + width = scene->canvas->x; + height = scene->canvas->y; + + dmnsn_new_progress_element(progress, height); - if (t != 0.0) { - sRGB.R = 1.0 - (t - 2.25)/2.25; - sRGB.G = sRGB.R; - sRGB.B = sRGB.R; - color = dmnsn_color_from_sRGB(sRGB); + /* Iterate through each pixel */ + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + /* Set the pixel to the background color */ + color = scene->background; + t = 0.0; + + /* Get the ray corresponding to the (i,j)th pixel */ + ray = (*scene->camera->ray_fn)(scene->camera, scene->canvas, i, j); + + for (k = 0; k < dmnsn_array_size(scene->objects); ++k) { + dmnsn_array_get(scene->objects, k, &object); + + /* Transform the ray according to the object */ + ray_trans = dmnsn_matrix_line_mul(object->trans, ray); + + /* Test for intersections with objects */ + intersections = (*object->intersections_fn)(object, ray_trans); + for (l = 0; l < dmnsn_array_size(intersections); ++l) { + dmnsn_array_get(intersections, l, &t_temp); + if (t_temp < t || t == 0.0) t = t_temp; } + dmnsn_delete_array(intersections); + } - dmnsn_set_pixel(scene->canvas, i, j, color); + if (t != 0.0) { + sRGB.R = 1.0 - (t - 2.25)/2.25; + sRGB.G = sRGB.R; + sRGB.B = sRGB.R; + color = dmnsn_color_from_sRGB(sRGB); } + + dmnsn_set_pixel(scene->canvas, i, j, color); } - } - return NULL; + dmnsn_increment_progress(progress); + } } diff --git a/tests/raytrace.c b/tests/raytrace.c index bb26f58..7ea28da 100644 --- a/tests/raytrace.c +++ b/tests/raytrace.c @@ -24,6 +24,7 @@ int main() { + dmnsn_progress *progress; FILE *file; dmnsn_scene *scene; dmnsn_object *sphere, *cube; @@ -71,10 +72,14 @@ main() { ); dmnsn_array_push(scene->objects, &cube); - dmnsn_raytrace_scene(scene); + progress = dmnsn_raytrace_scene_async(scene); + progressbar("Raytracing scene: ", progress); + dmnsn_finish_progress(progress); file = fopen("raytrace.png", "wb"); - dmnsn_png_write_canvas(scene->canvas, file); + progress = dmnsn_png_write_canvas_async(scene->canvas, file); + progressbar("Writing PNG file: ", progress); + dmnsn_finish_progress(progress); dmnsn_delete_cube(cube); dmnsn_delete_sphere(sphere); |