diff options
author | Tavian Barnes <tavianator@gmail.com> | 2009-06-14 01:48:35 +0000 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2009-06-14 01:48:35 +0000 |
commit | 3ce0bfcd0e16d909b7495f07c9e8a82e4781ee88 (patch) | |
tree | 98ba25a085f0a06ab41a152fff3f065909611a91 | |
parent | 9f8055ac23b829babe5ed469251435b64ac82831 (diff) | |
download | dimension-3ce0bfcd0e16d909b7495f07c9e8a82e4781ee88.tar.xz |
Make raytracing engine multi-threaded.
-rw-r--r-- | libdimension/Makefile.am | 2 | ||||
-rw-r--r-- | libdimension/array.c | 9 | ||||
-rw-r--r-- | libdimension/dimension/array.h | 5 | ||||
-rw-r--r-- | libdimension/raytrace.c | 103 | ||||
-rw-r--r-- | libdimension/scene.c | 22 | ||||
-rw-r--r-- | tests/raytrace.c | 7 |
6 files changed, 120 insertions, 28 deletions
diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am index 91d0af0..2b5784a 100644 --- a/libdimension/Makefile.am +++ b/libdimension/Makefile.am @@ -21,6 +21,6 @@ nobase_include_HEADERS = dimension.h dimension/array.h dimension/camera.h dimens lib_LTLIBRARIES = libdimension.la -libdimension_la_SOURCES = $(nobase_include_HEADERS) array.c camera.c canvas.c color.c cube.c error.c geometry.c png.c object.c scene.c sphere.c +libdimension_la_SOURCES = $(nobase_include_HEADERS) array.c camera.c canvas.c color.c cube.c error.c geometry.c png.c object.c raytrace.c scene.c sphere.c libdimension_la_LDFLAGS = -version-info 0:0:0 libdimension_la_LIBADD = -lm -lpthread -lpng diff --git a/libdimension/array.c b/libdimension/array.c index e6e4363..88eb88f 100644 --- a/libdimension/array.c +++ b/libdimension/array.c @@ -53,6 +53,15 @@ dmnsn_array_pop(dmnsn_array *array, void *obj) dmnsn_array_resize(array, array->length - 1); } +void * +dmnsn_array_at(dmnsn_array *array, size_t i) +{ + if (i >= array->length) { + dmnsn_error(DMNSN_SEVERITY_HIGH, "Array index out of bounds."); + } + return array->ptr + array->obj_size*i; +} + void dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj) { diff --git a/libdimension/dimension/array.h b/libdimension/dimension/array.h index 9ee3584..0a64952 100644 --- a/libdimension/dimension/array.h +++ b/libdimension/dimension/array.h @@ -38,8 +38,9 @@ dmnsn_array *dmnsn_new_array(size_t obj_size); void dmnsn_array_push(dmnsn_array *array, const void *obj); void dmnsn_array_pop(dmnsn_array *array, void *obj); -void dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj); -void dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj); +void *dmnsn_array_at(dmnsn_array *array, size_t i); +void dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj); +void dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj); void dmnsn_array_resize(dmnsn_array *array, size_t length); diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c new file mode 100644 index 0000000..5d728d5 --- /dev/null +++ b/libdimension/raytrace.c @@ -0,0 +1,103 @@ +/************************************************************************* + * 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/>. * + *************************************************************************/ + +#include "dimension.h" +#include <unistd.h> /* For sysconf */ + +typedef struct { + dmnsn_scene *scene; + unsigned int i, n; +} dmnsn_raytrace_thread_payload; + +static void *dmnsn_raytrace_scene_thread(void *arg); + +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); + } + + for (i = 0; i < n; ++i) { + dmnsn_array_get(threads, i, &thread); + pthread_join(thread, NULL); + } + + dmnsn_delete_array(payloads); + dmnsn_delete_array(threads); +} + +/* Raytrace a scene */ +static void * +dmnsn_raytrace_scene_thread(void *arg) +{ + unsigned int i, j, k; + dmnsn_object *object; + dmnsn_line ray; + dmnsn_raytrace_thread_payload *payload = (dmnsn_raytrace_thread_payload *)arg; + dmnsn_scene *scene = payload->scene; + dmnsn_array *intersections; + + /* 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 */ + dmnsn_set_pixel(scene->canvas, i, j, scene->background); + + /* 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 < scene->objects->length; ++k) { + dmnsn_array_get(scene->objects, k, &object); + /* Test for an intersection with an object */ + intersections = (*object->intersections_fn)(object, ray); + if (intersections->length > 0) { + /* Mark intersections white */ + dmnsn_set_pixel(scene->canvas, i, j, + dmnsn_color_from_XYZ(dmnsn_whitepoint)); + dmnsn_delete_array(intersections); + break; + } + dmnsn_delete_array(intersections); + } + } + } + } +} diff --git a/libdimension/scene.c b/libdimension/scene.c index 4a84823..048ad45 100644 --- a/libdimension/scene.c +++ b/libdimension/scene.c @@ -38,25 +38,3 @@ dmnsn_delete_scene(dmnsn_scene *scene) free(scene); } } - -void -dmnsn_raytrace_scene(dmnsn_scene *scene) -{ - unsigned int i, j; - dmnsn_object *object; - dmnsn_line ray; - - dmnsn_array_get(scene->objects, 0, &object); - - for (i = 0; i < scene->canvas->x; ++i) { - for (j = 0; j < scene->canvas->y; ++j) { - ray = (*scene->camera->ray_fn)(scene->camera, scene->canvas, i, j); - if ((*object->intersections_fn)(object, ray)->length > 0) { - dmnsn_set_pixel(scene->canvas, i, j, - dmnsn_color_from_XYZ(dmnsn_whitepoint)); - } else { - dmnsn_set_pixel(scene->canvas, i, j, scene->background); - } - } - } -} diff --git a/tests/raytrace.c b/tests/raytrace.c index 1fbf837..de1bc89 100644 --- a/tests/raytrace.c +++ b/tests/raytrace.c @@ -25,7 +25,7 @@ int main() { FILE *file; dmnsn_scene *scene; - dmnsn_object *object; + dmnsn_object *cube; dmnsn_sRGB sRGB; dmnsn_color color; dmnsn_matrix trans; @@ -58,14 +58,15 @@ int main() { color.filter = 0.1; scene->background = color; - object = dmnsn_new_cube(); - dmnsn_array_push(scene->objects, &object); + cube = dmnsn_new_cube(); + dmnsn_array_push(scene->objects, &cube); dmnsn_raytrace_scene(scene); file = fopen("raytrace.png", "wb"); dmnsn_png_write_canvas(scene->canvas, file); + dmnsn_delete_cube(cube); dmnsn_delete_perspective_camera(scene->camera); dmnsn_delete_canvas(scene->canvas); dmnsn_delete_scene(scene); |