diff options
Diffstat (limited to 'libdimension')
-rw-r--r-- | libdimension/canvas.c | 32 | ||||
-rw-r--r-- | libdimension/color.c | 20 | ||||
-rw-r--r-- | libdimension/dimension.h | 4 | ||||
-rw-r--r-- | libdimension/dimension/canvas.h | 8 | ||||
-rw-r--r-- | libdimension/dimension/color.h | 13 | ||||
-rw-r--r-- | libdimension/dimension/error.h | 10 | ||||
-rw-r--r-- | libdimension/dimension/geometry.h | 5 | ||||
-rw-r--r-- | libdimension/error.c | 13 | ||||
-rw-r--r-- | libdimension/geometry.c | 8 |
9 files changed, 89 insertions, 24 deletions
diff --git a/libdimension/canvas.c b/libdimension/canvas.c index 49096fc..516c978 100644 --- a/libdimension/canvas.c +++ b/libdimension/canvas.c @@ -19,24 +19,33 @@ *************************************************************************/ #include "dimension.h" -#include <pthread.h> /* Must be first included header */ -#include <stdlib.h> /* For malloc(), free() */ +#include <pthread.h> +#include <stdlib.h> /* For malloc(), free() */ +/* Allocate a new canvas, of width x and height y. If any intermediary step + fails, free all acquired memory to avoid leaks. */ dmnsn_canvas * dmnsn_new_canvas(unsigned int x, unsigned int y) { unsigned int i, j, k, l; + /* Allocate the dmnsn_canvas struct */ dmnsn_canvas *canvas = malloc(sizeof(dmnsn_canvas)); if (canvas) { + /* *canvas exists */ + + /* Set the width and height */ canvas->x = x; canvas->y = y; + + /* Allocate the pixels */ canvas->pixels = malloc(sizeof(dmnsn_color)*x*y); if (!canvas->pixels) { free(canvas); return NULL; } + /* Allocate the rwlocks */ canvas->rwlocks = malloc(sizeof(pthread_rwlock_t)*x*y); if (!canvas->rwlocks) { free(canvas->pixels); @@ -44,6 +53,7 @@ dmnsn_new_canvas(unsigned int x, unsigned int y) return NULL; } + /* Initialize the rwlocks */ for (i = 0; i < x; ++i) { for (j = 0; j < y; ++j) { if (pthread_rwlock_init(&canvas->rwlocks[j*x + i], NULL) != 0) { @@ -53,7 +63,7 @@ dmnsn_new_canvas(unsigned int x, unsigned int y) for (l = 0; l < j; ++l) { for (k = 0; k < x; ++k) { if (pthread_rwlock_destroy(&canvas->rwlocks[l*x + k]) != 0) { - /* Low severity, because leaked memory won't actually hurt us */ + /* Low severity, because leaked locks won't actually hurt us */ dmnsn_error(DMNSN_SEVERITY_LOW, "Leaking rwlocks in failed allocation."); } @@ -79,12 +89,16 @@ dmnsn_new_canvas(unsigned int x, unsigned int y) return canvas; } +/* Delete a dmnsn_canvas allocated with dmnsn_new_canvas */ void 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) { if (pthread_rwlock_destroy(&canvas->rwlocks[j*canvas->x + i]) != 0) { @@ -94,12 +108,14 @@ dmnsn_delete_canvas(dmnsn_canvas *canvas) } } + /* Free the locks, pixels, and canvas */ free(canvas->rwlocks); free(canvas->pixels); free(canvas); } } +/* Get a pixel at (x,y) thread-safely, using dmnsn_rdlock_pixel. */ dmnsn_color dmnsn_get_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y) { @@ -110,6 +126,7 @@ dmnsn_get_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y) return color; } +/* Set a pixel at (x,y) thread-safely, using dmnsn_wrlock_pixel. */ void dmnsn_set_pixel(dmnsn_canvas *canvas, unsigned int x, unsigned int y, dmnsn_color color) @@ -119,28 +136,37 @@ dmnsn_set_pixel(dmnsn_canvas *canvas, dmnsn_unlock_pixel(canvas, x, y); } +/* Acquire a read-lock for a pixel */ void dmnsn_rdlock_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y) { if (pthread_rwlock_rdlock(&canvas->rwlocks[y*canvas->x + x]) != 0) { + /* Medium severity, because undefined behaviour is pretty likely if our + reads and writes aren't synced */ dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't acquire read-lock for pixel."); } } +/* Acquire a write-lock for a pixel */ void dmnsn_wrlock_pixel(dmnsn_canvas *canvas, unsigned int x, unsigned int y) { if (pthread_rwlock_wrlock(&canvas->rwlocks[y*canvas->x + x]) != 0) { + /* Medium severity, because undefined behaviour is pretty likely if our + reads and writes aren't synced */ dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't acquire write-lock for pixel."); } } +/* Unlock a pixel */ void dmnsn_unlock_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y) { if (pthread_rwlock_unlock(&canvas->rwlocks[y*canvas->x + x]) != 0) { + /* Medium severity, because if the pixel is locked, we're likely to hang + the next time we try to read or write it */ dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't unlock pixel."); } } diff --git a/libdimension/color.c b/libdimension/color.c index e2a4df9..5a685c1 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -26,6 +26,7 @@ const dmnsn_CIE_XYZ dmnsn_whitepoint = { .X = 0.9504060171449392, .Y = 0.9999085943425312, .Z = 1.089062231497274 }; +/* Convert a CIE XYZ color to a dmnsn_color (actually a no-op) */ dmnsn_color dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ) { @@ -34,6 +35,7 @@ dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ) return ret; } +/* Convert a CIE xyY color to a dmnsn_color */ dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY) { @@ -44,6 +46,7 @@ dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY) return ret; } +/* Inverse function of CIE L*a*b*'s `f' function, for the reverse conversion */ static double dmnsn_Lab_finv(double t) { if (t > 6.0/29.0) { return t*t*t; @@ -52,6 +55,8 @@ static double dmnsn_Lab_finv(double t) { } } +/* Convert a CIE L*a*b* color to a dmnsn_color, relative to the given + whitepoint. */ dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white) { @@ -71,6 +76,8 @@ dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white) return ret; } +/* Convert a CIE L*u*v* color to a dmnsn_color, relative to the given + whitepoint. */ dmnsn_color dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white) { @@ -94,6 +101,7 @@ dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white) return ret; } +/* Inverse function of sRGB's `C' function, for the reverse conversion */ static double dmnsn_sRGB_Cinv(double CsRGB) { /* * If C represents R, G, and B, then the Clinear values are now found as @@ -110,6 +118,7 @@ static double dmnsn_sRGB_Cinv(double CsRGB) { } } +/* Convert an sRGB value to a dmnsn_color */ dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB) { @@ -140,6 +149,7 @@ dmnsn_color_from_sRGB(dmnsn_sRGB sRGB) return ret; } +/* Convert a dmnsn_color to a CIE XYZ color (actually a no-op) */ dmnsn_CIE_XYZ dmnsn_XYZ_from_color(dmnsn_color color) { @@ -147,6 +157,7 @@ dmnsn_XYZ_from_color(dmnsn_color color) return ret; } +/* Convert a dmnsn_color to a CIE xyY color */ dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color) { @@ -156,6 +167,7 @@ dmnsn_xyY_from_color(dmnsn_color color) return ret; } +/* CIE L*a*b*'s `f' function */ static double dmnsn_Lab_f(double t) { if (t > 216.0/24389.0) { return pow(t, 1.0/3.0); @@ -164,6 +176,8 @@ static double dmnsn_Lab_f(double t) { } } +/* Convert a dmnsn_color to a CIE L*a*b* color, relative to the given + whitepoint */ dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) { @@ -176,6 +190,8 @@ dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) return ret; } +/* Convert a dmnsn_color to a CIE L*u*v* color, relative to the given + whitepoint */ dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) { @@ -194,6 +210,7 @@ dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) return ret; } +/* sRGB's `C' function */ static double dmnsn_sRGB_C(double Clinear) { /* * If C represents R, G, and B, then the sRGB values are now found as follows: @@ -209,6 +226,7 @@ static double dmnsn_sRGB_C(double Clinear) { } } +/* Convert a dmnsn_color to an sRGB color */ dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color) { @@ -234,6 +252,7 @@ dmnsn_sRGB_from_color(dmnsn_color color) return ret; } +/* Add two colors in a perceptually correct manner, using CIE L*a*b*. */ dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) { @@ -254,6 +273,7 @@ dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) return ret; } +/* Find the perceptual difference between two colors, using CIE L*a*b*. */ double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2) { diff --git a/libdimension/dimension.h b/libdimension/dimension.h index 97f07a5..735e1a0 100644 --- a/libdimension/dimension.h +++ b/libdimension/dimension.h @@ -21,10 +21,8 @@ #ifndef DIMENSION_H #define DIMENSION_H -#include <stdbool.h> -#include <stdint.h> - #ifdef __cplusplus +/* We've been included from a C++ file; mark everything here as extern "C" */ extern "C" { #endif diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h index 4449403..f05264b 100644 --- a/libdimension/dimension/canvas.h +++ b/libdimension/dimension/canvas.h @@ -18,15 +18,14 @@ * <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; @@ -40,6 +39,7 @@ typedef struct { pthread_rwlock_t *rwlocks; } dmnsn_canvas; +/* Allocate and free a canvas */ dmnsn_canvas *dmnsn_new_canvas(unsigned int x, unsigned int y); void dmnsn_delete_canvas(dmnsn_canvas *canvas); diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index 0e64875..f1964c3 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -25,10 +25,6 @@ #ifndef DIMENSION_COLOR_H #define DIMENSION_COLOR_H -#ifdef __cplusplus -extern "C" { -#endif - /* Internally, we use CIE 1931 XYZ color. */ typedef struct { double X, Y, Z; @@ -67,6 +63,8 @@ typedef struct { /* Standard whitepoint, determined by the conversion of sRGB white to XYZ */ extern const dmnsn_CIE_XYZ dmnsn_whitepoint; +/* Color conversions */ + dmnsn_color dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ); dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY); dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white); @@ -79,11 +77,10 @@ dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); +/* Perceptually correct color combination */ dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2); -double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); -#ifdef __cplusplus -} -#endif +/* Perceptual color difference */ +double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); #endif /* DIMENSION_COLOR_H */ diff --git a/libdimension/dimension/error.h b/libdimension/dimension/error.h index 2c00a4a..858ff96 100644 --- a/libdimension/dimension/error.h +++ b/libdimension/dimension/error.h @@ -18,24 +18,28 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +#ifndef DIMENSION_ERROR_H +#define DIMENSION_ERROR_H + /* * Error handling. */ -#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(severity, __PRETTY_FUNCTION__, __LINE__, str) +/* Called by dmnsn_error() - don't call directly */ void dmnsn_report_error(dmnsn_severity severity, const char *func, unsigned int line, const char *str); + +/* Get and set the library resilience, thread-safely */ dmnsn_severity dmnsn_get_resilience(); void dmnsn_set_resilience(dmnsn_severity resilience); diff --git a/libdimension/dimension/geometry.h b/libdimension/dimension/geometry.h index 26705ca..e1d1497 100644 --- a/libdimension/dimension/geometry.h +++ b/libdimension/dimension/geometry.h @@ -29,12 +29,13 @@ typedef double dmnsn_scalar; typedef struct { dmnsn_scalar x, y, z; } dmnsn_vector; -/* Vector arithmetic */ - +/* Shorthand for vector construction */ dmnsn_vector dmnsn_vector_construct(dmnsn_scalar x, dmnsn_scalar y, dmnsn_scalar z); +/* Vector arithmetic */ + dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs); dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs); dmnsn_vector dmnsn_vector_mul(dmnsn_scalar lhs, dmnsn_vector rhs); diff --git a/libdimension/error.c b/libdimension/error.c index 728652b..38ba40b 100644 --- a/libdimension/error.c +++ b/libdimension/error.c @@ -26,29 +26,36 @@ static dmnsn_severity dmnsn_resilience = DMNSN_SEVERITY_MEDIUM; static pthread_mutex_t dmnsn_resilience_mutex = PTHREAD_MUTEX_INITIALIZER; +// Called by dmnsn_error macro (don't call directly). void dmnsn_report_error(dmnsn_severity severity, const char *func, unsigned int line, const char *str) { if (severity >= dmnsn_get_resilience()) { + // An error more severe than our resilience happened, bail out fprintf(stderr, "Dimension ERROR: %s, line %u: %s\n", func, line, str); exit(EXIT_FAILURE); } else { + // A trivial error happened, warn and continue fprintf(stderr, "Dimension WARNING: %s, line %u: %s\n", func, line, str); } } +/* Return the current resilience, thread-safely. */ dmnsn_severity dmnsn_get_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__, "Couldn't lock resilience mutex."); } - resilience = dmnsn_resilience; + resilience = dmnsn_resilience; // Copy the static variable to a local if (pthread_mutex_unlock(&dmnsn_resilience_mutex) != 0) { + // 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__, "Couldn't unlock resilience mutex."); @@ -60,6 +67,7 @@ void 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__, "Resilience has wrong value."); @@ -67,12 +75,15 @@ 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__, "Couldn't lock resilience mutex."); } dmnsn_resilience = resilience; if (pthread_mutex_unlock(&dmnsn_resilience_mutex) != 0) { + // 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__, "Couldn't unlock resilience mutex."); diff --git a/libdimension/geometry.c b/libdimension/geometry.c index 5786f57..0eab10b 100644 --- a/libdimension/geometry.c +++ b/libdimension/geometry.c @@ -20,6 +20,7 @@ #include "dimension.h" +/* Construct a vector from x, y, and z. Just for convienence. */ dmnsn_vector dmnsn_vector_construct(dmnsn_scalar x, dmnsn_scalar y, dmnsn_scalar z) { @@ -27,6 +28,7 @@ dmnsn_vector_construct(dmnsn_scalar x, dmnsn_scalar y, dmnsn_scalar z) return v; } +/* Add two vectors */ dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -36,6 +38,7 @@ dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs) return v; } +/* Subtract two vectors */ dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -45,6 +48,7 @@ dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs) return v; } +/* Multiply a vector by a scalar */ dmnsn_vector dmnsn_vector_mul(dmnsn_scalar lhs, dmnsn_vector rhs) { @@ -52,6 +56,7 @@ dmnsn_vector_mul(dmnsn_scalar lhs, dmnsn_vector rhs) return v; } +/* Divide a vector by a scalar */ dmnsn_vector dmnsn_vector_div(dmnsn_vector lhs, dmnsn_scalar rhs) { @@ -59,12 +64,14 @@ dmnsn_vector_div(dmnsn_vector lhs, dmnsn_scalar rhs) return v; } +/* Dot product */ dmnsn_scalar dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs) { return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z; } +/* Cross product */ dmnsn_vector dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -74,6 +81,7 @@ dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs) return v; } +/* A point on a line, l. Returns l.x0 + t*l.n */ dmnsn_vector dmnsn_line_point(dmnsn_line l, dmnsn_scalar t) { |