diff options
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."); } @@ -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> |