summaryrefslogtreecommitdiffstats
path: root/libdimension
diff options
context:
space:
mode:
Diffstat (limited to 'libdimension')
-rw-r--r--libdimension/canvas.c32
-rw-r--r--libdimension/color.c20
-rw-r--r--libdimension/dimension.h4
-rw-r--r--libdimension/dimension/canvas.h8
-rw-r--r--libdimension/dimension/color.h13
-rw-r--r--libdimension/dimension/error.h10
-rw-r--r--libdimension/dimension/geometry.h5
-rw-r--r--libdimension/error.c13
-rw-r--r--libdimension/geometry.c8
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)
{