From bfbe9e43e108f6816c17b9b7764b75284ac78313 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 14 Dec 2011 19:27:22 -0500 Subject: 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. --- libdimension/dimension/color.h | 192 ++++++++++++++++++++++++++++------------- 1 file changed, 131 insertions(+), 61 deletions(-) (limited to 'libdimension/dimension/color.h') 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 /** 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 \ - "" +#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) -- cgit v1.2.3