summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-04-22 13:19:09 -0400
committerTavian Barnes <tavianator@gmail.com>2011-04-22 13:19:09 -0400
commit68e39815977c406b8ec39ee3e2fe975087b66303 (patch)
tree3eb5f109af2c21edf15bd83a336ce6a3e8720615
parent1208ac55766e410f7cac3ad9d6cf588e7846ca64 (diff)
downloaddimension-68e39815977c406b8ec39ee3e2fe975087b66303.tar.xz
Make colors less abstract.
-rw-r--r--dimension/realize.c17
-rw-r--r--libdimension/color.c308
-rw-r--r--libdimension/dimension/color.h98
-rw-r--r--libdimension/gl.c67
-rw-r--r--libdimension/png.c145
-rw-r--r--tests/libdimension/render.c6
6 files changed, 130 insertions, 511 deletions
diff --git a/dimension/realize.c b/dimension/realize.c
index 019011e..2603ba1 100644
--- a/dimension/realize.c
+++ b/dimension/realize.c
@@ -98,18 +98,11 @@ dmnsn_realize_color(dmnsn_astnode astnode)
dmnsn_array_get(astnode.children, 3, &fnode);
dmnsn_array_get(astnode.children, 4, &tnode);
- double r = dmnsn_realize_float(rnode),
- g = dmnsn_realize_float(gnode),
- b = dmnsn_realize_float(bnode),
- f = dmnsn_realize_float(fnode),
- t = dmnsn_realize_float(tnode);
-
- dmnsn_sRGB sRGB = { .R = r, .G = g, .B = b };
- dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
- color.filter = f;
- color.trans = t;
-
- return color;
+ return dmnsn_new_color5(dmnsn_realize_float(rnode),
+ dmnsn_realize_float(gnode),
+ dmnsn_realize_float(bnode),
+ dmnsn_realize_float(fnode),
+ dmnsn_realize_float(tnode));
}
static dmnsn_matrix
diff --git a/libdimension/color.c b/libdimension/color.c
index 0af063f..24a4574 100644
--- a/libdimension/color.c
+++ b/libdimension/color.c
@@ -24,12 +24,6 @@
*/
#include "dimension.h"
-#include <math.h> /* For pow(), sqrt() */
-
-/* sRGB white point (CIE D50) */
-const dmnsn_CIE_XYZ dmnsn_whitepoint = { .X = 0.9504060171449392,
- .Y = 0.9999085943425312,
- .Z = 1.089062231497274 };
/* Standard colors */
const dmnsn_color dmnsn_black = {
@@ -103,252 +97,19 @@ const dmnsn_color dmnsn_cyan = {
.trans = 0.0
};
-bool
-dmnsn_color_is_black(dmnsn_color color)
-{
- return color.R == 0.0 && color.G == 0.0 && color.B == 0.0;
-}
-
-/* Convert an sRGB color to a dmnsn_color (actually a no-op) */
-dmnsn_color
-dmnsn_color_from_sRGB(dmnsn_sRGB sRGB)
-{
- dmnsn_color ret = {
- .R = sRGB.R,
- .G = sRGB.G,
- .B = sRGB.B,
- .filter = 0.0,
- .trans = 0.0
- };
- 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:
- *
- * { 12.92*Clinear, Clinear <= 0.0031308
- * Csrgb = { 1/2.4
- * { (1.055)*Clinear - 0.055, Clinear > 0.0031308
- */
- if (Clinear <= 0.0031308) {
- return 12.92*Clinear;
- } else {
- return 1.055*pow(Clinear, 1.0/2.4) - 0.055;
- }
-}
-
-/* Convert a CIE XYZ color to a dmnsn_color */
-dmnsn_color
-dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ)
-{
- dmnsn_color color = {
- .R = 3.2410*XYZ.X - 1.5374*XYZ.Y - 0.4986*XYZ.Z,
- .G = -0.9692*XYZ.X + 1.8760*XYZ.Y + 0.0416*XYZ.Z,
- .B = 0.0556*XYZ.X - 0.2040*XYZ.Y + 1.0570*XYZ.Z,
- .filter = 0.0,
- .trans = 0.0
- };
- color.R = dmnsn_sRGB_C(color.R);
- color.G = dmnsn_sRGB_C(color.G);
- color.B = dmnsn_sRGB_C(color.B);
- return color;
-}
-
-/* Convert a CIE xyY color to a dmnsn_color */
-dmnsn_color
-dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY)
-{
- dmnsn_CIE_XYZ ret = {
- .X = xyY.Y*xyY.x/xyY.y,
- .Y = xyY.Y,
- .Z = xyY.Y*(1.0 - xyY.x - xyY.y)/xyY.y,
- };
- return dmnsn_color_from_XYZ(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;
- } else {
- return 108.0*(t - 16.0/116.0)/841.0;
- }
-}
-
-/* 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)
-{
- double fx, fy, fz;
- dmnsn_CIE_XYZ ret;
-
- fy = (Lab.L + 16.0)/116.0;
- fx = fy + Lab.a/500.0;
- fz = fy - Lab.b/200.0;
-
- ret.X = white.X*dmnsn_Lab_finv(fx);
- ret.Y = white.Y*dmnsn_Lab_finv(fy);
- ret.Z = white.Z*dmnsn_Lab_finv(fz);
- return dmnsn_color_from_XYZ(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)
-{
- double fy;
- double uprime, unprime, vprime, vnprime;
- dmnsn_CIE_XYZ ret;
-
- fy = (Luv.L + 16.0)/116.0;
-
- unprime = 4.0*white.X/(white.X + 15.0*white.Y + 3.0*white.Z);
- uprime = Luv.u/Luv.L/13.0 + unprime;
- vnprime = 9.0*white.Y/(white.X + 15.0*white.Y + 3.0*white.Z);
- vprime = Luv.v/Luv.L/13.0 + vnprime;
-
- ret.Y = white.Y*dmnsn_Lab_finv(fy);
- ret.X = ret.Y*9.0*uprime/vprime/4.0;
- ret.Z = ret.Y*(12.0 - 3*uprime - 20*vprime)/vprime/4.0;
- return dmnsn_color_from_XYZ(ret);
-}
-
-/* Convert a dmnsn_color to an sRGB color (actually a no-op) */
-dmnsn_sRGB
-dmnsn_sRGB_from_color(dmnsn_color color)
-{
- dmnsn_sRGB sRGB = { .R = color.R, .G = color.G, .B = color.B };
- return sRGB;
-}
-
-/** 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
- * follows:
- *
- * { Csrgb/12.92, Csrgb <= 0.04045
- * Clinear = { 1/2.4
- * { ((Csrgb + 0.055)/1.055) , Csrgb > 0.04045
- */
- if (CsRGB <= 0.040449936) {
- return CsRGB/12.92;
- } else {
- return pow((CsRGB + 0.055)/1.055, 2.4);
- }
-}
-
-/* Convert a dmnsn_color to a CIE XYZ color */
-dmnsn_CIE_XYZ
-dmnsn_XYZ_from_color(dmnsn_color color)
-{
- color.R = dmnsn_sRGB_Cinv(color.R);
- color.G = dmnsn_sRGB_Cinv(color.G);
- color.B = dmnsn_sRGB_Cinv(color.B);
-
- dmnsn_CIE_XYZ ret = {
- .X = 0.4123808838268995*color.R + 0.3575728355732478*color.G
- + 0.1804522977447919*color.B,
- .Y = 0.2126198631048975*color.R + 0.7151387878413206*color.G
- + 0.0721499433963131*color.B,
- .Z = 0.0193434956789248*color.R + 0.1192121694056356*color.G
- + 0.9505065664127130*color.B,
- };
- return ret;
-}
-
-/* Convert a dmnsn_color to a CIE xyY color */
-dmnsn_CIE_xyY
-dmnsn_xyY_from_color(dmnsn_color color)
-{
- dmnsn_CIE_XYZ XYZ = dmnsn_XYZ_from_color(color);
- dmnsn_CIE_xyY ret = {
- .x = XYZ.X/(XYZ.X + XYZ.Y + XYZ.Z),
- .y = XYZ.Y/(XYZ.X + XYZ.Y + XYZ.Z),
- .Y = XYZ.Y
- };
- 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);
- } else {
- return 841.0*t/108.0 + 4.0/29.0;
- }
-}
-
-/* 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)
-{
- dmnsn_CIE_XYZ XYZ = dmnsn_XYZ_from_color(color);
- dmnsn_CIE_Lab ret;
-
- ret.L = 116.0*dmnsn_Lab_f(XYZ.Y/white.Y) - 16.0;
- ret.a = 500.0*(dmnsn_Lab_f(XYZ.X/white.X) - dmnsn_Lab_f(XYZ.Y/white.Y));
- ret.b = 200.0*(dmnsn_Lab_f(XYZ.Y/white.Y) - dmnsn_Lab_f(XYZ.Z/white.Z));
- 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)
-{
- dmnsn_CIE_XYZ XYZ = dmnsn_XYZ_from_color(color);
- double uprime, unprime, vprime, vnprime;
- dmnsn_CIE_Luv ret;
-
- uprime = 4.0*XYZ.X / (XYZ.X + 15.0*XYZ.Y + 3.0*XYZ.Z);
- unprime = 4.0*white.X / (white.X + 15.0*white.Y + 3.0*white.Z);
- vprime = 9.0*XYZ.Y / (XYZ.X + 15.0*XYZ.Y + 3.0*XYZ.Z);
- vnprime = 9.0*white.Y / (white.X + 15.0*white.Y + 3.0*white.Z);
-
- ret.L = 116.0*dmnsn_Lab_f(XYZ.Y/white.Y) - 16.0;
- ret.u = 13.0*ret.L*(uprime - unprime);
- ret.v = 13.0*ret.L*(vprime - vnprime);
- return ret;
-}
-
/* Greyscale color intensity */
double
dmnsn_color_intensity(dmnsn_color color)
{
- dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color);
- return 0.2126198631048975*sRGB.R + 0.7151387878413206*sRGB.G
- + 0.0721499433963131*sRGB.B;
+ return 0.2126198631048975*color.R + 0.7151387878413206*color.G
+ + 0.0721499433963131*color.B;
}
/* Add two colors */
dmnsn_color
dmnsn_color_add(dmnsn_color c1, dmnsn_color c2)
{
- dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(c1);
- dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(c2);
-
- dmnsn_sRGB sRGB = {
- .R = sRGB1.R + sRGB2.R,
- .G = sRGB1.G + sRGB2.G,
- .B = sRGB1.B + sRGB2.B
- };
-
- dmnsn_color ret = dmnsn_color_from_sRGB(sRGB);
+ dmnsn_color ret = dmnsn_new_color(c1.R + c2.R, c1.G + c2.G, c1.B + c2.B);
double n1 = dmnsn_color_intensity(c1), n2 = dmnsn_color_intensity(c2);
if (n1 + n2 != 0.0) {
@@ -363,34 +124,23 @@ dmnsn_color_add(dmnsn_color c1, dmnsn_color c2)
dmnsn_color
dmnsn_color_mul(double n, dmnsn_color color)
{
- dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color);
- sRGB.R *= n;
- sRGB.G *= n;
- sRGB.B *= n;
-
- dmnsn_color ret = dmnsn_color_from_sRGB(sRGB);
- ret.filter = color.filter;
- ret.trans = color.trans;
- return ret;
+ color.R *= n;
+ color.G *= n;
+ color.B *= n;
+ return color;
}
/* For n in [0, 1] get the color in a gradient between c1 and c2 */
dmnsn_color
dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n)
{
- dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(c1);
- dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(c2);
-
- dmnsn_sRGB sRGB = {
- .R = n*(sRGB2.R - sRGB1.R) + sRGB1.R,
- .G = n*(sRGB2.G - sRGB1.G) + sRGB1.G,
- .B = n*(sRGB2.B - sRGB1.B) + sRGB1.B
- };
-
- dmnsn_color ret = dmnsn_color_from_sRGB(sRGB);
- ret.filter = n*(c2.filter - c1.filter) + c1.filter;
- ret.trans = n*(c2.trans - c1.trans) + c1.trans;
- return ret;
+ return dmnsn_new_color5(
+ n*(c2.R - c1.R) + c1.R,
+ n*(c2.G - c1.G) + c1.G,
+ n*(c2.B - c1.B) + c1.B,
+ n*(c2.filter - c1.filter) + c1.filter,
+ n*(c2.trans - c1.trans) + c1.trans
+ );
}
/* Filters `light' through `filter' */
@@ -433,32 +183,6 @@ dmnsn_apply_filter(dmnsn_color color, dmnsn_color filter)
dmnsn_color
dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color)
{
- /* We use the sRGB primaries */
- dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(light);
- dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(color);
-
- dmnsn_sRGB sRGB = {
- .R = sRGB1.R*sRGB2.R,
- .G = sRGB1.G*sRGB2.G,
- .B = sRGB1.B*sRGB2.B
- };
-
- dmnsn_color ret = dmnsn_color_from_sRGB(sRGB);
- ret.filter = color.filter;
- ret.trans = color.trans;
- return ret;
-}
-
-/* Find the perceptual difference between two colors, using CIE L*a*b* */
-double
-dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2)
-{
- dmnsn_CIE_Lab Lab1, Lab2;
-
- Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint);
- Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint);
-
- return sqrt((Lab1.L - Lab2.L)*(Lab1.L - Lab2.L)
- + (Lab1.a - Lab2.a)*(Lab1.a - Lab2.a)
- + (Lab1.b - Lab2.b)*(Lab1.b - Lab2.b));
+ return dmnsn_new_color5(light.R*color.R, light.G*color.G, light.B*color.B,
+ color.filter, color.trans);
}
diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h
index 887c2c7..8db5158 100644
--- a/libdimension/dimension/color.h
+++ b/libdimension/dimension/color.h
@@ -30,52 +30,16 @@
/** A color value. */
typedef struct {
+ double R; /**< sRGB red value. */
+ double G; /**< sRGB green value. */
+ double B; /**< sRGB blue value. */
+
/** Filtered transparency. */
double filter;
/** Unfiltered transparency; <tt>filter + trans</tt> should be <= 1. */
double trans;
-
- /* Internally we use sRGB color. */
- double R; /**< @internal sRGB red value. */
- double G; /**< @internal sRGB green value. */
- double B; /**< @internal sRGB blue value. */
} dmnsn_color;
-/** sRGB color. */
-typedef struct {
- double R; /**< sRGB red value. */
- double G; /**< sRGB green value. */
- double B; /**< sRGB blue value. */
-} dmnsn_sRGB;
-
-/** CIE XYZ color. */
-typedef struct {
- double X; /**< X component. */
- double Y; /**< Y (luminance) component. */
- double Z; /**< Z component. */
-} dmnsn_CIE_XYZ;
-
-/** CIE xyY color. */
-typedef struct {
- double x; /**< x chromaticity coordinate (in [0, 1]). */
- double y; /**< y chromaticity coordinate (in [0, 1]). */
- double Y; /**< Luminance, unbounded >= 0; 1 is diffuse white. */
-} dmnsn_CIE_xyY;
-
-/** CIE 1976 (L*, a*, b*) color. */
-typedef struct {
- double L; /**< Luminance (100 is diffuse white). */
- double a; /**< Red/greed color-opponent value. */
- double b; /**< Yellow/blue color-opponent value. */
-} dmnsn_CIE_Lab;
-
-/** CIE 1976 (L*, u*, v*) color. */
-typedef struct {
- double L; /**< Luminance (same L* as CIE L*, a*, b*). */
- double u; /**< u* coordinate. */
- double v; /**< v* coordinate. */
-} dmnsn_CIE_Luv;
-
/* Standard colors */
extern const dmnsn_color dmnsn_black; /**< Black. */
extern const dmnsn_color dmnsn_white; /**< White. */
@@ -88,36 +52,33 @@ extern const dmnsn_color dmnsn_orange; /**< Orange. */
extern const dmnsn_color dmnsn_yellow; /**< Yellow. */
extern const dmnsn_color dmnsn_cyan; /**< Cyan. */
-/** Standard whitepoint, determined by the conversion of sRGB white to
- CIE XYZ */
-extern const dmnsn_CIE_XYZ dmnsn_whitepoint;
-
-/** Is this color black? */
-bool dmnsn_color_is_black(dmnsn_color color);
+/* Color construction */
-/* Color conversions */
+/** 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 };
+ return ret;
+}
-/** Convert an sRGB color to a Dimension color. */
-dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB);
-/** Convert a CIE XYZ color to a Dimension color. */
-dmnsn_color dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ);
-/** Convert a CIE xyY color to a Dimension color. */
-dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY);
-/** Convert a CIE L*, a*, b* color to a Dimension color. */
-dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white);
-/** Convert a CIE L*, u*, v* color to a Dimension color. */
-dmnsn_color dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white);
+/** Construct a new color with transparent components. */
+DMNSN_INLINE dmnsn_color
+dmnsn_new_color5(double R, double G, double B, double filter, double trans)
+{
+ dmnsn_color ret = { R, G, B, filter, trans };
+ return ret;
+}
-/** Convert a Dimension color to sRGB. */
-dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color);
-/** Convert a Dimension color to CIE XYZ. */
-dmnsn_CIE_XYZ dmnsn_XYZ_from_color(dmnsn_color color);
-/** Convert a Dimension color to CIE xyY. */
-dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color);
-/** Convert a Dimension color to CIE L*, a*, b*. */
-dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white);
-/** Convert a Dimension color to CIE L*, u*, v*. */
-dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white);
+/** Is this color black? */
+DMNSN_INLINE bool
+dmnsn_color_is_black(dmnsn_color color)
+{
+ return fabs(color.R) < dmnsn_epsilon
+ && fabs(color.G) < dmnsn_epsilon
+ && fabs(color.B) < dmnsn_epsilon
+ && fabs(color.trans) < dmnsn_epsilon;
+}
/* Perceptual color manipulation */
@@ -138,7 +99,4 @@ dmnsn_color dmnsn_apply_filter(dmnsn_color color, dmnsn_color filter);
/** Illuminate \p color with \p light. */
dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color);
-/** Return the perceptual difference between two colors. */
-double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2);
-
#endif /* DIMENSION_COLOR_H */
diff --git a/libdimension/gl.c b/libdimension/gl.c
index 857c7de..587038f 100644
--- a/libdimension/gl.c
+++ b/libdimension/gl.c
@@ -62,7 +62,6 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
{
GLushort *pixels; /* Array of 16-bit ints in RGBA order */
GLushort *pixel;
- dmnsn_sRGB sRGB;
dmnsn_color color;
size_t width = canvas->width;
@@ -84,32 +83,31 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas)
pixel = pixels + 4*(y*width + x);
color = dmnsn_get_pixel(canvas, x, y);
- sRGB = dmnsn_sRGB_from_color(color);
/* Saturate R, G, and B to [0, UINT16_MAX] */
- if (sRGB.R <= 0.0) {
+ if (color.R <= 0.0) {
pixel[0] = 0;
- } else if (sRGB.R >= 1.0) {
+ } else if (color.R >= 1.0) {
pixel[0] = UINT16_MAX;
} else {
- pixel[0] = sRGB.R*UINT16_MAX;
+ pixel[0] = color.R*UINT16_MAX;
}
- if (sRGB.G <= 0.0) {
+ if (color.G <= 0.0) {
pixel[1] = 0;
- } else if (sRGB.G >= 1.0) {
+ } else if (color.G >= 1.0) {
pixel[1] = UINT16_MAX;
} else {
- pixel[1] = sRGB.G*UINT16_MAX;
+ pixel[1] = color.G*UINT16_MAX;
}
- if (sRGB.B <= 0.0) {
+ if (color.B <= 0.0) {
pixel[2] = 0;
- } else if (sRGB.B >= 1.0) {
+ } else if (color.B >= 1.0) {
pixel[2] = UINT16_MAX;
} else {
- pixel[2] = sRGB.B*UINT16_MAX;
+ pixel[2] = color.B*UINT16_MAX;
}
double alpha = dmnsn_color_intensity(color)*color.filter + color.trans;
@@ -134,14 +132,10 @@ dmnsn_canvas *
dmnsn_gl_read_canvas(size_t x0, size_t y0,
size_t width, size_t height)
{
- dmnsn_canvas *canvas;
- GLushort *pixels; /* Array of 16-bit ints in RGBA order */
- GLushort *pixel;
- dmnsn_sRGB sRGB;
- dmnsn_color color;
+ dmnsn_canvas *canvas = dmnsn_new_canvas(width, height);
- canvas = dmnsn_new_canvas(width, height);
- pixels = dmnsn_malloc(4*width*height*sizeof(GLushort));
+ /* Array of 16-bit ints in RGBA order */
+ GLushort *pixels = dmnsn_malloc(4*width*height*sizeof(GLushort));
glReadPixels(x0, y0, width, height, GL_RGBA, GL_UNSIGNED_SHORT, pixels);
@@ -153,14 +147,13 @@ dmnsn_gl_read_canvas(size_t x0, size_t y0,
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
- pixel = pixels + 4*(y*width + x);
-
- sRGB.R = ((double)pixel[0])/UINT16_MAX;
- sRGB.G = ((double)pixel[1])/UINT16_MAX;
- sRGB.B = ((double)pixel[2])/UINT16_MAX;
+ GLushort *pixel = pixels + 4*(y*width + x);
- color = dmnsn_color_from_sRGB(sRGB);
- color.filter = ((double)pixel[3])/UINT16_MAX;
+ dmnsn_color color = dmnsn_new_color5((double)pixel[0]/UINT16_MAX,
+ (double)pixel[1]/UINT16_MAX,
+ (double)pixel[2]/UINT16_MAX,
+ 0.0,
+ (double)pixel[3]/UINT16_MAX);
dmnsn_set_pixel(canvas, x, y, color);
}
}
@@ -174,37 +167,33 @@ static void
dmnsn_gl_optimizer_fn(const dmnsn_canvas *canvas,
dmnsn_canvas_optimizer optimizer, size_t x, size_t y)
{
- dmnsn_color color;
- dmnsn_sRGB sRGB;
GLushort *pixel = (GLushort *)optimizer.ptr + 4*(y*canvas->width + x);
-
- color = dmnsn_get_pixel(canvas, x, y);
- sRGB = dmnsn_sRGB_from_color(color);
+ dmnsn_color color = dmnsn_get_pixel(canvas, x, y);
/* Saturate R, G, and B to [0, UINT16_MAX] */
- if (sRGB.R <= 0.0) {
+ if (color.R <= 0.0) {
pixel[0] = 0;
- } else if (sRGB.R >= 1.0) {
+ } else if (color.R >= 1.0) {
pixel[0] = UINT16_MAX;
} else {
- pixel[0] = sRGB.R*UINT16_MAX;
+ pixel[0] = color.R*UINT16_MAX;
}
- if (sRGB.G <= 0.0) {
+ if (color.G <= 0.0) {
pixel[1] = 0;
- } else if (sRGB.G >= 1.0) {
+ } else if (color.G >= 1.0) {
pixel[1] = UINT16_MAX;
} else {
- pixel[1] = sRGB.G*UINT16_MAX;
+ pixel[1] = color.G*UINT16_MAX;
}
- if (sRGB.B <= 0.0) {
+ if (color.B <= 0.0) {
pixel[2] = 0;
- } else if (sRGB.B >= 1.0) {
+ } else if (color.B >= 1.0) {
pixel[2] = UINT16_MAX;
} else {
- pixel[2] = sRGB.B*UINT16_MAX;
+ pixel[2] = color.B*UINT16_MAX;
}
double alpha = dmnsn_color_intensity(color)*color.filter + color.trans;
diff --git a/libdimension/png.c b/libdimension/png.c
index 7a327d6..534a085 100644
--- a/libdimension/png.c
+++ b/libdimension/png.c
@@ -62,36 +62,34 @@ dmnsn_png_optimizer_fn(const dmnsn_canvas *canvas,
dmnsn_canvas_optimizer optimizer, size_t x, size_t y)
{
dmnsn_color color;
- dmnsn_sRGB sRGB;
uint16_t *pixel = (uint16_t *)optimizer.ptr + 4*(y*canvas->width + x);
color = dmnsn_get_pixel(canvas, x, y);
- sRGB = dmnsn_sRGB_from_color(color);
/* Saturate R, G, and B to [0, UINT16_MAX] */
- if (sRGB.R <= 0.0) {
+ if (color.R <= 0.0) {
pixel[0] = 0;
- } else if (sRGB.R >= 1.0) {
+ } else if (color.R >= 1.0) {
pixel[0] = UINT16_MAX;
} else {
- pixel[0] = sRGB.R*UINT16_MAX;
+ pixel[0] = color.R*UINT16_MAX;
}
- if (sRGB.G <= 0.0) {
+ if (color.G <= 0.0) {
pixel[1] = 0;
- } else if (sRGB.G >= 1.0) {
+ } else if (color.G >= 1.0) {
pixel[1] = UINT16_MAX;
} else {
- pixel[1] = sRGB.G*UINT16_MAX;
+ pixel[1] = color.G*UINT16_MAX;
}
- if (sRGB.B <= 0.0) {
+ if (color.B <= 0.0) {
pixel[2] = 0;
- } else if (sRGB.B >= 1.0) {
+ } else if (color.B >= 1.0) {
pixel[2] = UINT16_MAX;
} else {
- pixel[2] = sRGB.B*UINT16_MAX;
+ pixel[2] = color.B*UINT16_MAX;
}
double alpha = dmnsn_color_intensity(color)*color.filter + color.trans;
@@ -274,32 +272,31 @@ dmnsn_png_write_canvas_thread(void *ptr)
for (size_t x = 0; x < width; ++x) {
/* Invert the rows. PNG coordinates are fourth quadrant. */
dmnsn_color color = dmnsn_get_pixel(payload->canvas, x, height - y - 1);
- dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color);
/* Saturate R, G, and B to [0, UINT16_MAX] */
- if (sRGB.R <= 0.0) {
+ if (color.R <= 0.0) {
row[4*x] = 0;
- } else if (sRGB.R >= 1.0) {
+ } else if (color.R >= 1.0) {
row[4*x] = UINT16_MAX;
} else {
- row[4*x] = sRGB.R*UINT16_MAX;
+ row[4*x] = color.R*UINT16_MAX;
}
- if (sRGB.G <= 0.0) {
+ if (color.G <= 0.0) {
row[4*x + 1] = 0;
- } else if (sRGB.G >= 1.0) {
+ } else if (color.G >= 1.0) {
row[4*x + 1] = UINT16_MAX;
} else {
- row[4*x + 1] = sRGB.G*UINT16_MAX;
+ row[4*x + 1] = color.G*UINT16_MAX;
}
- if (sRGB.B <= 0.0) {
+ if (color.B <= 0.0) {
row[4*x + 2] = 0;
- } else if (sRGB.B >= 1.0) {
+ } else if (color.B >= 1.0) {
row[4*x + 2] = UINT16_MAX;
} else {
- row[4*x + 2] = sRGB.B*UINT16_MAX;
+ row[4*x + 2] = color.B*UINT16_MAX;
}
double alpha = color.filter + color.trans;
@@ -445,86 +442,46 @@ dmnsn_png_read_canvas_thread(void *ptr)
/* Now we convert the image to our canvas format. This depends on the image
bit depth (which has been scaled up to at least 8 or 16), and the presence
- of an alpha channel. For performance reasons, the tests are outside the
- loops, although that doesn't really matter for a decent compiler. */
- if (bit_depth == 16) {
- if (color_type & PNG_COLOR_MASK_ALPHA) {
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- png_bytep png_pixel = image + 8*(y*width + x);
-
- dmnsn_sRGB sRGB = {
- .R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1]))
- /UINT16_MAX,
- .G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3]))
- /UINT16_MAX,
- .B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5]))
- /UINT16_MAX
- };
-
- dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
- color.trans = ((double)((png_pixel[6] << UINT16_C(8))
- + png_pixel[7]))/UINT16_MAX;
- dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
- }
- dmnsn_increment_progress(payload->progress);
- }
- } else {
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- png_bytep png_pixel = image + 6*(y*width + x);
+ of an alpha channel. */
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ dmnsn_color color;
+ color.filter = 0.0;
- dmnsn_sRGB sRGB = {
- .R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1]))
- /UINT16_MAX,
- .G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3]))
- /UINT16_MAX,
- .B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5]))
- /UINT16_MAX
- };
-
- dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
- dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
- }
- dmnsn_increment_progress(payload->progress);
- }
- }
- } else {
- /* Bit depth is 8 */
- if (color_type & PNG_COLOR_MASK_ALPHA) {
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
+ if (color_type & PNG_COLOR_MASK_ALPHA) {
+ if (bit_depth == 16) {
+ png_bytep png_pixel = image + 8*(y*width + x);
+ color.R = (double)((png_pixel[0] << 8) + png_pixel[1])/UINT16_MAX;
+ color.G = (double)((png_pixel[2] << 8) + png_pixel[3])/UINT16_MAX;
+ color.R = (double)((png_pixel[4] << 8) + png_pixel[5])/UINT16_MAX;
+ color.trans = (double)((png_pixel[6] << 8) + png_pixel[7])/UINT16_MAX;
+ } else {
png_bytep png_pixel = image + 4*(y*width + x);
-
- dmnsn_sRGB sRGB = {
- .R = ((double)png_pixel[0])/UINT8_MAX,
- .G = ((double)png_pixel[1])/UINT8_MAX,
- .B = ((double)png_pixel[2])/UINT8_MAX
- };
-
- dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
- color.trans = ((double)png_pixel[3])/UINT8_MAX;
- dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
+ color.R = (double)png_pixel[0]/UINT16_MAX;
+ color.G = (double)png_pixel[1]/UINT16_MAX;
+ color.R = (double)png_pixel[2]/UINT16_MAX;
+ color.trans = (double)png_pixel[3]/UINT16_MAX;
}
- dmnsn_increment_progress(payload->progress);
- }
- } else {
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- png_bytep png_pixel = image + 3*(y*width + x);
-
- dmnsn_sRGB sRGB = {
- sRGB.R = ((double)png_pixel[0])/UINT8_MAX,
- sRGB.G = ((double)png_pixel[1])/UINT8_MAX,
- sRGB.B = ((double)png_pixel[2])/UINT8_MAX
- };
+ } else {
+ color.trans = 0.0;
- dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
- dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
+ if (bit_depth == 16) {
+ png_bytep png_pixel = image + 6*(y*width + x);
+ color.R = (double)((png_pixel[0] << 8) + png_pixel[1])/UINT16_MAX;
+ color.G = (double)((png_pixel[2] << 8) + png_pixel[3])/UINT16_MAX;
+ color.R = (double)((png_pixel[4] << 8) + png_pixel[5])/UINT16_MAX;
+ } else {
+ png_bytep png_pixel = image + 3*(y*width + x);
+ color.R = (double)png_pixel[0]/UINT16_MAX;
+ color.G = (double)png_pixel[1]/UINT16_MAX;
+ color.R = (double)png_pixel[2]/UINT16_MAX;
}
- dmnsn_increment_progress(payload->progress);
}
+
+ dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
}
+
+ dmnsn_increment_progress(payload->progress);
}
dmnsn_free(row_pointers);
diff --git a/tests/libdimension/render.c b/tests/libdimension/render.c
index 44548d1..5b03423 100644
--- a/tests/libdimension/render.c
+++ b/tests/libdimension/render.c
@@ -73,8 +73,7 @@ dmnsn_new_test_scene(void)
dmnsn_pattern *sky_gradient = dmnsn_new_gradient_pattern(dmnsn_y);
dmnsn_map *sky_gradient_color_map = dmnsn_new_color_map();
dmnsn_add_map_entry(sky_gradient_color_map, 0.0, &dmnsn_orange);
- dmnsn_color background = dmnsn_color_from_sRGB((dmnsn_sRGB){ 0.0, 0.1, 0.2 });
- background.filter = 0.1;
+ dmnsn_color background = dmnsn_new_color5(0.0, 0.1, 0.2, 0.1, 0.0);
dmnsn_add_map_entry(sky_gradient_color_map, 0.35, &background);
dmnsn_pigment *sky_pigment
= dmnsn_new_color_map_pigment(sky_gradient, sky_gradient_color_map);
@@ -194,8 +193,7 @@ dmnsn_new_test_scene(void)
dmnsn_add_map_entry(checker_pigment_map, 1.0, &pigment2);
plane->texture->pigment
= dmnsn_new_pigment_map_pigment(checker2, checker_pigment_map);
- plane->texture->pigment->quick_color
- = dmnsn_color_from_sRGB((dmnsn_sRGB){ 1.0, 0.5, 0.75 });
+ plane->texture->pigment->quick_color = dmnsn_new_color(1.0, 0.5, 0.75);
dmnsn_array_push(scene->objects, &plane);
return scene;