summaryrefslogtreecommitdiffstats
path: root/libdimension/dimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-12-14 19:27:22 -0500
committerTavian Barnes <tavianator@gmail.com>2011-12-14 19:52:36 -0500
commitbfbe9e43e108f6816c17b9b7764b75284ac78313 (patch)
tree189f85eeec18a76ccb626e45455fa7e45406db7c /libdimension/dimension
parent7db5342a36341b061a8785a3b349cf0fcad69ebf (diff)
downloaddimension-bfbe9e43e108f6816c17b9b7764b75284ac78313.tar.xz
Re-think colors.
Color is a property of light, and thus doesn't include information about transparency. But canvas pixels and object pigments represent a color and a degree of transparency. The new type dmnsn_tcolor/ TColor encapsulates that information. Also, fix the transparent shadow implementation.
Diffstat (limited to 'libdimension/dimension')
-rw-r--r--libdimension/dimension/canvas.h18
-rw-r--r--libdimension/dimension/color.h192
-rw-r--r--libdimension/dimension/finish.h8
-rw-r--r--libdimension/dimension/finishes.h7
-rw-r--r--libdimension/dimension/pigment.h10
-rw-r--r--libdimension/dimension/pigments.h11
-rw-r--r--libdimension/dimension/tcolor.h100
7 files changed, 249 insertions, 97 deletions
diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h
index 48a64c1..ba06b8c 100644
--- a/libdimension/dimension/canvas.h
+++ b/libdimension/dimension/canvas.h
@@ -26,7 +26,7 @@
#include <stddef.h>
/** A canvas, or image. */
-typedef struct {
+typedef struct dmnsn_canvas {
size_t width; /**< Canvas width. */
size_t height; /**< Canvas height. */
@@ -38,7 +38,7 @@ typedef struct {
* Stored in first-quadrant representation (origin is bottom-left). The pixel
* at (a,b) is accessible as pixels[b*width + a].
*/
- dmnsn_color *pixels;
+ dmnsn_tcolor *pixels;
dmnsn_refcount refcount; /**< @internal Reference count. */
} dmnsn_canvas;
@@ -94,9 +94,9 @@ void dmnsn_canvas_optimize(dmnsn_canvas *canvas,
* @param[in] canvas The canvas to access.
* @param[in] x The x coordinate.
* @param[in] y The y coordinate.
- * @return The color of the canvas at (\p x, \p y).
+ * @return The color of the pixel at (\p x, \p y).
*/
-DMNSN_INLINE dmnsn_color
+DMNSN_INLINE dmnsn_tcolor
dmnsn_canvas_get_pixel(const dmnsn_canvas *canvas, size_t x, size_t y)
{
dmnsn_assert(x < canvas->width && y < canvas->height,
@@ -105,18 +105,18 @@ dmnsn_canvas_get_pixel(const dmnsn_canvas *canvas, size_t x, size_t y)
}
/**
- * Set the color of a pixel.
+ * Set the value of a pixel.
* @param[in,out] canvas The canvas to modify.
* @param[in] x The x coordinate of the pixel.
* @param[in] y The y coordinate of the pixel.
- * @param[in] color The color to set the pixel at (\p x, \p y) to.
+ * @param[in] tcolor The value to set the pixel at (\p x, \p y) to.
*/
void dmnsn_canvas_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y,
- dmnsn_color color);
+ dmnsn_tcolor tcolor);
/**
* Clear a canvas uniformly with a given color.
* @param[in,out] canvas The canvas to erase.
- * @param[in] color The color to paint it with.
+ * @param[in] tcolor The color to paint it with.
*/
-void dmnsn_canvas_clear(dmnsn_canvas *canvas, dmnsn_color color);
+void dmnsn_canvas_clear(dmnsn_canvas *canvas, dmnsn_tcolor tcolor);
diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h
index 295400b..34f3884 100644
--- a/libdimension/dimension/color.h
+++ b/libdimension/dimension/color.h
@@ -20,97 +20,167 @@
/**
* @file
- * Color-related types and operations.
+ * Colors.
*/
#include <stdbool.h>
/** A color value. */
typedef struct {
- double R; /**< Red. */
- double G; /**< Green. */
- double B; /**< Blue. */
-
- double trans; /**< Transparency. */
- double filter; /**< Degree of filtering. */
+ double R; /**< Red component. */
+ double G; /**< Green component. */
+ double B; /**< Blue component. */
} dmnsn_color;
/** A standard format string for colors. */
-#define DMNSN_COLOR_FORMAT \
- "<red = %g, green = %g, blue = %g, trans = %g, filter = %g>"
+#define DMNSN_COLOR_FORMAT "Color<%g, %g, %g>"
/** The appropriate arguements to printf() a color. */
-#define DMNSN_COLOR_PRINTF(c) (c).R, (c).G, (c).B, (c).trans, (c).filter
-
-/* Standard colors */
-extern const dmnsn_color dmnsn_black; /**< Black. */
-extern const dmnsn_color dmnsn_white; /**< White. */
-extern const dmnsn_color dmnsn_clear; /**< Clear. */
-extern const dmnsn_color dmnsn_red; /**< Red. */
-extern const dmnsn_color dmnsn_green; /**< Green. */
-extern const dmnsn_color dmnsn_blue; /**< Blue. */
-extern const dmnsn_color dmnsn_magenta; /**< Magenta. */
-extern const dmnsn_color dmnsn_orange; /**< Orange. */
-extern const dmnsn_color dmnsn_yellow; /**< Yellow. */
-extern const dmnsn_color dmnsn_cyan; /**< Cyan. */
-
-/* Color construction */
+#define DMNSN_COLOR_PRINTF(c) (c).R, (c).G, (c).B
/** Construct a new color. */
DMNSN_INLINE dmnsn_color
dmnsn_new_color(double R, double G, double B)
{
- dmnsn_color ret = { R, G, B, 0.0, 0.0 };
+ dmnsn_color ret = { R, G, B };
return ret;
}
-/** Construct a new color with transparent components. */
-DMNSN_INLINE dmnsn_color
-dmnsn_new_color5(double R, double G, double B, double trans, double filter)
+/** Apply sRGB gamma */
+DMNSN_INLINE double
+dmnsn_sRGB_gamma(double Clinear)
{
- dmnsn_color ret = { R, G, B, trans, filter };
- return ret;
+ /*
+ * If C represents R, G, and B, then the sRGB values are now found as follows:
+ *
+ * { 12.92*Clinear, Clinear <= 0.0031308
+ * Csrgb = { 1/2.4
+ * { (1.055)*Clinear - 0.055, Clinear > 0.0031308
+ */
+ if (Clinear == 1.0) {
+ return 1.0; /* Map 1.0 to 1.0 instead of 0.9999999999999999 */
+ } else if (Clinear > 0.0031308) {
+ return 1.055*pow(Clinear, 1.0/2.4) - 0.055;
+ } else {
+ return 12.92*Clinear;
+ }
}
-/** Saturate the color components to [0.0, 1.0]. */
+/** Convert to sRGB space. */
DMNSN_INLINE dmnsn_color
-dmnsn_color_saturate(dmnsn_color color)
+dmnsn_color_to_sRGB(dmnsn_color color)
{
- color.R = dmnsn_min(dmnsn_max(color.R, 0.0), 1.0);
- color.G = dmnsn_min(dmnsn_max(color.G, 0.0), 1.0);
- color.B = dmnsn_min(dmnsn_max(color.B, 0.0), 1.0);
- color.trans = dmnsn_min(dmnsn_max(color.trans, 0.0), 1.0);
- color.filter = dmnsn_min(dmnsn_max(color.filter, 0.0), 1.0);
- return color;
+ return dmnsn_new_color(
+ dmnsn_sRGB_gamma(color.R),
+ dmnsn_sRGB_gamma(color.G),
+ dmnsn_sRGB_gamma(color.B)
+ );
}
-/* Perceptual color manipulation */
-
-/** Apply sRGB gamma */
-double dmnsn_sRGB_gamma(double Clinear);
-/** Convert to sRGB space. */
-dmnsn_color dmnsn_color_to_sRGB(dmnsn_color color);
/** Remove sRGB gamma */
-double dmnsn_sRGB_inverse_gamma(double CsRGB);
+DMNSN_INLINE double
+dmnsn_sRGB_inverse_gamma(double CsRGB)
+{
+ /*
+ * If C represents R, G, and B, then the Clinear values are now found as
+ * follows:
+ *
+ * { Csrgb/12.92, Csrgb <= 0.04045
+ * Clinear = { 1/2.4
+ * { ((Csrgb + 0.055)/1.055) , Csrgb > 0.04045
+ */
+ if (CsRGB == 1.0) {
+ return 1.0; /* Map 1.0 to 1.0 instead of 0.9999999999999999 */
+ } else if (CsRGB <= 0.040449936) {
+ return CsRGB/12.92;
+ } else {
+ return pow((CsRGB + 0.055)/1.055, 2.4);
+ }
+}
+
/** Convert from sRGB space. */
-dmnsn_color dmnsn_color_from_sRGB(dmnsn_color color);
+DMNSN_INLINE dmnsn_color
+dmnsn_color_from_sRGB(dmnsn_color color)
+{
+ return dmnsn_new_color(
+ dmnsn_sRGB_inverse_gamma(color.R),
+ dmnsn_sRGB_inverse_gamma(color.G),
+ dmnsn_sRGB_inverse_gamma(color.B)
+ );
+}
/** Greyscale color intensity. */
-double dmnsn_color_intensity(dmnsn_color color);
+DMNSN_INLINE double
+dmnsn_color_intensity(dmnsn_color color)
+{
+ return 0.2126*color.R + 0.7152*color.G + 0.0722*color.B;
+}
+
/** Add two colors together. */
-dmnsn_color dmnsn_color_add(dmnsn_color lhs, dmnsn_color rhs);
+DMNSN_INLINE dmnsn_color
+dmnsn_color_add(dmnsn_color lhs, dmnsn_color rhs)
+{
+ return dmnsn_new_color(lhs.R + rhs.R, lhs.G + rhs.G, lhs.B + rhs.B);
+}
+
/** Subtract two colors. */
-dmnsn_color dmnsn_color_sub(dmnsn_color lhs, dmnsn_color rhs);
-/** Multiply a color's intensity by \p n. */
-dmnsn_color dmnsn_color_mul(double n, dmnsn_color color);
+DMNSN_INLINE dmnsn_color
+dmnsn_color_sub(dmnsn_color lhs, dmnsn_color rhs)
+{
+ return dmnsn_new_color(lhs.R - rhs.R, lhs.G - rhs.G, lhs.B - rhs.B);
+}
+
+/** Scale a color's intensity. */
+DMNSN_INLINE dmnsn_color
+dmnsn_color_mul(double n, dmnsn_color color)
+{
+ return dmnsn_new_color(n*color.R, n*color.G, n*color.B);
+}
+
/** Return the color at \p n on a gradient from \p c1 at 0 to \p c2 at 1. */
-dmnsn_color dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n);
-/** Filter \p light through \p filter. */
-dmnsn_color dmnsn_filter_light(dmnsn_color light, dmnsn_color filter);
-/** Add the background contribution \p filtered to \p filter. */
-dmnsn_color dmnsn_apply_transparency(dmnsn_color filtered, dmnsn_color filter);
-/** Add the background contribution of \p color to \p filter. */
-dmnsn_color dmnsn_apply_filter(dmnsn_color color, dmnsn_color filter);
-/** Convert the color into a close equivalent with only transmittance. */
-dmnsn_color dmnsn_remove_filter(dmnsn_color color);
+DMNSN_INLINE dmnsn_color
+dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n)
+{
+ return dmnsn_new_color(
+ n*(c2.R - c1.R) + c1.R,
+ n*(c2.G - c1.G) + c1.G,
+ n*(c2.B - c1.B) + c1.B
+ );
+}
+
/** Illuminate \p color with \p light. */
-dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color);
+DMNSN_INLINE dmnsn_color
+dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color)
+{
+ return dmnsn_new_color(light.R*color.R, light.G*color.G, light.B*color.B);
+}
+
+/** Saturate the color components to [0.0, 1.0]. */
+DMNSN_INLINE dmnsn_color
+dmnsn_color_saturate(dmnsn_color color)
+{
+ color.R = dmnsn_min(dmnsn_max(color.R, 0.0), 1.0);
+ color.G = dmnsn_min(dmnsn_max(color.G, 0.0), 1.0);
+ color.B = dmnsn_min(dmnsn_max(color.B, 0.0), 1.0);
+ return color;
+}
+
+/* Standard colors */
+
+/** Black. */
+#define dmnsn_black dmnsn_new_color(0.0, 0.0, 0.0)
+/** White. */
+#define dmnsn_white dmnsn_new_color(1.0, 1.0, 1.0)
+/** Red. */
+#define dmnsn_red dmnsn_new_color(1.0, 0.0, 0.0)
+/** Green. */
+#define dmnsn_green dmnsn_new_color(0.0, 1.0, 0.0)
+/** Blue. */
+#define dmnsn_blue dmnsn_new_color(0.0, 0.0, 1.0)
+/** Magenta. */
+#define dmnsn_magenta dmnsn_new_color(1.0, 0.0, 1.0)
+/** Orange. */
+#define dmnsn_orange dmnsn_new_color(1.0, 0.21404114048223255, 0.0)
+/** Yellow. */
+#define dmnsn_yellow dmnsn_new_color(1.0, 1.0, 0.0)
+/** Cyan. */
+#define dmnsn_cyan dmnsn_new_color(0.0, 1.0, 1.0)
diff --git a/libdimension/dimension/finish.h b/libdimension/dimension/finish.h
index 2e3b48c..4ac9239 100644
--- a/libdimension/dimension/finish.h
+++ b/libdimension/dimension/finish.h
@@ -38,14 +38,12 @@ typedef dmnsn_color dmnsn_ambient_fn(const dmnsn_ambient *ambient,
/** Ambient finish component. */
struct dmnsn_ambient {
- dmnsn_ambient_fn *ambient_fn; /**< Ambient callback. */
- dmnsn_free_fn *free_fn; /**< Destructor callback. */
- void *ptr; /**< Generic data pointer. */
- dmnsn_refcount refcount; /**< @internal Reference count. */
+ dmnsn_color ambient; /**< Ambient light. */
+ dmnsn_refcount refcount; /**< @internal Reference count. */
};
/** Allocate a dummy ambient component. */
-dmnsn_ambient *dmnsn_new_ambient(void);
+dmnsn_ambient *dmnsn_new_ambient(dmnsn_color ambient);
/** Delete an ambient component. */
void dmnsn_delete_ambient(dmnsn_ambient *ambient);
diff --git a/libdimension/dimension/finishes.h b/libdimension/dimension/finishes.h
index d9cd14c..7ed66d3 100644
--- a/libdimension/dimension/finishes.h
+++ b/libdimension/dimension/finishes.h
@@ -24,13 +24,6 @@
*/
/**
- * Ambient finish.
- * @param[in] ambient The color of the ambient light.
- * @return An ambient finish component.
- */
-dmnsn_ambient *dmnsn_new_basic_ambient(dmnsn_color ambient);
-
-/**
* Regular diffuse finish.
* @param[in] diffuse The diffuse reflection coefficient.
* @return A diffuse finish component.
diff --git a/libdimension/dimension/pigment.h b/libdimension/dimension/pigment.h
index 716c28b..176ff28 100644
--- a/libdimension/dimension/pigment.h
+++ b/libdimension/dimension/pigment.h
@@ -32,8 +32,8 @@ typedef struct dmnsn_pigment dmnsn_pigment;
* @param[in] v The point to color.
* @return The color of the pigment at \p v.
*/
-typedef dmnsn_color dmnsn_pigment_fn(const dmnsn_pigment *pigment,
- dmnsn_vector v);
+typedef dmnsn_tcolor dmnsn_pigment_fn(const dmnsn_pigment *pigment,
+ dmnsn_vector v);
/**
* Pigment initializer callback.
@@ -51,7 +51,7 @@ struct dmnsn_pigment {
dmnsn_matrix trans_inv; /**< The inverse of the transformation matrix. */
/** Quick color -- used for low-quality renders. */
- dmnsn_color quick_color;
+ dmnsn_tcolor quick_color;
/** Generic pointer. */
void *ptr;
@@ -86,5 +86,5 @@ void dmnsn_pigment_initialize(dmnsn_pigment *pigment);
* @param[in] v The point to color.
* @return The color at \p v.
*/
-dmnsn_color dmnsn_pigment_evaluate(const dmnsn_pigment *pigment,
- dmnsn_vector v);
+dmnsn_tcolor dmnsn_pigment_evaluate(const dmnsn_pigment *pigment,
+ dmnsn_vector v);
diff --git a/libdimension/dimension/pigments.h b/libdimension/dimension/pigments.h
index 3584167..383e38b 100644
--- a/libdimension/dimension/pigments.h
+++ b/libdimension/dimension/pigments.h
@@ -28,7 +28,7 @@
* @param[in] color The color of the pigment.
* @return A pigment with the color \p color everywhere.
*/
-dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_color color);
+dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_tcolor color);
/**
* An image map. The image (regardless of its real dimensions) is projected
@@ -53,15 +53,6 @@ typedef enum dmnsn_pigment_map_flags {
dmnsn_map *dmnsn_new_pigment_map(void);
/**
- * Add a raw color to a pigment map.
- * Shorthand for creating a solid pigment and adding it manually.
- * @param[in,out] map The pigment map to add to.
- * @param[in] n The index of the entry.
- * @param[in] color The value of the entry.
- */
-void dmnsn_pigment_map_add_color(dmnsn_map *map, double n, dmnsn_color color);
-
-/**
* A pigment-mapped pigment.
* @param[in,out] pattern The pattern of the pigment.
* @param[in,out] map The pigment map to apply to the pattern.
diff --git a/libdimension/dimension/tcolor.h b/libdimension/dimension/tcolor.h
new file mode 100644
index 0000000..d1b7338
--- /dev/null
+++ b/libdimension/dimension/tcolor.h
@@ -0,0 +1,100 @@
+/*************************************************************************
+ * Copyright (C) 2009-2011 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library is distributed in the hope that it will be *
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Colors with transparency information.
+ */
+
+/** A transparent color. */
+typedef struct dmnsn_tcolor {
+ dmnsn_color c; /**< Color. */
+ double T; /**< Transparency. */
+ double F; /**< Proportion of filtered transparency. */
+} dmnsn_tcolor;
+
+/** Create a tcolor. */
+DMNSN_INLINE dmnsn_tcolor
+dmnsn_new_tcolor(dmnsn_color c, double T, double F)
+{
+ dmnsn_tcolor ret = { c, T, F };
+ return ret;
+}
+
+/** Convert a dmnsn_color into a dmnsn_tcolor. */
+#define DMNSN_TCOLOR(c) dmnsn_new_tcolor(c, 0.0, 0.0)
+
+/** Create a tcolor with individually-specified components. */
+DMNSN_INLINE dmnsn_tcolor
+dmnsn_new_tcolor5(double R, double G, double B, double T, double F)
+{
+ dmnsn_tcolor ret = { dmnsn_new_color(R, G, B), T, F };
+ return ret;
+}
+
+/** Return the color at \p n on a gradient from \p c1 at 0 to \p c2 at 1. */
+DMNSN_INLINE dmnsn_tcolor
+dmnsn_tcolor_gradient(dmnsn_tcolor c1, dmnsn_tcolor c2, double n)
+{
+ return dmnsn_new_tcolor(
+ dmnsn_color_gradient(c1.c, c2.c, n),
+ n*(c2.T - c1.T) + c1.T,
+ n*(c2.F - c1.F) + c1.F
+ );
+}
+
+/** Filter \p light through \p filter. */
+DMNSN_INLINE dmnsn_color
+dmnsn_tcolor_filter(dmnsn_color light, dmnsn_tcolor filter)
+{
+ dmnsn_color filtered =
+ dmnsn_color_mul(filter.T*filter.F, dmnsn_color_illuminate(light, filter.c));
+ dmnsn_color transmitted = dmnsn_color_mul(filter.T*(1.0 - filter.F), light);
+ return dmnsn_color_add(filtered, transmitted);
+}
+
+/** Remove the filtered component of a tcolor. */
+DMNSN_INLINE dmnsn_tcolor
+dmnsn_tcolor_remove_filter(dmnsn_tcolor tcolor)
+{
+ double intensity = dmnsn_color_intensity(tcolor.c);
+ double newtrans = (1.0 - (1.0 - intensity)*tcolor.F)*tcolor.T;
+ if (1.0 - newtrans >= dmnsn_epsilon) {
+ tcolor.c = dmnsn_color_mul((1.0 - tcolor.T)/(1.0 - newtrans), tcolor.c);
+ }
+ tcolor.T = newtrans;
+ tcolor.F = 0.0;
+ return tcolor;
+}
+
+/** Saturate the tcolor components to [0.0, 1.0]. */
+DMNSN_INLINE dmnsn_tcolor
+dmnsn_tcolor_saturate(dmnsn_tcolor tcolor)
+{
+ tcolor.c = dmnsn_color_saturate(tcolor.c);
+ tcolor.T = dmnsn_min(dmnsn_max(tcolor.T, 0.0), 1.0);
+ tcolor.F = dmnsn_min(dmnsn_max(tcolor.F, 0.0), 1.0);
+ return tcolor;
+}
+
+/* Standard tcolors */
+
+/** Clear. */
+#define dmnsn_clear dmnsn_new_tcolor5(0.0, 0.0, 0.0, 0.0, 0.0)