summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rw-r--r--configure.ac2
-rw-r--r--doc/libdimension.texi1
-rw-r--r--libdimension/cameras.c9
-rw-r--r--libdimension/canvas.c5
-rw-r--r--libdimension/color.c2
-rw-r--r--libdimension/dimension/cameras.h1
-rw-r--r--libdimension/dimension/canvas.h1
-rw-r--r--libdimension/dimension/error.h11
-rw-r--r--libdimension/dimension/progress.h6
-rw-r--r--libdimension/dimension/raytrace.h1
-rw-r--r--libdimension/dimension/scene.h1
-rw-r--r--libdimension/error.c11
-rw-r--r--libdimension/geometry.c11
-rw-r--r--libdimension/gl.c15
-rw-r--r--libdimension/inlines.c2
-rw-r--r--libdimension/progress.c8
-rw-r--r--libdimension/raytrace.c2
-rw-r--r--libdimension/scene.c3
-rw-r--r--libdimensionxx/camera.cpp4
-rw-r--r--libdimensionxx/cameras.cpp6
-rw-r--r--libdimensionxx/canvas.cpp7
-rw-r--r--libdimensionxx/cookie-fopencookie.cpp11
-rw-r--r--libdimensionxx/cookie-tmpfile.cpp2
-rw-r--r--libdimensionxx/dimensionxx/cameras.hpp2
-rw-r--r--libdimensionxx/dimensionxx/cookie.hpp3
-rw-r--r--libdimensionxx/dimensionxx/error.hpp4
-rw-r--r--libdimensionxx/dimensionxx/object.hpp4
-rw-r--r--libdimensionxx/dimensionxx/objects.hpp2
-rw-r--r--libdimensionxx/dimensionxx/raytrace.hpp1
-rw-r--r--libdimensionxx/object.cpp8
-rw-r--r--libdimensionxx/progress.cpp3
-rw-r--r--libdimensionxx/raytrace.cpp1
-rw-r--r--libdimensionxx/scene.cpp2
-rw-r--r--tests/gl.c17
-rw-r--r--tests/glxx.cpp23
-rw-r--r--tests/png.c8
-rw-r--r--tests/pngxx.cpp5
-rw-r--r--tests/raytrace.c13
-rw-r--r--tests/raytracexx.cpp2
-rw-r--r--tests/tests.c2
-rw-r--r--tests/warning.c2
42 files changed, 166 insertions, 63 deletions
diff --git a/Makefile.am b/Makefile.am
index 00e77bf..7893825 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,9 @@
###########################################################################
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = doc libdimension libdimensionxx tests
+SUBDIRS = doc \
+ libdimension \
+ libdimensionxx \
+ tests
EXTRA_DIST = autogen.sh
diff --git a/configure.ac b/configure.ac
index bc27a03..b8d55a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -29,6 +29,7 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_LIBTOOL
+dnl Determine if we can use the fopencookie() implementation of FILE_Cookie
AC_MSG_CHECKING([for fopencookie()])
AC_LINK_IFELSE(AC_LANG_PROGRAM(
[[ #define _GNU_SOURCE
@@ -38,7 +39,6 @@ AC_LINK_IFELSE(AC_LANG_PROGRAM(
[fopencookie=yes
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
-
AM_CONDITIONAL([FOPENCOOKIE], [test "$fopencookie" = "yes"])
dnl Generate Makefiles
diff --git a/doc/libdimension.texi b/doc/libdimension.texi
index 2433673..c51894b 100644
--- a/doc/libdimension.texi
+++ b/doc/libdimension.texi
@@ -4,6 +4,7 @@
@settitle The Dimension 3-D Rendering Library
@c %**end of header
+@c Combine variable and function indicies
@syncodeindex vr fn
@c Wrap code examples at 72 chars, please
diff --git a/libdimension/cameras.c b/libdimension/cameras.c
index f346bbc..29d1df4 100644
--- a/libdimension/cameras.c
+++ b/libdimension/cameras.c
@@ -36,16 +36,19 @@ static dmnsn_line dmnsn_perspective_camera_ray_fn(const dmnsn_camera *camera,
dmnsn_camera *
dmnsn_new_perspective_camera(dmnsn_matrix trans)
{
+ dmnsn_matrix *ptr;
dmnsn_camera *camera = dmnsn_new_camera();
if (camera) {
camera->ray_fn = &dmnsn_perspective_camera_ray_fn;
- camera->ptr = malloc(sizeof(dmnsn_matrix));
- if (!camera->ptr) {
+ /* Allocate room for the transformation matrix */
+ ptr = malloc(sizeof(dmnsn_matrix));
+ if (!ptr) {
dmnsn_delete_camera(camera);
return NULL;
}
- *((dmnsn_matrix*)camera->ptr) = trans;
+ *ptr = trans;
+ camera->ptr = ptr;
}
return camera;
}
diff --git a/libdimension/canvas.c b/libdimension/canvas.c
index 4151a0b..2e4000b 100644
--- a/libdimension/canvas.c
+++ b/libdimension/canvas.c
@@ -61,7 +61,7 @@ dmnsn_delete_canvas(dmnsn_canvas *canvas)
for (i = 0; i < dmnsn_array_size(canvas->optimizers); ++i) {
dmnsn_array_get(canvas->optimizers, i, &optimizer);
if (optimizer.free_fn) {
- optimizer.free_fn(optimizer.ptr);
+ (*optimizer.free_fn)(optimizer.ptr);
}
}
@@ -76,6 +76,7 @@ int
dmnsn_optimize_canvas(dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer)
{
if (canvas->too_late) {
+ /* Don't set an optimizer if dmnsn_set_pixel() has been called */
return 1;
} else {
dmnsn_array_push(canvas->optimizers, &optimizer);
@@ -100,6 +101,6 @@ dmnsn_set_pixel(dmnsn_canvas *canvas, unsigned int x, unsigned int y,
/* Call the optimizers */
for (i = 0; i < dmnsn_array_size(canvas->optimizers); ++i) {
dmnsn_array_get(canvas->optimizers, i, &optimizer);
- optimizer.optimizer_fn(canvas, optimizer, x, y);
+ (*optimizer.optimizer_fn)(canvas, optimizer, x, y);
}
}
diff --git a/libdimension/color.c b/libdimension/color.c
index 4aede1f..433e437 100644
--- a/libdimension/color.c
+++ b/libdimension/color.c
@@ -268,7 +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 */
+ /* Weighted 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/dimension/cameras.h b/libdimension/dimension/cameras.h
index a75e9b9..d161f0e 100644
--- a/libdimension/dimension/cameras.h
+++ b/libdimension/dimension/cameras.h
@@ -31,6 +31,7 @@
dmnsn_camera *dmnsn_new_perspective_camera(dmnsn_matrix trans);
void dmnsn_delete_perspective_camera(dmnsn_camera *camera);
+/* Get or set the transformation matrix */
dmnsn_matrix dmnsn_get_perspective_camera_trans(const dmnsn_camera *camera);
void dmnsn_set_perspective_camera_trans(dmnsn_camera *camera, dmnsn_matrix T);
diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h
index aaf728b..1818ccc 100644
--- a/libdimension/dimension/canvas.h
+++ b/libdimension/dimension/canvas.h
@@ -40,6 +40,7 @@ typedef struct {
dmnsn_color *pixels;
} dmnsn_canvas;
+/* Forward-declare dmnsn_canvas_optimizer */
typedef struct dmnsn_canvas_optimizer dmnsn_canvas_optimizer;
/* Canvas optimizer callback types */
diff --git a/libdimension/dimension/error.h b/libdimension/dimension/error.h
index cd7dd81..c5bf2a1 100644
--- a/libdimension/dimension/error.h
+++ b/libdimension/dimension/error.h
@@ -34,10 +34,17 @@ typedef enum {
DMNSN_SEVERITY_HIGH /* Always die */
} dmnsn_severity;
+#ifdef __GNUC__
+ #define DMNSN_FUNC __PRETTY_FUNCTION__
+#elif (__STDC_VERSION__ >= 199901L)
+ #define DMNSN_FUNC __func__
+#else
+ #define DMNSN_FUNC __FILE__
+#endif
+
/* Use this macro to report an error */
#define dmnsn_error(severity, str) \
- dmnsn_report_error((dmnsn_severity)(severity), __PRETTY_FUNCTION__, __LINE__,\
- (str))
+ dmnsn_report_error((dmnsn_severity)(severity), DMNSN_FUNC, __LINE__, (str))
/* Called by dmnsn_error() - don't call directly */
void dmnsn_report_error(dmnsn_severity severity,
diff --git a/libdimension/dimension/progress.h b/libdimension/dimension/progress.h
index 57a38b6..0de1f03 100644
--- a/libdimension/dimension/progress.h
+++ b/libdimension/dimension/progress.h
@@ -52,14 +52,16 @@ typedef struct {
pthread_mutex_t *mutex;
} dmnsn_progress;
+/* Allocate a new progress object */
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
- addition to deleting `progress' */
+/* Join the worker thread and returns it's integer return value in addition to
+ deleting `progress' */
int dmnsn_finish_progress(dmnsn_progress *progress);
+/* Get the progress of the background task, out of 1.0 */
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);
diff --git a/libdimension/dimension/raytrace.h b/libdimension/dimension/raytrace.h
index 2be79a8..a855c24 100644
--- a/libdimension/dimension/raytrace.h
+++ b/libdimension/dimension/raytrace.h
@@ -25,6 +25,7 @@
#ifndef DIMENSION_RAYTRACE_H
#define DIMENSION_RAYTRACE_H
+/* Render a scene by raytracing */
int dmnsn_raytrace_scene(dmnsn_scene *scene);
dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene);
diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h
index 67db588..11195d4 100644
--- a/libdimension/dimension/scene.h
+++ b/libdimension/dimension/scene.h
@@ -32,6 +32,7 @@ typedef struct {
dmnsn_canvas *canvas;
} dmnsn_scene;
+/* Create a scene, initializing only the ->objects field */
dmnsn_scene *dmnsn_new_scene();
void dmnsn_delete_scene(dmnsn_scene *scene);
diff --git a/libdimension/error.c b/libdimension/error.c
index df3ade3..81278f1 100644
--- a/libdimension/error.c
+++ b/libdimension/error.c
@@ -49,7 +49,7 @@ dmnsn_get_resilience()
if (pthread_mutex_lock(&dmnsn_resilience_mutex) != 0) {
/* Couldn't lock the mutex, so warn and continue. */
fprintf(stderr, "Dimension WARNING: %s, line %u: %s\n",
- __PRETTY_FUNCTION__, __LINE__,
+ DMNSN_FUNC, __LINE__,
"Couldn't lock resilience mutex.");
}
resilience = dmnsn_resilience; /* Copy the static variable to a local */
@@ -57,7 +57,7 @@ dmnsn_get_resilience()
/* Couldn't unlock the mutex, so warn and continue. If the mutex was locked
earlier, the next dmnsn_get/set_resilience is likely to hang. */
fprintf(stderr, "Dimension WARNING: %s, line %u: %s\n",
- __PRETTY_FUNCTION__, __LINE__,
+ DMNSN_FUNC, __LINE__,
"Couldn't unlock resilience mutex.");
}
return resilience;
@@ -69,8 +69,7 @@ dmnsn_set_resilience(dmnsn_severity resilience)
{
if (resilience > DMNSN_SEVERITY_HIGH) {
/* Tried to set an illegal resilience, bail out */
- fprintf(stderr, "Dimension ERROR: %s, line %u: %s\n",
- __PRETTY_FUNCTION__, __LINE__,
+ fprintf(stderr, "Dimension ERROR: %s, line %u: %s\n", DMNSN_FUNC, __LINE__,
"Resilience has wrong value.");
exit(EXIT_FAILURE);
}
@@ -78,7 +77,7 @@ dmnsn_set_resilience(dmnsn_severity resilience)
if (pthread_mutex_lock(&dmnsn_resilience_mutex) != 0) {
/* Couldn't lock the mutex, so warn and continue. */
fprintf(stderr, "Dimension WARNING: %s, line %u: %s\n",
- __PRETTY_FUNCTION__, __LINE__,
+ DMNSN_FUNC, __LINE__,
"Couldn't lock resilience mutex.");
}
dmnsn_resilience = resilience;
@@ -86,7 +85,7 @@ dmnsn_set_resilience(dmnsn_severity resilience)
/* Couldn't unlock the mutex, so warn and continue. If the mutex was locked
earlier, the next dmnsn_get/set_resilience is likely to hang. */
fprintf(stderr, "Dimension WARNING: %s, line %u: %s\n",
- __PRETTY_FUNCTION__, __LINE__,
+ DMNSN_FUNC, __LINE__,
"Couldn't unlock resilience mutex.");
}
}
diff --git a/libdimension/geometry.c b/libdimension/geometry.c
index 030cd68..8ebc3d9 100644
--- a/libdimension/geometry.c
+++ b/libdimension/geometry.c
@@ -65,7 +65,7 @@ dmnsn_rotation_matrix(dmnsn_vector theta)
}
axis = dmnsn_vector_normalize(theta);
- /* Shorthand to make dmnsn_matrix_construct call legible */
+ /* Shorthand to make dmnsn_matrix_construct() call legible */
s = sin(angle);
t = 1.0 - cos(angle);
@@ -123,7 +123,13 @@ dmnsn_matrix_inverse(dmnsn_matrix A)
double Pdet = A.n[0][0]*A.n[1][1] - A.n[0][1]*A.n[1][0];
if (Pdet == 0.0) {
- /* If we can't invert P, try a more generic algorithm */
+ /* If we can't invert P, try a more generic algorithm; this is very
+ unlikely, but not impossible, eg.
+ ( 1 1 0 0 )
+ ( 1 1 1 0 )
+ ( 0 1 1 0 )
+ ( 0 0 0 1 )
+ */
return dmnsn_matrix_inverse_generic(A);
}
@@ -146,6 +152,7 @@ dmnsn_matrix_inverse(dmnsn_matrix A)
PiQ = dmnsn_matrix2_mul(Pi, Q);
RPiQ = dmnsn_matrix2_mul(R, PiQ);
+ /* Calculate the partitioned inverse */
SS = dmnsn_matrix2_inverse(dmnsn_matrix2_sub(S, RPiQ));
RR = dmnsn_matrix2_negate(dmnsn_matrix2_mul(SS, RPi));
QQ = dmnsn_matrix2_negate(dmnsn_matrix2_mul(PiQ, SS));
diff --git a/libdimension/gl.c b/libdimension/gl.c
index 20c9af3..006db4b 100644
--- a/libdimension/gl.c
+++ b/libdimension/gl.c
@@ -46,12 +46,15 @@ dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas)
optimizer.optimizer_fn = &dmnsn_gl_optimizer_fn;
optimizer.free_fn = &free;
+ /* Allocate a buffer to hold RGB values */
optimizer.ptr = malloc(4*canvas->x*canvas->y*sizeof(GLushort));
if (!optimizer.ptr) {
return 1;
}
+ /* Set a new optimizer */
if (dmnsn_optimize_canvas(canvas, optimizer) != 0) {
+ /* Set failed; dmnsn_set_pixel() has probably been called already */
free(optimizer.ptr);
return 1;
}
@@ -78,11 +81,11 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
dmnsn_array_get(canvas->optimizers, i, &optimizer);
if (optimizer.optimizer_fn == &dmnsn_gl_optimizer_fn) {
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_SHORT, optimizer.ptr);
- return 0;
+ return glGetError() == GL_NO_ERROR ? 0 : 1;
}
}
- /* We couldn't, so to this non-optimally */
+ /* We couldn't, so transform the canvas to RGB now */
pixels = malloc(4*width*height*sizeof(GLushort));
if (!pixels) {
return 1;
@@ -129,7 +132,7 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_SHORT, pixels);
free(pixels);
- return 0;
+ return glGetError() == GL_NO_ERROR ? 0 : 1;
}
/* Read a canvas from a GL framebuffer. Returns NULL on failure. */
@@ -157,6 +160,12 @@ dmnsn_gl_read_canvas(unsigned int x0, unsigned int y0,
glReadPixels(x0, y0, width, height, GL_RGBA, GL_UNSIGNED_SHORT, pixels);
+ if (glGetError() != GL_NO_ERROR) {
+ free(pixels);
+ dmnsn_delete_canvas(canvas);
+ return NULL;
+ }
+
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
pixel = pixels + 4*(y*width + x);
diff --git a/libdimension/inlines.c b/libdimension/inlines.c
index e7d4c74..0a11969 100644
--- a/libdimension/inlines.c
+++ b/libdimension/inlines.c
@@ -18,6 +18,8 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+/* Set DMNSN_INLINE to produce definitions of inline functions, emitted here,
+ if needed */
#ifdef __cplusplus
/* C++ inline semantics */
#define DMNSN_INLINE inline
diff --git a/libdimension/progress.c b/libdimension/progress.c
index f366832..24f3a5e 100644
--- a/libdimension/progress.c
+++ b/libdimension/progress.c
@@ -63,6 +63,8 @@ dmnsn_new_progress()
return NULL;
}
+ /* Initialize the rwlock, condition variable, and mutex */
+
if (pthread_rwlock_init(progress->rwlock, NULL) != 0) {
free(progress->rwlock);
free(progress->mutex);
@@ -71,7 +73,6 @@ dmnsn_new_progress()
free(progress);
return NULL;
}
-
if (pthread_cond_init(progress->cond, NULL) != 0) {
if (pthread_rwlock_destroy(progress->rwlock) != 0) {
dmnsn_error(DMNSN_SEVERITY_LOW,
@@ -135,9 +136,8 @@ int dmnsn_finish_progress(dmnsn_progress *progress)
int retval = 1;
if (progress) {
- if (pthread_cond_broadcast(progress->cond) != 0) {
- dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't signal condition variable.");
- }
+ /* Wake up all waiters */
+ dmnsn_done_progress(progress);
if (pthread_join(progress->thread, &ptr) != 0) {
/* Medium severity because an unjoined thread likely means that the thread
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 1984d24..7bb6381 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -196,7 +196,7 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene,
dmnsn_line ray, ray_trans;
dmnsn_array *intersections;
dmnsn_color color;
- dmnsn_CIE_Lab Lab = { 0.0, 0.0, 0.0 }; // Shut up uninitialized use warning
+ dmnsn_CIE_Lab Lab = { 0.0, 0.0, 0.0 }; /* Shut up uninitialized use warning */
width = scene->canvas->x;
height = scene->canvas->y;
diff --git a/libdimension/scene.c b/libdimension/scene.c
index 9405f03..d167e16 100644
--- a/libdimension/scene.c
+++ b/libdimension/scene.c
@@ -26,8 +26,9 @@ dmnsn_scene *
dmnsn_new_scene()
{
dmnsn_scene *scene = malloc(sizeof(dmnsn_scene));
- if (scene)
+ if (scene) {
scene->objects = dmnsn_new_array(sizeof(dmnsn_object*));
+ }
return scene;
}
diff --git a/libdimensionxx/camera.cpp b/libdimensionxx/camera.cpp
index ba2428a..efe0802 100644
--- a/libdimensionxx/camera.cpp
+++ b/libdimensionxx/camera.cpp
@@ -30,7 +30,7 @@ namespace Dimension
Line
Camera::ray(const Canvas& canvas, unsigned int x, unsigned int y)
{
- return Line(dmnsn()->ray_fn(dmnsn(), canvas.dmnsn(), x, y));
+ return Line((*dmnsn()->ray_fn)(dmnsn(), canvas.dmnsn(), x, y));
}
// Return the wrapped camera
@@ -74,7 +74,7 @@ namespace Dimension
bool
Camera::unique() const
{
- return m_camera.unique();
+ return m_camera && m_camera.unique();
}
// Set the wrapped dmnsn_camera*
diff --git a/libdimensionxx/cameras.cpp b/libdimensionxx/cameras.cpp
index ea0bca9..dee4df6 100644
--- a/libdimensionxx/cameras.cpp
+++ b/libdimensionxx/cameras.cpp
@@ -31,7 +31,7 @@ namespace Dimension
}
}
- // Delete a perspective camera
+ // Delete a perspective camera, if we're the last reference
Perspective_Camera::~Perspective_Camera()
{
if (unique()) {
@@ -39,24 +39,28 @@ namespace Dimension
}
}
+ // Get the transformation matrix
Matrix
Perspective_Camera::trans()
{
return Matrix(dmnsn_get_perspective_camera_trans(dmnsn()));
}
+ // Set the transformation matrix
void
Perspective_Camera::trans(const Matrix& trans)
{
dmnsn_set_perspective_camera_trans(dmnsn(), trans.dmnsn());
}
+ // Shallow-copy this camera
Camera*
Perspective_Camera::copy() const
{
return new Perspective_Camera(*this);
}
+ // Private copy-constructor, for copy() implementation
Perspective_Camera::Perspective_Camera(const Perspective_Camera& camera)
: Camera(camera)
{ }
diff --git a/libdimensionxx/canvas.cpp b/libdimensionxx/canvas.cpp
index 3ff9d32..6118730 100644
--- a/libdimensionxx/canvas.cpp
+++ b/libdimensionxx/canvas.cpp
@@ -24,7 +24,12 @@ namespace Dimension
{
// Allocate the canvas with dmnsn_new_canvas()
Canvas::Canvas(unsigned int width, unsigned int height)
- : m_canvas(new dmnsn_canvas*(dmnsn_new_canvas(width, height))) { }
+ : m_canvas(new dmnsn_canvas*(dmnsn_new_canvas(width, height)))
+ {
+ if (!dmnsn()) {
+ throw Dimension_Error("Couldn't allocate canvas.");
+ }
+ }
// Wrap an existing dmnsn_canvas*
Canvas::Canvas(dmnsn_canvas* canvas)
diff --git a/libdimensionxx/cookie-fopencookie.cpp b/libdimensionxx/cookie-fopencookie.cpp
index e165c8d..1d1f813 100644
--- a/libdimensionxx/cookie-fopencookie.cpp
+++ b/libdimensionxx/cookie-fopencookie.cpp
@@ -26,12 +26,11 @@
#endif
#include <stdio.h>
-// The conundrum: libdimension and libdimension-* use C I/O, with FILE*'s.
-// We want to use C++ I/O with std::i/ostreams. If present, we use the
-// nonportable GNU stdio extension fopencookie(), which creates a FILE* with
-// custom read/write/seek functions. BSD also has a similar function, funopen()
-// which we should use too. Failing in all that, fall back on a tmpfile()
-// buffer (see cookie-tmpfile.cpp).
+// The conundrum: libdimension uses C I/O, with FILE*'s. We want to use C++ I/O
+// with std::i/ostreams. If present, we use the nonportable GNU stdio extension
+// fopencookie(), which creates a FILE* with custom read/write/seek functions.
+// BSD also has a similar function, funopen() which we should use too. Failing
+// in all that, fall back on a tmpfile() buffer (see cookie-tmpfile.cpp).
namespace Dimension
{
diff --git a/libdimensionxx/cookie-tmpfile.cpp b/libdimensionxx/cookie-tmpfile.cpp
index 6a41f09..b2d25b8 100644
--- a/libdimensionxx/cookie-tmpfile.cpp
+++ b/libdimensionxx/cookie-tmpfile.cpp
@@ -21,7 +21,7 @@
#include "dimensionxx.hpp"
#include <stdio.h>
-// Use a tmpfile as a buffer for a C++/C I/O interface.
+// Use a tmpfile() as a buffer for a C++/C I/O interface.
namespace Dimension
{
diff --git a/libdimensionxx/dimensionxx/cameras.hpp b/libdimensionxx/dimensionxx/cameras.hpp
index cabae97..2726a0c 100644
--- a/libdimensionxx/dimensionxx/cameras.hpp
+++ b/libdimensionxx/dimensionxx/cameras.hpp
@@ -32,9 +32,11 @@ namespace Dimension
Perspective_Camera(const Matrix& trans);
~Perspective_Camera();
+ // Get/set the transformation matrix
Matrix trans();
void trans(const Matrix& trans);
+ // Shallow-copy the camera
Camera* copy() const;
private:
diff --git a/libdimensionxx/dimensionxx/cookie.hpp b/libdimensionxx/dimensionxx/cookie.hpp
index 0d8b4da..9dbe7b8 100644
--- a/libdimensionxx/dimensionxx/cookie.hpp
+++ b/libdimensionxx/dimensionxx/cookie.hpp
@@ -38,12 +38,15 @@ namespace Dimension
FILE_Cookie(std::iostream& iostr);
~FILE_Cookie();
+ // Get the magic FILE*
FILE* file();
const FILE* file() const;
+ // Are we an input or output stream?
bool is_input() const;
bool is_output() const;
+ // Get the C++ streams
std::istream& istr();
const std::istream& istr() const;
std::ostream& ostr();
diff --git a/libdimensionxx/dimensionxx/error.hpp b/libdimensionxx/dimensionxx/error.hpp
index 7fb0e53..ad61284 100644
--- a/libdimensionxx/dimensionxx/error.hpp
+++ b/libdimensionxx/dimensionxx/error.hpp
@@ -20,8 +20,8 @@
// 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.
+// be thrown, like in destructors, and whenever libdimension uses it internally.
+// Exceptions are thrown otherwise to report errors.
#ifndef DIMENSIONXX_ERROR_HPP
#define DIMENSIONXX_ERROR_HPP
diff --git a/libdimensionxx/dimensionxx/object.hpp b/libdimensionxx/dimensionxx/object.hpp
index c56d358..e0b45f4 100644
--- a/libdimensionxx/dimensionxx/object.hpp
+++ b/libdimensionxx/dimensionxx/object.hpp
@@ -40,10 +40,10 @@ namespace Dimension
virtual Array<double> intersections(const Line& l);
virtual bool inside(const Vector& point);
- // Shallow-copy a derived
+ // Shallow-copy a derived object
virtual Object* copy() const = 0;
- // Access the wrapped C object.
+ // Access the wrapped C object
dmnsn_object* dmnsn();
const dmnsn_object* dmnsn() const;
diff --git a/libdimensionxx/dimensionxx/objects.hpp b/libdimensionxx/dimensionxx/objects.hpp
index 5b43dc4..11e408c 100644
--- a/libdimensionxx/dimensionxx/objects.hpp
+++ b/libdimensionxx/dimensionxx/objects.hpp
@@ -32,6 +32,7 @@ namespace Dimension
Sphere();
~Sphere();
+ // Shallow-copy the sphere
Object* copy() const;
private:
@@ -47,6 +48,7 @@ namespace Dimension
Cube();
~Cube();
+ // Shallow-copy the cube
Object* copy() const;
private:
diff --git a/libdimensionxx/dimensionxx/raytrace.hpp b/libdimensionxx/dimensionxx/raytrace.hpp
index bfd7e1c..8cf4ee4 100644
--- a/libdimensionxx/dimensionxx/raytrace.hpp
+++ b/libdimensionxx/dimensionxx/raytrace.hpp
@@ -34,6 +34,7 @@ namespace Dimension
Raytracer(Scene& scene);
~Raytracer();
+ // Render the scene
void render();
Progress render_async();
diff --git a/libdimensionxx/object.cpp b/libdimensionxx/object.cpp
index 61b8b7d..1a43f62 100644
--- a/libdimensionxx/object.cpp
+++ b/libdimensionxx/object.cpp
@@ -26,12 +26,14 @@ namespace Dimension
Object::~Object()
{ }
+ // Get the transformation matrix
Matrix
Object::trans()
{
return Matrix(dmnsn()->trans);
}
+ // Set the transformation matrix
void
Object::trans(const Matrix& trans)
{
@@ -42,14 +44,14 @@ namespace Dimension
Array<double>
Object::intersections(const Line& l)
{
- return Array<double>(dmnsn()->intersections_fn(dmnsn(), l.dmnsn()));
+ return Array<double>((*dmnsn()->intersections_fn)(dmnsn(), l.dmnsn()));
}
// Whether the point `point' is inside the object
bool
Object::inside(const Vector& point)
{
- return dmnsn()->inside_fn(dmnsn(), point.dmnsn());
+ return (*dmnsn()->inside_fn)(dmnsn(), point.dmnsn());
}
// Return the wrapped object
@@ -93,7 +95,7 @@ namespace Dimension
bool
Object::unique() const
{
- return m_object.unique();
+ return m_object && m_object.unique();
}
// Set the wrapped dmnsn_object*
diff --git a/libdimensionxx/progress.cpp b/libdimensionxx/progress.cpp
index 66d9d7f..7cf42aa 100644
--- a/libdimensionxx/progress.cpp
+++ b/libdimensionxx/progress.cpp
@@ -22,6 +22,7 @@
namespace Dimension
{
+ // No-op virtual destructor
Persist_Base::~Persist_Base()
{ }
@@ -38,7 +39,7 @@ namespace Dimension
// Finish the progress if not yet finished and we are unique
Progress::~Progress()
{
- if (m_progress) {
+ if (m_progress && m_progress.unique()) {
try {
finish();
} catch (...) {
diff --git a/libdimensionxx/raytrace.cpp b/libdimensionxx/raytrace.cpp
index 263fe6d..d3ae769 100644
--- a/libdimensionxx/raytrace.cpp
+++ b/libdimensionxx/raytrace.cpp
@@ -22,6 +22,7 @@
namespace Dimension
{
+ // Construct a raytracer
Raytracer::Raytracer(Scene& scene)
: m_scene(&scene), m_rendered(false) { }
diff --git a/libdimensionxx/scene.cpp b/libdimensionxx/scene.cpp
index 2b0fba5..fec961a 100644
--- a/libdimensionxx/scene.cpp
+++ b/libdimensionxx/scene.cpp
@@ -27,7 +27,7 @@ namespace Dimension
: m_scene(new dmnsn_scene*(dmnsn_new_scene())), m_camera(camera.copy()),
m_canvas(new Canvas(canvas))
{
- if (!m_scene) {
+ if (!dmnsn()) {
throw Dimension_Error("Couldn't allocate scene.");
}
diff --git a/tests/gl.c b/tests/gl.c
index c9a3ae4..99040c1 100644
--- a/tests/gl.c
+++ b/tests/gl.c
@@ -26,29 +26,35 @@ main() {
dmnsn_display *display;
dmnsn_progress *progress;
dmnsn_scene *scene;
- dmnsn_object *sphere, *cube;
+ dmnsn_object *cube;
dmnsn_matrix trans;
+ const unsigned int frames = 10;
unsigned int i;
/* Set the resilience low for tests */
dmnsn_set_resilience(DMNSN_SEVERITY_LOW);
+ /* Create the default test scene */
scene = dmnsn_new_default_scene();
if (!scene) {
fprintf(stderr, "--- Couldn't create default scene! ---\n");
return EXIT_FAILURE;
}
+ /* Optimize the canvas for GL drawing */
if (dmnsn_gl_optimize_canvas(scene->canvas) != 0) {
dmnsn_delete_default_scene(scene);
fprintf(stderr, "--- Couldn't optimize canvas for GL! ---\n");
return EXIT_FAILURE;
}
- dmnsn_array_get(scene->objects, 0, &sphere);
+ /* Get the cube object */
dmnsn_array_get(scene->objects, 1, &cube);
+
+ /* Get the camera transformation matrix */
trans = dmnsn_get_perspective_camera_trans(scene->camera);
+ /* Create a new glX display */
display = dmnsn_new_display(scene->canvas);
if (!display) {
dmnsn_delete_default_scene(scene);
@@ -56,7 +62,10 @@ main() {
return EXIT_FAILURE;
}
- for (i = 0; i < 10; ++i) {
+ /* Render the animation */
+ for (i = 0; i < frames; ++i) {
+ /* Render the scene */
+
progress = dmnsn_raytrace_scene_async(scene);
if (!progress) {
dmnsn_delete_display(display);
@@ -74,6 +83,8 @@ main() {
return EXIT_FAILURE;
}
+ /* Display the scene */
+
if (dmnsn_gl_write_canvas(scene->canvas) != 0) {
dmnsn_delete_display(display);
dmnsn_delete_default_scene(scene);
diff --git a/tests/glxx.cpp b/tests/glxx.cpp
index d88c27d..c582f8c 100644
--- a/tests/glxx.cpp
+++ b/tests/glxx.cpp
@@ -26,12 +26,18 @@ int
main() {
using namespace Dimension;
+ // Set the resilience low for tests
+ resilience(SEVERITY_LOW);
+
+ // Create the default test scene
Scene scene = Tests::default_scene();
+ // Get the camera
Perspective_Camera& camera
= dynamic_cast<Perspective_Camera&>(scene.camera());
- Cube* cube;
+ // Find the cube
+ Cube* cube = 0;
for (Scene::Iterator i = scene.begin(); i != scene.end(); ++i) {
cube = dynamic_cast<Cube*>(&*i);
if (cube) {
@@ -42,23 +48,26 @@ main() {
throw Dimension_Error("Couldn't find a cube in the default scene.");
}
- // Set the resilience low for tests
- resilience(SEVERITY_LOW);
-
Raytracer raytracer(scene);
GL_Drawer drawer(scene.canvas());
Tests::Display display(scene.canvas());
- // Render the scene
- for (unsigned int i = 0; i < 10; ++i) {
+ // Render the animation
+ const unsigned int frames = 10;
+ for (unsigned int i = 0; i < frames; ++i) {
+ // Render the scene
Progress rprogress = raytracer.render_async();
std::cout << "Raytracing scene: " << rprogress << std::endl;
rprogress.finish();
+ // Display the frame
drawer.draw();
display.flush();
- cube->trans(inverse(Matrix::rotation(Vector(0.025, 0.0, 0.0)))*cube->trans());
+ // Rotate the cube and camera for the next frame
+ cube->trans(
+ inverse(Matrix::rotation(Vector(0.025, 0.0, 0.0)))*cube->trans()
+ );
camera.trans(Matrix::rotation(Vector(0.0, -0.05, 0.0))*camera.trans());
}
diff --git a/tests/png.c b/tests/png.c
index 8db6d63..0949f8b 100644
--- a/tests/png.c
+++ b/tests/png.c
@@ -40,12 +40,14 @@ main() {
/* Set the resilience low for tests */
dmnsn_set_resilience(DMNSN_SEVERITY_LOW);
+ /* Allocate a canvas */
canvas = dmnsn_new_canvas(3*x, y);
if (!canvas) {
fprintf(stderr, "--- Allocation of canvas failed! ---\n");
return EXIT_FAILURE;
}
+ /* Optimize the canvas for PNG export */
if (dmnsn_png_optimize_canvas(canvas) != 0) {
dmnsn_delete_canvas(canvas);
fprintf(stderr, "--- Couldn't optimize canvas for PNG! ---\n");
@@ -110,6 +112,8 @@ main() {
}
}
+ /* Write the image to PNG */
+
ofile = fopen("dimension1.png", "wb");
if (!ofile) {
fprintf(stderr, "--- Opening 'dimension1.png' for writing failed! ---\n");
@@ -137,6 +141,8 @@ main() {
fclose(ofile);
dmnsn_delete_canvas(canvas);
+ /* Read the image back from the PNG file */
+
ifile = fopen("dimension1.png", "rb");
if (!ifile) {
fprintf(stderr, "--- Opening 'dimension1.png' for reading failed! ---\n");
@@ -160,6 +166,8 @@ main() {
fclose(ifile);
+ /* ... and write it back again */
+
ofile = fopen("dimension2.png", "wb");
if (!ofile) {
fprintf(stderr, "--- Opening 'dimension2.png' for writing failed! ---\n");
diff --git a/tests/pngxx.cpp b/tests/pngxx.cpp
index 27fe89c..731f470 100644
--- a/tests/pngxx.cpp
+++ b/tests/pngxx.cpp
@@ -94,10 +94,13 @@ main()
}
}
+ // Write the image to PNG
Progress progress = writer.write_async();
std::cout << "Writing PNG file: " << progress << std::endl;
}
+ // Read the image back from PNG
+
std::ifstream ifstr("dimensionxx1.png", std::ios::binary);
PNG_Reader reader(ifstr);
@@ -105,6 +108,8 @@ main()
std::cout << "Reading PNG file: " << iprogress << std::endl;
Canvas canvas = PNG_Reader::finish(iprogress);
+ // And write it again
+
std::ofstream ofstr("dimensionxx2.png", std::ios::binary);
PNG_Writer writer(canvas, ofstr);
diff --git a/tests/raytrace.c b/tests/raytrace.c
index 4d54e1c..0515ab2 100644
--- a/tests/raytrace.c
+++ b/tests/raytrace.c
@@ -30,13 +30,22 @@ main() {
/* Set the resilience low for tests */
dmnsn_set_resilience(DMNSN_SEVERITY_LOW);
- /* Allocate our new scene */
+ /* Allocate our default scene */
scene = dmnsn_new_default_scene();
if (!scene) {
fprintf(stderr, "--- Allocation of default scene failed! ---\n");
return EXIT_FAILURE;
}
+ /* Optimize the canvas for PNG export */
+ if (dmnsn_png_optimize_canvas(canvas) != 0) {
+ dmnsn_delete_canvas(canvas);
+ fprintf(stderr, "--- Couldn't optimize canvas for PNG! ---\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Render scene */
+
progress = dmnsn_raytrace_scene_async(scene);
if (!progress) {
dmnsn_delete_default_scene(scene);
@@ -52,6 +61,8 @@ main() {
return EXIT_FAILURE;
}
+ /* Write the image to PNG */
+
file = fopen("raytrace.png", "wb");
if (!file) {
dmnsn_delete_default_scene(scene);
diff --git a/tests/raytracexx.cpp b/tests/raytracexx.cpp
index 3fed923..fd99acd 100644
--- a/tests/raytracexx.cpp
+++ b/tests/raytracexx.cpp
@@ -29,6 +29,7 @@ main() {
resilience(SEVERITY_LOW);
Scene scene = Tests::default_scene();
+ PNG_Writer writer(scene.canvas(), file);
// Render the scene
{
@@ -39,7 +40,6 @@ main() {
// Write the canvas
std::ofstream file("raytracexx.png");
- PNG_Writer writer(scene.canvas(), file);
Progress progress = writer.write_async();
std::cout << "Writing PNG file: " << progress << std::endl;
diff --git a/tests/tests.c b/tests/tests.c
index 7fd7f19..842405a 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -28,7 +28,7 @@ dmnsn_new_default_scene()
dmnsn_sRGB sRGB;
dmnsn_color color;
- /* Allocate our new scene */
+ /* Allocate a new scene */
scene = dmnsn_new_scene();
if (!scene) {
return NULL;
diff --git a/tests/warning.c b/tests/warning.c
index 46ccf15..e677c54 100644
--- a/tests/warning.c
+++ b/tests/warning.c
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
-// Make sure warnings don't kill us - this test should pass
+/* Make sure warnings don't kill us - this test should pass */
#include "tests.h"
#include <stdlib.h>