summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdimension/array.c25
-rw-r--r--libdimension/camera.c10
-rw-r--r--libdimension/canvas.c9
-rw-r--r--libdimension/color.c6
-rw-r--r--libdimension/cube.c4
-rw-r--r--libdimension/dimension.h4
-rw-r--r--libdimension/dimension/array.h14
-rw-r--r--libdimension/dimension/camera.h7
-rw-r--r--libdimension/dimension/canvas.h7
-rw-r--r--libdimension/dimension/color.h6
-rw-r--r--libdimension/dimension/cube.h6
-rw-r--r--libdimension/dimension/error.h19
-rw-r--r--libdimension/dimension/geometry.h4
-rw-r--r--libdimension/dimension/object.h7
-rw-r--r--libdimension/dimension/png.h4
-rw-r--r--libdimension/dimension/progress.h14
-rw-r--r--libdimension/dimension/raytrace.h4
-rw-r--r--libdimension/dimension/scene.h6
-rw-r--r--libdimension/dimension/sphere.h6
-rw-r--r--libdimension/error.c1
-rw-r--r--libdimension/object.c2
-rw-r--r--libdimension/png.c36
-rw-r--r--libdimension/progress.c31
-rw-r--r--libdimension/raytrace.c15
-rw-r--r--libdimension/scene.c2
-rw-r--r--libdimension/sphere.c7
-rw-r--r--libdimensionxx/cookie-fopencookie.cpp52
-rw-r--r--libdimensionxx/cookie-tmpfile.cpp83
-rw-r--r--libdimensionxx/dimensionxx/array.hpp7
-rw-r--r--libdimensionxx/dimensionxx/canvas.hpp4
-rw-r--r--libdimensionxx/dimensionxx/color.hpp4
-rw-r--r--libdimensionxx/dimensionxx/cookie.hpp4
-rw-r--r--libdimensionxx/dimensionxx/error.hpp6
-rw-r--r--libdimensionxx/dimensionxx/geometry.hpp55
-rw-r--r--libdimensionxx/dimensionxx/object.hpp4
-rw-r--r--libdimensionxx/dimensionxx/png.hpp4
-rw-r--r--libdimensionxx/dimensionxx/progress.hpp4
-rw-r--r--libdimensionxx/progress.cpp25
-rw-r--r--tests/error.c2
-rw-r--r--tests/png.c3
-rw-r--r--tests/pngxx.cpp3
-rw-r--r--tests/raytrace.c2
-rw-r--r--tests/tests.c1
-rw-r--r--tests/tests.h1
-rw-r--r--tests/testsxx.cpp1
-rw-r--r--tests/testsxx.hpp1
-rw-r--r--tests/warning.c2
47 files changed, 401 insertions, 123 deletions
diff --git a/libdimension/array.c b/libdimension/array.c
index f8f3c58..82588aa 100644
--- a/libdimension/array.c
+++ b/libdimension/array.c
@@ -26,6 +26,7 @@
static void dmnsn_array_get_impl(const dmnsn_array *array, size_t i, void *obj);
static void dmnsn_array_set_impl(dmnsn_array *array, size_t i, const void *obj);
+/* Allocate a new array - guaranteed not to fail if it returns */
dmnsn_array *
dmnsn_new_array(size_t obj_size)
{
@@ -35,11 +36,13 @@ dmnsn_new_array(size_t obj_size)
array->length = 0;
array->capacity = 4; /* Start with capacity of 4 */
+ /* Allocate the memory */
array->ptr = malloc(array->capacity*array->obj_size);
if (!array->ptr) {
dmnsn_error(DMNSN_SEVERITY_HIGH, "Array allocation failed.");
}
+ /* Allocate the read-write lock */
array->rwlock = malloc(sizeof(pthread_rwlock_t));
if (!array->rwlock || pthread_rwlock_init(array->rwlock, NULL) != 0) {
dmnsn_error(DMNSN_SEVERITY_HIGH, "Array rwlock allocation failed.");
@@ -49,6 +52,7 @@ dmnsn_new_array(size_t obj_size)
return array;
}
+/* Delete the array */
void dmnsn_delete_array(dmnsn_array *array) {
if (array) {
if (pthread_rwlock_destroy(array->rwlock) != 0) {
@@ -61,6 +65,7 @@ void dmnsn_delete_array(dmnsn_array *array) {
}
}
+/* Push obj to the end of the array, atomically */
void
dmnsn_array_push(dmnsn_array *array, const void *obj)
{
@@ -69,6 +74,7 @@ dmnsn_array_push(dmnsn_array *array, const void *obj)
dmnsn_array_unlock(array);
}
+/* Pop obj from the end of the array, atomically */
void
dmnsn_array_pop(dmnsn_array *array, void *obj)
{
@@ -76,11 +82,12 @@ dmnsn_array_pop(dmnsn_array *array, void *obj)
dmnsn_array_wrlock(array);
size = dmnsn_array_size_unlocked(array);
- dmnsn_array_get_impl(array, size - 1, obj);
- dmnsn_array_resize_unlocked(array, size - 1);
+ dmnsn_array_get_impl(array, size - 1, obj); /* Copy the object */
+ dmnsn_array_resize_unlocked(array, size - 1); /* Shrink the array */
dmnsn_array_unlock(array);
}
+/* Get the i'th object, bailing out if i is out of range */
void
dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj)
{
@@ -89,6 +96,7 @@ dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj)
dmnsn_array_unlock(array);
}
+/* Set the i'th object, expanding the array if necessary */
void
dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj)
{
@@ -97,6 +105,7 @@ dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj)
dmnsn_array_unlock(array);
}
+/* Get the size of the array, atomically */
size_t
dmnsn_array_size(const dmnsn_array *array)
{
@@ -109,6 +118,7 @@ dmnsn_array_size(const dmnsn_array *array)
return size;
}
+/* Set the size of the array, atomically */
void
dmnsn_array_resize(dmnsn_array *array, size_t length)
{
@@ -117,6 +127,7 @@ dmnsn_array_resize(dmnsn_array *array, size_t length)
dmnsn_array_unlock(array);
}
+/* Thread-unsafe range-checked element access */
void *
dmnsn_array_at(dmnsn_array *array, size_t i)
{
@@ -126,16 +137,19 @@ dmnsn_array_at(dmnsn_array *array, size_t i)
return (char *)array->ptr + array->obj_size*i;
}
+/* Get the size non-atomically, for manual locking */
size_t
dmnsn_array_size_unlocked(const dmnsn_array *array)
{
return array->length;
}
+/* Set the size non-atomically, for manual locking */
void
dmnsn_array_resize_unlocked(dmnsn_array *array, size_t length)
{
if (length > array->capacity) {
+ /* Resize if we don't have enough capacity */
array->capacity = length*2; /* We are greedy */
array->ptr = realloc(array->ptr, array->obj_size*array->capacity);
if (!array->ptr) {
@@ -146,6 +160,7 @@ dmnsn_array_resize_unlocked(dmnsn_array *array, size_t length)
array->length = length;
}
+/* Set a manual read-lock */
void
dmnsn_array_rdlock(const dmnsn_array *array)
{
@@ -157,6 +172,7 @@ dmnsn_array_rdlock(const dmnsn_array *array)
}
}
+/* Set a manual write-lock */
void
dmnsn_array_wrlock(dmnsn_array *array)
{
@@ -168,6 +184,7 @@ dmnsn_array_wrlock(dmnsn_array *array)
}
}
+/* Unset a manual lock */
void
dmnsn_array_unlock(const dmnsn_array *array)
{
@@ -178,19 +195,23 @@ dmnsn_array_unlock(const dmnsn_array *array)
}
}
+/* Actual "get" implementation */
static void
dmnsn_array_get_impl(const dmnsn_array *array, size_t i, void *obj)
{
if (i >= dmnsn_array_size_unlocked(array)) {
+ /* Range check failed */
dmnsn_error(DMNSN_SEVERITY_HIGH, "Array index out of bounds.");
}
memcpy(obj, array->ptr + array->obj_size*i, array->obj_size);
}
+/* Actual "set" implementation */
static void
dmnsn_array_set_impl(dmnsn_array *array, size_t i, const void *obj)
{
if (i >= dmnsn_array_size_unlocked(array)) {
+ /* Resize if i is out of range */
dmnsn_array_resize_unlocked(array, i + 1);
}
memcpy(array->ptr + array->obj_size*i, obj, array->obj_size);
diff --git a/libdimension/camera.c b/libdimension/camera.c
index 282daaf..c353cbe 100644
--- a/libdimension/camera.c
+++ b/libdimension/camera.c
@@ -21,12 +21,14 @@
#include "dimension.h"
#include <stdlib.h> /* For malloc */
+/* Allocate a new dummy camera */
dmnsn_camera *
dmnsn_new_camera()
{
return malloc(sizeof(dmnsn_camera));
}
+/* Free a dummy camera */
void
dmnsn_delete_camera(dmnsn_camera *camera)
{
@@ -35,11 +37,15 @@ dmnsn_delete_camera(dmnsn_camera *camera)
/* Perspective camera */
+/* Perspective camera ray callback */
static dmnsn_line dmnsn_perspective_camera_ray_fn(const dmnsn_camera *camera,
const dmnsn_canvas *canvas,
unsigned int x,
unsigned int y);
+/* Create a new perspective camera. Rays are aimed from the origin to a screen
+ located on the z = 1 frame, from (-0.5, -0.5) to (0.5, 0.5). Rays are then
+ transformed by the matrix `trans'. */
dmnsn_camera *
dmnsn_new_perspective_camera(dmnsn_matrix trans)
{
@@ -57,6 +63,7 @@ dmnsn_new_perspective_camera(dmnsn_matrix trans)
return camera;
}
+/* Delete a perspective camera */
void
dmnsn_delete_perspective_camera(dmnsn_camera *camera)
{
@@ -74,7 +81,10 @@ dmnsn_perspective_camera_ray_fn(const dmnsn_camera *camera,
dmnsn_matrix *trans = (dmnsn_matrix *)camera->ptr;
dmnsn_line l;
+ /* Rays originate at the origin, oddly enough */
l.x0 = dmnsn_vector_construct(0.0, 0.0, 0.0);
+
+ /* Aim at the z = 1 plane */
l.n.x = ((double)x)/(canvas->x - 1) - 0.5;
l.n.y = ((double)y)/(canvas->y - 1) - 0.5;
l.n.z = 1.0;
diff --git a/libdimension/canvas.c b/libdimension/canvas.c
index 516c978..13b1e9e 100644
--- a/libdimension/canvas.c
+++ b/libdimension/canvas.c
@@ -32,8 +32,6 @@ dmnsn_new_canvas(unsigned int x, unsigned int y)
dmnsn_canvas *canvas = malloc(sizeof(dmnsn_canvas));
if (canvas) {
- /* *canvas exists */
-
/* Set the width and height */
canvas->x = x;
canvas->y = y;
@@ -60,6 +58,7 @@ dmnsn_new_canvas(unsigned int x, unsigned int y)
/* pthread_rwlock_init failed. Destroy the locks we've already made,
free the canvas, and return NULL. We leak memory if destruction
fails (i.e. someone is somehow using an rwlock already). */
+
for (l = 0; l < j; ++l) {
for (k = 0; k < x; ++k) {
if (pthread_rwlock_destroy(&canvas->rwlocks[l*x + k]) != 0) {
@@ -96,8 +95,6 @@ dmnsn_delete_canvas(dmnsn_canvas *canvas)
unsigned int i, j;
if (canvas) {
- /* *canvas exists */
-
/* Destroy the rwlocks */
for (i = 0; i < canvas->x; ++i) {
for (j = 0; j < canvas->y; ++j) {
@@ -121,7 +118,7 @@ dmnsn_get_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y)
{
dmnsn_color color;
dmnsn_rdlock_pixel(canvas, x, y);
- color = canvas->pixels[y*canvas->x + x];
+ color = canvas->pixels[y*canvas->x + x];
dmnsn_unlock_pixel(canvas, x, y);
return color;
}
@@ -132,7 +129,7 @@ dmnsn_set_pixel(dmnsn_canvas *canvas,
unsigned int x, unsigned int y, dmnsn_color color)
{
dmnsn_wrlock_pixel(canvas, x, y);
- canvas->pixels[y*canvas->x + x] = color;
+ canvas->pixels[y*canvas->x + x] = color;
dmnsn_unlock_pixel(canvas, x, y);
}
diff --git a/libdimension/color.c b/libdimension/color.c
index 42ade8b..4aede1f 100644
--- a/libdimension/color.c
+++ b/libdimension/color.c
@@ -21,7 +21,7 @@
#include "dimension.h"
#include <math.h> /* For pow(), sqrt() */
-/* sRGB white point (D50) */
+/* sRGB white point (CIE D50) */
const dmnsn_CIE_XYZ dmnsn_whitepoint = { .X = 0.9504060171449392,
.Y = 0.9999085943425312,
.Z = 1.089062231497274 };
@@ -42,7 +42,8 @@ dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY)
dmnsn_color ret = { .X = xyY.Y*xyY.x/xyY.y,
.Y = xyY.Y,
.Z = xyY.Y*(1.0 - xyY.x - xyY.y)/xyY.y,
- .filter = 0.0, .trans = 0.0 };
+ .filter = 0.0,
+ .trans = 0.0 };
return ret;
}
@@ -267,6 +268,7 @@ dmnsn_color_add(dmnsn_color color1, dmnsn_color color2)
Lab.b = Lab1.b + Lab2.b;
ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint);
+ /* Waited average of transparencies by intensity */
ret.filter = (Lab1.L*color1.filter + Lab2.L*color2.filter)/Lab.L;
ret.trans = (Lab1.L*color1.trans + Lab2.L*color2.trans)/Lab.L;
diff --git a/libdimension/cube.c b/libdimension/cube.c
index 197a0f8..bb71d0b 100644
--- a/libdimension/cube.c
+++ b/libdimension/cube.c
@@ -27,6 +27,7 @@ static dmnsn_array *dmnsn_cube_intersections_fn(const dmnsn_object *cube,
static int dmnsn_cube_inside_fn(const dmnsn_object *cube,
dmnsn_vector point);
+/* Allocate a new cube object */
dmnsn_object *
dmnsn_new_cube()
{
@@ -38,12 +39,14 @@ dmnsn_new_cube()
return cube;
}
+/* Delete a cube */
void
dmnsn_delete_cube(dmnsn_object *cube)
{
dmnsn_delete_object(cube);
}
+/* Intersections callback for a cube */
static dmnsn_array *
dmnsn_cube_intersections_fn(const dmnsn_object *cube, dmnsn_line line)
{
@@ -104,6 +107,7 @@ dmnsn_cube_intersections_fn(const dmnsn_object *cube, dmnsn_line line)
return array;
}
+/* Inside callback for a cube */
static int
dmnsn_cube_inside_fn(const dmnsn_object *cube, dmnsn_vector point)
{
diff --git a/libdimension/dimension.h b/libdimension/dimension.h
index 5820200..5e262e3 100644
--- a/libdimension/dimension.h
+++ b/libdimension/dimension.h
@@ -18,6 +18,10 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/*
+ * libdimension - a library for photo-realistic 3-D rendering
+ */
+
#ifndef DIMENSION_H
#define DIMENSION_H
diff --git a/libdimension/dimension/array.h b/libdimension/dimension/array.h
index d0693fc..0af4406 100644
--- a/libdimension/dimension/array.h
+++ b/libdimension/dimension/array.h
@@ -18,14 +18,14 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_ARRAY_H
-#define DIMENSION_ARRAY_H
-
/*
* Simple thread-safe generalized arrays, for returning variable-length arrays
* from functions, and other fun stuff.
*/
+#ifndef DIMENSION_ARRAY_H
+#define DIMENSION_ARRAY_H
+
#include <pthread.h> /* For pthread_rwlock_t */
#include <stdlib.h> /* For size_t */
@@ -37,24 +37,26 @@ typedef struct {
pthread_rwlock_t *rwlock;
} dmnsn_array;
+/* Array allocation never returns NULL - if dmnsn_new_array, it succeeded */
dmnsn_array *dmnsn_new_array(size_t obj_size);
void dmnsn_delete_array(dmnsn_array *array);
+/* Thread-safe atomic array access */
+
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);
size_t dmnsn_array_size(const dmnsn_array *array);
void dmnsn_array_resize(dmnsn_array *array, size_t length);
-/* Manual locking */
-
+/* Non-atomic operations for manual locking */
void *dmnsn_array_at(dmnsn_array *array, size_t i);
size_t dmnsn_array_size_unlocked(const dmnsn_array *array);
void dmnsn_array_resize_unlocked(dmnsn_array *array, size_t length);
+/* Manual locking */
void dmnsn_array_rdlock(const dmnsn_array *array);
void dmnsn_array_wrlock(dmnsn_array *array);
void dmnsn_array_unlock(const dmnsn_array *array);
diff --git a/libdimension/dimension/camera.h b/libdimension/dimension/camera.h
index 95b36fa..9b06359 100644
--- a/libdimension/dimension/camera.h
+++ b/libdimension/dimension/camera.h
@@ -18,13 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_CAMERA_H
-#define DIMENSION_CAMERA_H
-
/*
* A camera.
*/
+#ifndef DIMENSION_CAMERA_H
+#define DIMENSION_CAMERA_H
+
/* Forward-declare dmnsn_camera */
typedef struct dmnsn_camera dmnsn_camera;
@@ -47,7 +47,6 @@ void dmnsn_delete_camera(dmnsn_camera *camera);
/* A perspective camera, at the origin, looking at (0, 0, 1). The feild of view
is the section of the plane z = 1 from (-0.5, -0.5) to (0.5, 0.5). Rays are
transformed by the transformation matrix `trans'. */
-
dmnsn_camera *dmnsn_new_perspective_camera(dmnsn_matrix trans);
void dmnsn_delete_perspective_camera(dmnsn_camera *camera);
diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h
index f05264b..50cc612 100644
--- a/libdimension/dimension/canvas.h
+++ b/libdimension/dimension/canvas.h
@@ -18,14 +18,15 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/*
+ * A canvas which is rendered to.
+ */
+
#ifndef DIMENSION_CANVAS_H
#define DIMENSION_CANVAS_H
#include <pthread.h>
-/*
- * A canvas which is rendered to.
- */
typedef struct {
unsigned int x, y;
diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h
index ab6efa3..f1964c3 100644
--- a/libdimension/dimension/color.h
+++ b/libdimension/dimension/color.h
@@ -18,13 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_COLOR_H
-#define DIMENSION_COLOR_H
-
/*
* Types to represent color.
*/
+#ifndef DIMENSION_COLOR_H
+#define DIMENSION_COLOR_H
+
/* Internally, we use CIE 1931 XYZ color. */
typedef struct {
double X, Y, Z;
diff --git a/libdimension/dimension/cube.h b/libdimension/dimension/cube.h
index e7f2b90..e55ec74 100644
--- a/libdimension/dimension/cube.h
+++ b/libdimension/dimension/cube.h
@@ -18,13 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_CUBE_H
-#define DIMENSION_CUBE_H
-
/*
* A cube, axis-aligned, from (-1, -1, -1) to (1, 1, 1)
*/
+#ifndef DIMENSION_CUBE_H
+#define DIMENSION_CUBE_H
+
dmnsn_object *dmnsn_new_cube();
void dmnsn_delete_cube(dmnsn_object *cube);
diff --git a/libdimension/dimension/error.h b/libdimension/dimension/error.h
index 3204cb2..cd7dd81 100644
--- a/libdimension/dimension/error.h
+++ b/libdimension/dimension/error.h
@@ -18,23 +18,26 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_ERROR_H
-#define DIMENSION_ERROR_H
-
/*
- * Error handling.
+ * Error handling. Errors are reported at a given severity by the dmnsn_error()
+ * macro at a given severity, which prints a warning if it is below the set
+ * resilience, or prints an error and exits if it's at or above the set
+ * resilience.
*/
+#ifndef DIMENSION_ERROR_H
+#define DIMENSION_ERROR_H
+
typedef enum {
DMNSN_SEVERITY_LOW, /* Only die on low resilience */
DMNSN_SEVERITY_MEDIUM, /* Die on low or medium resilience */
DMNSN_SEVERITY_HIGH /* Always die */
} dmnsn_severity;
-/* Use this to report an error */
-#define dmnsn_error(severity, str) \
- dmnsn_report_error((dmnsn_severity)severity, __PRETTY_FUNCTION__, __LINE__, \
- str)
+/* Use this macro to report an error */
+#define dmnsn_error(severity, str) \
+ dmnsn_report_error((dmnsn_severity)(severity), __PRETTY_FUNCTION__, __LINE__,\
+ (str))
/* Called by dmnsn_error() - don't call directly */
void dmnsn_report_error(dmnsn_severity severity,
diff --git a/libdimension/dimension/geometry.h b/libdimension/dimension/geometry.h
index 95692c6..c635fd9 100644
--- a/libdimension/dimension/geometry.h
+++ b/libdimension/dimension/geometry.h
@@ -19,7 +19,7 @@
*************************************************************************/
/*
- * Core geometric types like scalars, vectors, and rays.
+ * Core geometric types like vectors, matricies, and rays.
*/
#ifndef DIMENSION_GEOMETRY_H
@@ -73,6 +73,6 @@ dmnsn_line dmnsn_matrix_line_mul(dmnsn_matrix lhs, dmnsn_line rhs);
/* A point on a line, defined by x0 + t*n */
dmnsn_vector dmnsn_line_point(dmnsn_line l, double t);
/* Solve for the t value such that x0 + t*n = x */
-double dmnsn_line_index(dmnsn_line l, dmnsn_vector x);
+double dmnsn_line_index(dmnsn_line l, dmnsn_vector x);
#endif /* DIMENSION_GEOMETRY_H */
diff --git a/libdimension/dimension/object.h b/libdimension/dimension/object.h
index 589ac29..d18f426 100644
--- a/libdimension/dimension/object.h
+++ b/libdimension/dimension/object.h
@@ -18,13 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_OBJECT_H
-#define DIMENSION_OBJECT_H
-
/*
* Objects.
*/
+#ifndef DIMENSION_OBJECT_H
+#define DIMENSION_OBJECT_H
+
/* Forward-declare dmnsn_object */
typedef struct dmnsn_object dmnsn_object;
@@ -46,6 +46,7 @@ struct dmnsn_object {
dmnsn_object_inside_fn *inside_fn;
};
+/* Allocate a dummy object */
dmnsn_object *dmnsn_new_object();
void dmnsn_delete_object(dmnsn_object *object);
diff --git a/libdimension/dimension/png.h b/libdimension/dimension/png.h
index 05ff79a..858f79f 100644
--- a/libdimension/dimension/png.h
+++ b/libdimension/dimension/png.h
@@ -18,6 +18,10 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/*
+ * Support for exporting/importing canvases to/from PNG files
+ */
+
#ifndef DIMENSION_PNG_H
#define DIMENSION_PNG_H
diff --git a/libdimension/dimension/progress.h b/libdimension/dimension/progress.h
index a865c8f..7958ab9 100644
--- a/libdimension/dimension/progress.h
+++ b/libdimension/dimension/progress.h
@@ -18,6 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/*
+ * An interface for asynchronous tasks. *_async() versions of functions
+ * return a dmnsn_progress* object which can indicate the progress of the
+ * background task, and wait for task completion. The task's return value
+ * is returned as an int from dmnsn_finish_progress().
+ */
+
#ifndef DIMENSION_PROGRESS_H
#define DIMENSION_PROGRESS_H
@@ -43,6 +50,7 @@ typedef struct {
} dmnsn_progress;
dmnsn_progress *dmnsn_new_progress();
+/* For failed returns from *_async() functions */
void dmnsn_delete_progress(dmnsn_progress *progress);
/* This joins the worker thread and returns it's integer return value in
@@ -50,10 +58,14 @@ void dmnsn_delete_progress(dmnsn_progress *progress);
int dmnsn_finish_progress(dmnsn_progress *progress);
double dmnsn_get_progress(const dmnsn_progress *progress);
+/* Wait for the progress to be >= prog, in a better way than spinlocking */
void dmnsn_wait_progress(const dmnsn_progress *progress, double prog);
+/* Create a new level of loop nesting */
void dmnsn_new_progress_element(dmnsn_progress *progress, unsigned int total);
+/* Increment the progress counter; should only be called from innermost loop */
void dmnsn_increment_progress(dmnsn_progress *progress);
-void dmnsn_progress_done(dmnsn_progress *progress);
+/* Instantly complete the progress */
+void dmnsn_done_progress(dmnsn_progress *progress);
#endif /* DIMENSION_PROGRESS_H */
diff --git a/libdimension/dimension/raytrace.h b/libdimension/dimension/raytrace.h
index a69bb72..b58a39b 100644
--- a/libdimension/dimension/raytrace.h
+++ b/libdimension/dimension/raytrace.h
@@ -18,6 +18,10 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/*
+ * Render a scene by raytracing
+ */
+
#ifndef DIMENSION_RAYTRACE_H
#define DIMENSION_RAYTRACE_H
diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h
index a6f2e5d..35087a7 100644
--- a/libdimension/dimension/scene.h
+++ b/libdimension/dimension/scene.h
@@ -18,13 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_SCENE_H
-#define DIMENSION_SCENE_H
-
/*
* A scene.
*/
+#ifndef DIMENSION_SCENE_H
+#define DIMENSION_SCENE_H
+
typedef struct {
dmnsn_color background;
dmnsn_array *objects;
diff --git a/libdimension/dimension/sphere.h b/libdimension/dimension/sphere.h
index 2547965..d7a8f54 100644
--- a/libdimension/dimension/sphere.h
+++ b/libdimension/dimension/sphere.h
@@ -18,13 +18,13 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSION_SPHERE_H
-#define DIMENSION_SPHERE_H
-
/*
* A sphere object, of radius 1, centered at the origin.
*/
+#ifndef DIMENSION_SPHERE_H
+#define DIMENSION_SPHERE_H
+
dmnsn_object *dmnsn_new_sphere();
void dmnsn_delete_sphere(dmnsn_object *sphere);
diff --git a/libdimension/error.c b/libdimension/error.c
index a8c7ec7..df3ade3 100644
--- a/libdimension/error.c
+++ b/libdimension/error.c
@@ -63,6 +63,7 @@ dmnsn_get_resilience()
return resilience;
}
+/* Set the resilience, thread-safely */
void
dmnsn_set_resilience(dmnsn_severity resilience)
{
diff --git a/libdimension/object.c b/libdimension/object.c
index 75a82b6..dddcd61 100644
--- a/libdimension/object.c
+++ b/libdimension/object.c
@@ -21,6 +21,7 @@
#include "dimension.h"
#include <stdlib.h> /* For malloc */
+/* Allocate a dummy object */
dmnsn_object *
dmnsn_new_object()
{
@@ -31,6 +32,7 @@ dmnsn_new_object()
return object;
}
+/* Free a dummy object */
void
dmnsn_delete_object(dmnsn_object *object)
{
diff --git a/libdimension/png.c b/libdimension/png.c
index b8cfabc..6bb1f13 100644
--- a/libdimension/png.c
+++ b/libdimension/png.c
@@ -25,6 +25,8 @@
#include <arpa/inet.h>
#include <stdlib.h>
+/* Payload to store function arguments for thread callbacks */
+
typedef struct {
dmnsn_progress *progress;
const dmnsn_canvas *canvas;
@@ -37,6 +39,7 @@ typedef struct {
FILE *file;
} dmnsn_png_read_payload;
+/* Thread callbacks */
static void *dmnsn_png_write_canvas_thread(void *ptr);
static void *dmnsn_png_read_canvas_thread(void *ptr);
@@ -67,11 +70,11 @@ dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas, FILE *file)
payload->canvas = canvas;
payload->file = file;
+ /* Create the worker thread */
if (pthread_create(&progress->thread, NULL, &dmnsn_png_write_canvas_thread,
payload)
!= 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM,
- "Creating png writing worker thread failed.");
+ free(payload);
dmnsn_delete_progress(progress);
return NULL;
}
@@ -108,11 +111,11 @@ dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
payload->canvas = canvas;
payload->file = file;
+ /* Create the worker thread */
if (pthread_create(&progress->thread, NULL, &dmnsn_png_read_canvas_thread,
payload)
!= 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM,
- "Creating png writing worker thread failed.");
+ free(payload);
dmnsn_delete_progress(progress);
return NULL;
}
@@ -121,10 +124,14 @@ dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
return progress;
}
+/* Actual implementations */
static int dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
const dmnsn_canvas *canvas, FILE *file);
static dmnsn_canvas *dmnsn_png_read_canvas_impl(dmnsn_progress *progress,
FILE *file);
+
+/* Thread callbacks */
+
static void *
dmnsn_png_write_canvas_thread(void *ptr)
{
@@ -134,7 +141,8 @@ dmnsn_png_write_canvas_thread(void *ptr)
*retval = dmnsn_png_write_canvas_impl(payload->progress,
payload->canvas, payload->file);
}
- dmnsn_progress_done(payload->progress);
+ dmnsn_done_progress(payload->progress);
+ free(payload);
return retval;
}
@@ -146,12 +154,14 @@ dmnsn_png_read_canvas_thread(void *ptr)
if (retval) {
*payload->canvas = dmnsn_png_read_canvas_impl(payload->progress,
payload->file);
- *retval = payload->canvas ? 0 : 1;
+ *retval = payload->canvas ? 0 : 1; /* Fail if it returned NULL */
}
- dmnsn_progress_done(payload->progress);
+ dmnsn_done_progress(payload->progress);
+ free(payload);
return retval;
}
+/* Actually write the PNG file */
static int
dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
const dmnsn_canvas *canvas, FILE *file)
@@ -272,9 +282,11 @@ static pthread_key_t progress_key;
static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
static int progress_key_init = 0;
+/* Callback to increment the progress after a row has been read */
static void dmnsn_png_read_row_callback(png_structp png_ptr, png_uint_32 row,
int pass);
+/* Actually read a PNG file */
static dmnsn_canvas *
dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
{
@@ -301,9 +313,7 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
if (progress_key_init == 0) {
if (pthread_key_create(&progress_key, NULL) != 0) {
- /* High severity because dmnsn_png_read_row_callback will surely segfault
- if it can't get the dmnsn_progress* from the key */
- dmnsn_error(DMNSN_SEVERITY_HIGH,
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM,
"Couldn't create thread-specific pointer.");
}
@@ -311,7 +321,7 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
}
if (pthread_setspecific(progress_key, progress) != 0) {
- dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't set thread-specific pointer.");
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't set thread-specific pointer.");
}
if (pthread_mutex_unlock(&progress_mutex) != 0) {
@@ -506,5 +516,7 @@ static void
dmnsn_png_read_row_callback(png_structp png_ptr, png_uint_32 row, int pass)
{
dmnsn_progress *progress = pthread_getspecific(progress_key);
- dmnsn_increment_progress(progress);
+ if (progress) {
+ dmnsn_increment_progress(progress);
+ }
} \ No newline at end of file
diff --git a/libdimension/progress.c b/libdimension/progress.c
index 29469a6..f25af74 100644
--- a/libdimension/progress.c
+++ b/libdimension/progress.c
@@ -32,6 +32,8 @@ dmnsn_new_progress()
progress->elements = dmnsn_new_array(sizeof(dmnsn_progress_element));
dmnsn_array_push(progress->elements, &element);
+ /* Allocate space for the condition variable and mutex */
+
progress->cond = malloc(sizeof(pthread_cond_t));
if (!progress->cond) {
dmnsn_delete_array(progress->elements);
@@ -139,22 +141,22 @@ void
dmnsn_wait_progress(const dmnsn_progress *progress, double prog)
{
if (pthread_mutex_lock(progress->mutex) != 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't lock condition mutex.");
- }
-
- while (dmnsn_get_progress(progress) < prog) {
- if (pthread_cond_wait(progress->cond, progress->mutex) != 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM,
- "Couldn't wait on condition variable.");
+ dmnsn_error(DMNSN_SEVERITY_LOW, "Couldn't lock condition mutex.");
+ } else {
+ while (dmnsn_get_progress(progress) < prog) {
+ if (pthread_cond_wait(progress->cond, progress->mutex) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_LOW,
+ "Couldn't wait on condition variable.");
+ }
}
- }
- if (pthread_mutex_unlock(progress->mutex) != 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't unlock condition mutex.");
+ if (pthread_mutex_unlock(progress->mutex) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_LOW, "Couldn't unlock condition mutex.");
+ }
}
}
-/* A new level of algorithmic nesting */
+/* Start a new level of algorithmic nesting */
void
dmnsn_new_progress_element(dmnsn_progress *progress, unsigned int total)
{
@@ -173,13 +175,14 @@ dmnsn_increment_progress(dmnsn_progress *progress)
dmnsn_array_wrlock(progress->elements);
size = dmnsn_array_size_unlocked(progress->elements);
element = dmnsn_array_at(progress->elements, size - 1);
- ++element->progress;
+ ++element->progress; /* Increment the last element */
while (element->progress >= element->total && size > 1) {
+ /* As long as the last element is complete, pop it */
--size;
dmnsn_array_resize_unlocked(progress->elements, size);
element = dmnsn_array_at(progress->elements, size - 1);
- ++element->progress;
+ ++element->progress; /* Increment the next element */
}
if (pthread_cond_broadcast(progress->cond) != 0) {
@@ -190,7 +193,7 @@ dmnsn_increment_progress(dmnsn_progress *progress)
/* Immediately set to 100% completion */
void
-dmnsn_progress_done(dmnsn_progress *progress)
+dmnsn_done_progress(dmnsn_progress *progress)
{
dmnsn_progress_element *element;
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index bd423c2..aa3a445 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -21,13 +21,17 @@
#include "dimension.h"
#include <unistd.h> /* For sysconf */
+/* Payload type for passing arguments to worker thread */
+
typedef struct {
dmnsn_progress *progress;
dmnsn_scene *scene;
} dmnsn_raytrace_payload;
+/* Thread callback */
static void *dmnsn_raytrace_scene_thread(void *ptr);
+/* Raytrace a scene */
void
dmnsn_raytrace_scene(dmnsn_scene *scene)
{
@@ -35,6 +39,7 @@ dmnsn_raytrace_scene(dmnsn_scene *scene)
dmnsn_finish_progress(progress);
}
+/* Raytrace a scene in the background */
dmnsn_progress *
dmnsn_raytrace_scene_async(dmnsn_scene *scene)
{
@@ -54,8 +59,7 @@ dmnsn_raytrace_scene_async(dmnsn_scene *scene)
if (pthread_create(&progress->thread, NULL, &dmnsn_raytrace_scene_thread,
payload)
!= 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM,
- "Creating raytracing worker thread failed.");
+ free(payload);
dmnsn_delete_progress(progress);
return NULL;
}
@@ -64,9 +68,11 @@ dmnsn_raytrace_scene_async(dmnsn_scene *scene)
return progress;
}
+/* Actual raytracing implementation */
static void dmnsn_raytrace_scene_impl(dmnsn_progress *progress,
dmnsn_scene *scene);
+/* Thread callback */
static void *
dmnsn_raytrace_scene_thread(void *ptr)
{
@@ -76,7 +82,8 @@ dmnsn_raytrace_scene_thread(void *ptr)
dmnsn_raytrace_scene_impl(payload->progress, payload->scene);
*retval = 0;
}
- dmnsn_progress_done(payload->progress);
+ dmnsn_done_progress(payload->progress);
+ free(payload);
return retval;
}
@@ -116,6 +123,7 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene)
/* Test for intersections with objects */
intersections = (*object->intersections_fn)(object, ray_trans);
+ /* Find the closest intersection */
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;
@@ -123,6 +131,7 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene)
dmnsn_delete_array(intersections);
}
+ /* Shade according to distance from camera */
if (t != 0.0) {
sRGB.R = 1.0 - (t - 2.25)/2.25;
sRGB.G = sRGB.R;
diff --git a/libdimension/scene.c b/libdimension/scene.c
index 048ad45..9405f03 100644
--- a/libdimension/scene.c
+++ b/libdimension/scene.c
@@ -21,6 +21,7 @@
#include "dimension.h"
#include <stdlib.h> /* For malloc */
+/* Allocate an empty scene */
dmnsn_scene *
dmnsn_new_scene()
{
@@ -30,6 +31,7 @@ dmnsn_new_scene()
return scene;
}
+/* Free a scene */
void
dmnsn_delete_scene(dmnsn_scene *scene)
{
diff --git a/libdimension/sphere.c b/libdimension/sphere.c
index 5a4d1a9..f6950dc 100644
--- a/libdimension/sphere.c
+++ b/libdimension/sphere.c
@@ -22,11 +22,13 @@
#include <stdlib.h> /* For malloc */
#include <math.h> /* For sqrt */
+/* Sphere object callbacks */
static dmnsn_array *dmnsn_sphere_intersections_fn(const dmnsn_object *sphere,
dmnsn_line line);
static int dmnsn_sphere_inside_fn(const dmnsn_object *sphere,
dmnsn_vector point);
+/* Allocate a new sphere */
dmnsn_object *
dmnsn_new_sphere()
{
@@ -38,12 +40,14 @@ dmnsn_new_sphere()
return sphere;
}
+/* Free a sphere */
void
dmnsn_delete_sphere(dmnsn_object *sphere)
{
dmnsn_delete_object(sphere);
}
+/* Return a list of insersections of `line' with a sphere */
static dmnsn_array *
dmnsn_sphere_intersections_fn(const dmnsn_object *sphere, dmnsn_line line)
{
@@ -66,8 +70,9 @@ dmnsn_sphere_intersections_fn(const dmnsn_object *sphere, dmnsn_line line)
return array;
}
+/* Return whether a point is inside a sphere (x**2 + y**2 + z**2 < 1.0) */
static int
dmnsn_sphere_inside_fn(const dmnsn_object *sphere, dmnsn_vector point)
{
- return sqrt(point.x*point.x + point.y*point.y + point.z*point.z) < 1.0;
+ return point.x*point.x + point.y*point.y + point.z*point.z < 1.0;
}
diff --git a/libdimensionxx/cookie-fopencookie.cpp b/libdimensionxx/cookie-fopencookie.cpp
index 78b6e8b..070b038 100644
--- a/libdimensionxx/cookie-fopencookie.cpp
+++ b/libdimensionxx/cookie-fopencookie.cpp
@@ -21,6 +21,7 @@
#include "dimensionxx.hpp"
#ifndef _GNU_SOURCE
+// For fopencookie()
# define _GNU_SOURCE
#endif
#include <stdio.h>
@@ -99,7 +100,7 @@ namespace Dimension
}
if (streams->is_output()) {
- // If we have an output stream, seek it too
+ // If we have an output stream, seek it
switch (whence) {
case SEEK_SET:
streams->ostr().seekp(*offset, std::ios::beg);
@@ -164,14 +165,55 @@ namespace Dimension
// Close the file
FILE_Cookie::~FILE_Cookie() { std::fclose(m_file); }
+ // Get the FILE*
FILE* FILE_Cookie::file() { return m_file; }
const FILE* FILE_Cookie::file() const { return m_file; }
bool FILE_Cookie::is_input() const { return m_istr; }
bool FILE_Cookie::is_output() const { return m_ostr; }
- std::istream& FILE_Cookie::istr() { return *m_istr; }
- const std::istream& FILE_Cookie::istr() const { return *m_istr; }
- std::ostream& FILE_Cookie::ostr() { return *m_ostr; }
- const std::ostream& FILE_Cookie::ostr() const { return *m_ostr; }
+ // Get the C++ streams
+
+ std::istream&
+ FILE_Cookie::istr()
+ {
+ if (is_input()) {
+ return *m_istr;
+ } else {
+ throw Dimension_Error("Attempted to get input stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
+
+ const std::istream&
+ FILE_Cookie::istr() const
+ {
+ if (is_input()) {
+ return *m_istr;
+ } else {
+ throw Dimension_Error("Attempted to get input stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
+
+ std::ostream&
+ FILE_Cookie::ostr()
+ {
+ if (is_output()) {
+ return *m_ostr;
+ } else {
+ throw Dimension_Error("Attempted to get output stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
+
+ const std::ostream& FILE_Cookie::ostr() const
+ {
+ if (is_output()) {
+ return *m_ostr;
+ } else {
+ throw Dimension_Error("Attempted to get output stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
}
diff --git a/libdimensionxx/cookie-tmpfile.cpp b/libdimensionxx/cookie-tmpfile.cpp
index ec320d8..6a41f09 100644
--- a/libdimensionxx/cookie-tmpfile.cpp
+++ b/libdimensionxx/cookie-tmpfile.cpp
@@ -27,74 +27,85 @@ namespace Dimension
{
namespace
{
+ // Write an input stream completely to a FILE*; this works poorly for
+ // console input, which may not have an EOF in the near future
void
write_cookie(FILE* file, std::istream& istr)
{
+ const unsigned int bs = 8192; // Bytes to read at once
unsigned int count, pos;
- const unsigned int bs = 8192;
char buffer[bs];
- pos = istr.tellg();
- istr.seekg(0);
+ pos = istr.tellg(); // Get the stream's current position
+ istr.seekg(0); // Seek to the beginning
while (true) {
+ // Read the whole stream into `file', `bs' bytes at a time
istr.read(buffer, bs);
count = istr.gcount();
if (count != bs) {
if (istr.eof()) {
+ // We reached EOF; write the last count bytes
fwrite(buffer, 1, count, file);
break;
} else {
+ // Some other error
throw Dimension_Error("Error reading from input stream.");
}
}
+ // Write the next `bs' bytes
fwrite(buffer, 1, bs, file);
}
- fseek(file, pos, SEEK_SET);
+ fseek(file, pos, SEEK_SET); // Seek to the stream's initial position
}
+ // Read a C++ stream completely from a file
void
read_cookie(std::ostream& ostr, FILE* file)
{
+ const unsigned int bs = 8192; // Bytes to read at a time
unsigned int count, pos;
- const unsigned int bs = 8192;
char buffer[bs];
- pos = ftell(file);
- rewind(file);
+ pos = ftell(file); // Get the initial position
+ rewind(file); // Seek to the beginning
while (true) {
count = fread(buffer, 1, bs, file);
if (count != bs) {
if (feof(file)) {
+ // Reached EOF, write the last `count' bytes
ostr.write(buffer, count);
break;
} else {
+ // Some other error
throw Dimension_Error("Error reading from temporary file.");
}
}
+ // Write the next `bs' bytes
ostr.write(buffer, bs);
}
- ostr.seekp(pos);
+ ostr.seekp(pos); // Seek to the initial position of `file'
}
}
// Make an input FILE_Cookie
FILE_Cookie::FILE_Cookie(std::istream& istr)
- : m_file(tmpfile()), m_istr(&istr), m_ostr(0)
+ : m_file(std::tmpfile()), m_istr(&istr), m_ostr(0)
{
if (!m_file) {
throw Dimension_Error("Error opening temporary file for C++/C I/O"
" interface.");
}
+ // Write the input stream to the temporary file
write_cookie(m_file, *m_istr);
}
// Make an output FILE_Cookie
FILE_Cookie::FILE_Cookie(std::ostream& ostr)
- : m_file(tmpfile()), m_istr(0), m_ostr(&ostr)
+ : m_file(std::tmpfile()), m_istr(0), m_ostr(&ostr)
{
if (!m_file) {
throw Dimension_Error("Error opening temporary file for C++/C I/O"
@@ -104,13 +115,14 @@ namespace Dimension
// Make an I/O FILE_Cookie
FILE_Cookie::FILE_Cookie(std::iostream& iostr)
- : m_file(tmpfile()), m_istr(&iostr), m_ostr(&iostr)
+ : m_file(std::tmpfile()), m_istr(&iostr), m_ostr(&iostr)
{
if (!m_file) {
throw Dimension_Error("Error opening temporary file for C++/C I/O"
" interface.");
}
+ // Write the input stream to the temporary file
write_cookie(m_file, *m_istr);
}
@@ -123,14 +135,55 @@ namespace Dimension
std::fclose(m_file);
}
+ // Get the FILE*
FILE* FILE_Cookie::file() { return m_file; }
const FILE* FILE_Cookie::file() const { return m_file; }
bool FILE_Cookie::is_input() const { return m_istr; }
bool FILE_Cookie::is_output() const { return m_ostr; }
- std::istream& FILE_Cookie::istr() { return *m_istr; }
- const std::istream& FILE_Cookie::istr() const { return *m_istr; }
- std::ostream& FILE_Cookie::ostr() { return *m_ostr; }
- const std::ostream& FILE_Cookie::ostr() const { return *m_ostr; }
+ // Get the C++ streams
+
+ std::istream&
+ FILE_Cookie::istr()
+ {
+ if (is_input()) {
+ return *m_istr;
+ } else {
+ throw Dimension_Error("Attempted to get input stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
+
+ const std::istream&
+ FILE_Cookie::istr() const
+ {
+ if (is_input()) {
+ return *m_istr;
+ } else {
+ throw Dimension_Error("Attempted to get input stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
+
+ std::ostream&
+ FILE_Cookie::ostr()
+ {
+ if (is_output()) {
+ return *m_ostr;
+ } else {
+ throw Dimension_Error("Attempted to get output stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
+
+ const std::ostream& FILE_Cookie::ostr() const
+ {
+ if (is_output()) {
+ return *m_ostr;
+ } else {
+ throw Dimension_Error("Attempted to get output stream from non-input"
+ " FILE_Cookie.");
+ }
+ }
}
diff --git a/libdimensionxx/dimensionxx/array.hpp b/libdimensionxx/dimensionxx/array.hpp
index dfbf1c8..735e17a 100644
--- a/libdimensionxx/dimensionxx/array.hpp
+++ b/libdimensionxx/dimensionxx/array.hpp
@@ -18,14 +18,14 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// dmnsn_array* wrapper.
+
#ifndef DIMENSIONXX_ARRAY_HPP
#define DIMENSIONXX_ARRAY_HPP
#include <tr1/memory> // For tr1::shared_ptr
#include <cstdlib> // For size_t
-// dmnsn_array* wrapper.
-
namespace Dimension
{
// RAII scoped read-lock
@@ -148,6 +148,8 @@ namespace Dimension
return ret;
}
+ // Access the underlying dmnsn_array*
+
template <typename T>
dmnsn_array*
Array<T>::dmnsn()
@@ -170,6 +172,7 @@ namespace Dimension
return *m_array;
}
+ // Release the dmnsn_array*, if we are the only Array holding it
template <typename T>
dmnsn_array*
Array<T>::release()
diff --git a/libdimensionxx/dimensionxx/canvas.hpp b/libdimensionxx/dimensionxx/canvas.hpp
index eda9ad3..f9e77e5 100644
--- a/libdimensionxx/dimensionxx/canvas.hpp
+++ b/libdimensionxx/dimensionxx/canvas.hpp
@@ -18,11 +18,11 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// dmnsn_canvas* wrapper.
+
#ifndef DIMENSIONXX_CANVAS_HPP
#define DIMENSIONXX_CANVAS_HPP
-// dmnsn_canvas* wrapper.
-
namespace Dimension
{
// Base canvas class. Wraps a dmnsn_canvas*.
diff --git a/libdimensionxx/dimensionxx/color.hpp b/libdimensionxx/dimensionxx/color.hpp
index c79f86b..9289479 100644
--- a/libdimensionxx/dimensionxx/color.hpp
+++ b/libdimensionxx/dimensionxx/color.hpp
@@ -18,11 +18,11 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// Wrappers for libdimension colors.
+
#ifndef DIMENSIONXX_COLOR_HPP
#define DIMENSIONXX_COLOR_HPP
-// Wrappers for libdimension colors.
-
namespace Dimension
{
// Forward declarations
diff --git a/libdimensionxx/dimensionxx/cookie.hpp b/libdimensionxx/dimensionxx/cookie.hpp
index df26b93..0d8b4da 100644
--- a/libdimensionxx/dimensionxx/cookie.hpp
+++ b/libdimensionxx/dimensionxx/cookie.hpp
@@ -18,11 +18,11 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// Some internal magic to use C FILE* I/O with C++ streams.
+
#ifndef DIMENSIONXX_COOKIE_HPP
#define DIMENSIONXX_COOKIE_HPP
-// Some internal magic to use C FILE* I/O with C++ streams.
-
#include <istream>
#include <ostream>
#include <cstdio>
diff --git a/libdimensionxx/dimensionxx/error.hpp b/libdimensionxx/dimensionxx/error.hpp
index 99670cb..7fb0e53 100644
--- a/libdimensionxx/dimensionxx/error.hpp
+++ b/libdimensionxx/dimensionxx/error.hpp
@@ -18,14 +18,14 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#ifndef DIMENSIONXX_ERROR_HPP
-#define DIMENSIONXX_ERROR_HPP
-
// Wrappers for libdimension error handling, and an exception class.
// dmnsn_error is still used by libdimensionxx whenever an exception shouldn't
// be thrown, like in destructors, and whenever libdimension or libdimension-*
// use it internally. Exceptions are thrown otherwise to report errors.
+#ifndef DIMENSIONXX_ERROR_HPP
+#define DIMENSIONXX_ERROR_HPP
+
#include <dimension.h>
#include <stdexcept>
#include <string>
diff --git a/libdimensionxx/dimensionxx/geometry.hpp b/libdimensionxx/dimensionxx/geometry.hpp
index f623eda..606f83a 100644
--- a/libdimensionxx/dimensionxx/geometry.hpp
+++ b/libdimensionxx/dimensionxx/geometry.hpp
@@ -18,15 +18,17 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// Wrappers for geometric types (Vectors, Matricies, Lines (rays)).
+
#ifndef DIMENSIONXX_GEOMETRY_HPP
#define DIMENSIONXX_GEOMETRY_HPP
-// Wrappers for geometric types (Vectors, Matricies, Lines (rays)).
-
#include <dimension.h>
namespace Dimension
{
+ class Vector;
+
// Wrapper for dmnsn_matrix
class Matrix
{
@@ -56,6 +58,12 @@ namespace Dimension
// Get the wrapped matrix
dmnsn_matrix dmnsn() const { return m_matrix; }
+ // Special constructors
+ static inline Matrix identity();
+ static inline Matrix scale(const Vector& factor);
+ static inline Matrix translation(const Vector& d);
+ static inline Matrix rotation(const Vector& theta);
+
private:
dmnsn_matrix m_matrix;
};
@@ -126,6 +134,49 @@ namespace Dimension
dmnsn_line m_line;
};
+ // Matrix operators
+
+ inline Matrix
+ operator*(const Matrix& lhs, const Matrix& rhs)
+ {
+ // This order is important!
+ Matrix r = rhs;
+ r *= lhs;
+ return r;
+ }
+
+ inline Matrix
+ inverse(const Matrix& M)
+ {
+ return Matrix(dmnsn_matrix_inverse(M.dmnsn()));
+ }
+
+ // Special Matrix constructors
+
+ inline Matrix
+ Matrix::identity()
+ {
+ return Matrix(dmnsn_identity_matrix());
+ }
+
+ inline Matrix
+ Matrix::scale(const Vector& factor)
+ {
+ return Matrix(dmnsn_scale_matrix(factor.dmnsn()));
+ }
+
+ inline Matrix
+ Matrix::translation(const Vector& d)
+ {
+ return Matrix(dmnsn_translation_matrix(d.dmnsn()));
+ }
+
+ inline Matrix
+ Matrix::rotation(const Vector& theta)
+ {
+ return Matrix(dmnsn_rotation_matrix(theta.dmnsn()));
+ }
+
// Vector operators
inline Vector
diff --git a/libdimensionxx/dimensionxx/object.hpp b/libdimensionxx/dimensionxx/object.hpp
index 3b2c6c1..40dcb25 100644
--- a/libdimensionxx/dimensionxx/object.hpp
+++ b/libdimensionxx/dimensionxx/object.hpp
@@ -18,11 +18,11 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// dmnsn_object* wrapper.
+
#ifndef DIMENSIONXX_OBJECT_HPP
#define DIMENSIONXX_OBJECT_HPP
-// dmnsn_object* wrapper.
-
namespace Dimension
{
// Abstract base object class. Wraps a dmnsn_object*.
diff --git a/libdimensionxx/dimensionxx/png.hpp b/libdimensionxx/dimensionxx/png.hpp
index d768287..980840c 100644
--- a/libdimensionxx/dimensionxx/png.hpp
+++ b/libdimensionxx/dimensionxx/png.hpp
@@ -18,11 +18,11 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// C++ wrapper for libdimension PNG support. PNG_Canvas derives from Canvas.
+
#ifndef DIMENSIONXX_PNG_HPP
#define DIMENSIONXX_PNG_HPP
-// C++ wrapper for libdimension PNG support. PNG_Canvas derives from Canvas.
-
#include <istream>
#include <ostream>
diff --git a/libdimensionxx/dimensionxx/progress.hpp b/libdimensionxx/dimensionxx/progress.hpp
index b9df870..3fff1bc 100644
--- a/libdimensionxx/dimensionxx/progress.hpp
+++ b/libdimensionxx/dimensionxx/progress.hpp
@@ -18,14 +18,14 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// dmnsn_progress* wrapper.
+
#ifndef DIMENSIONXX_PROGRESS_HPP
#define DIMENSIONXX_PROGRESS_HPP
#include <tr1/memory> // For tr1::shared_ptr
#include <list>
-// dmnsn_canvas* wrapper.
-
namespace Dimension
{
// Base class for persisting objects
diff --git a/libdimensionxx/progress.cpp b/libdimensionxx/progress.cpp
index ca74571..0a32b72 100644
--- a/libdimensionxx/progress.cpp
+++ b/libdimensionxx/progress.cpp
@@ -25,14 +25,17 @@ namespace Dimension
Persist_Base::~Persist_Base()
{ }
+ // Construct a dmnsn_progress* wrapper
Progress::Progress(dmnsn_progress* progress)
: m_progress(new dmnsn_progress*(progress))
{ }
+ // Construct a dmnsn_progress* wrapper, with a known persister
Progress::Progress(dmnsn_progress* progress, const Persister& persister)
: m_progress(new dmnsn_progress*(progress)), m_persister(persister)
{ }
+ // Finish the progress if not yet finished and we are unique
Progress::~Progress()
{
if (m_progress && m_progress.unique()) {
@@ -45,45 +48,55 @@ namespace Dimension
}
}
+ // Get the current progress
double
Progress::progress() const
{
return dmnsn_get_progress(dmnsn());
}
+ // Wait until progress() >= progress
void
Progress::wait(double progress) const
{
dmnsn_wait_progress(dmnsn(), progress);
}
+ // Start a new level of loop nesting
void
Progress::new_element(unsigned int total)
{
dmnsn_new_progress_element(dmnsn(), total);
}
+ // Increment the progress
void
Progress::increment()
{
dmnsn_increment_progress(dmnsn());
}
+ // Immediately finish the progress
void
Progress::done()
{
- dmnsn_progress_done(dmnsn());
+ dmnsn_done_progress(dmnsn());
}
+ // Wait for progress completion
void
Progress::finish()
{
- if (m_progress.unique()) {
- dmnsn_finish_progress(dmnsn());
- m_progress.reset();
- } else {
+ if (!m_progress) {
+ throw Dimension_Error("Attempt to finish Progress twice.");
+ }
+
+ if (!m_progress.unique()) {
throw Dimension_Error("Attempt to finish non-unique Progress.");
}
+
+ dmnsn_finish_progress(dmnsn());
+ m_progress.reset(); // Don't try again
}
// Access the set of persisted objects
@@ -93,6 +106,8 @@ namespace Dimension
return m_persister;
}
+ // Access the underlying dmnsn_progress*
+
dmnsn_progress*
Progress::dmnsn()
{
diff --git a/tests/error.c b/tests/error.c
index 7bd8ef6..fd9fc75 100644
--- a/tests/error.c
+++ b/tests/error.c
@@ -18,6 +18,8 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/* Make sure that errors terminate us - this test should fail */
+
#include "tests.h"
#include <stdlib.h>
diff --git a/tests/png.c b/tests/png.c
index b80af04..3d46f38 100644
--- a/tests/png.c
+++ b/tests/png.c
@@ -18,6 +18,8 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/* Test PNG file I/O */
+
#include "tests.h"
#include <stdlib.h>
#include <stdio.h>
@@ -36,6 +38,7 @@ main() {
unsigned int i, j;
const unsigned int x = 333, y = 300;
+ /* Set the resilience low for tests */
dmnsn_set_resilience(DMNSN_SEVERITY_LOW);
canvas = dmnsn_new_canvas(3*x, y);
diff --git a/tests/pngxx.cpp b/tests/pngxx.cpp
index 4a99370..c7cf0e0 100644
--- a/tests/pngxx.cpp
+++ b/tests/pngxx.cpp
@@ -18,12 +18,15 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// Test C++ PNG file I/O
+
#include "testsxx.hpp"
#include <fstream>
int
main()
{
+ // Set the resilience low for tests
Dimension::resilience(Dimension::SEVERITY_LOW);
const unsigned int width = 333, height = 300;
diff --git a/tests/raytrace.c b/tests/raytrace.c
index 7ea28da..83e6b2b 100644
--- a/tests/raytrace.c
+++ b/tests/raytrace.c
@@ -32,6 +32,7 @@ main() {
dmnsn_color color;
dmnsn_matrix trans;
+ /* Set the resilience low for tests */
dmnsn_set_resilience(DMNSN_SEVERITY_LOW);
scene = dmnsn_new_scene();
@@ -80,6 +81,7 @@ main() {
progress = dmnsn_png_write_canvas_async(scene->canvas, file);
progressbar("Writing PNG file: ", progress);
dmnsn_finish_progress(progress);
+ fclose(file);
dmnsn_delete_cube(cube);
dmnsn_delete_sphere(sphere);
diff --git a/tests/tests.c b/tests/tests.c
index 67e5ee1..b938d39 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -20,6 +20,7 @@
#include "tests.h"
+/* Print a progress bar of the progress of `progress' */
void
progressbar(const char *str, const dmnsn_progress *progress)
{
diff --git a/tests/tests.h b/tests/tests.h
index c6b0de6..49e814c 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -21,4 +21,5 @@
#include "../libdimension/dimension.h"
#include <stdio.h>
+/* Print a progress bar of the progress of `progress' */
void progressbar(const char *str, const dmnsn_progress *progress);
diff --git a/tests/testsxx.cpp b/tests/testsxx.cpp
index a4a7d7b..532b3dc 100644
--- a/tests/testsxx.cpp
+++ b/tests/testsxx.cpp
@@ -20,6 +20,7 @@
#include "testsxx.hpp"
+// Print a progress bar of the progress of `progress'
std::ostream&
operator<<(std::ostream& ostr, const Dimension::Progress& progress)
{
diff --git a/tests/testsxx.hpp b/tests/testsxx.hpp
index 43c7593..f7b0bc6 100644
--- a/tests/testsxx.hpp
+++ b/tests/testsxx.hpp
@@ -21,5 +21,6 @@
#include "../libdimensionxx/dimensionxx.hpp"
#include <iostream>
+// Print a progress bar of the progress of `progress'
std::ostream& operator<<(std::ostream& ostr,
const Dimension::Progress& progress);
diff --git a/tests/warning.c b/tests/warning.c
index 80199c9..b2170d4 100644
--- a/tests/warning.c
+++ b/tests/warning.c
@@ -18,6 +18,8 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+// Make sure warnings don't kill us - this test should pass
+
#include "tests.h"
#include <stdlib.h>