summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdimension/Makefile.am1
-rw-r--r--libdimension/dimension.h1
-rw-r--r--libdimension/dimension/raytrace.h27
-rw-r--r--libdimension/raytrace.c153
-rw-r--r--tests/raytrace.c9
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);