/* * CS5600 University of Utah * Charles McGarvey * mcgarvey@eng.utah.edu */ #ifndef _COLOR_H_ #define _COLOR_H_ #include "common.h" /* * A color channel will be the same as a scalar. */ typedef scal_t colorchan_t; /* * A color class. * Colors are represented by RGBA values between 0.0 and 1.0. */ struct color { colorchan_t r; colorchan_t g; colorchan_t b; colorchan_t a; }; typedef struct color color_t; /* * Initialize a color. */ INLINE_MAYBE void color_init(color_t* c, colorchan_t r, colorchan_t g, colorchan_t b, colorchan_t a) { c->r = r; c->g = g; c->b = b; c->a = a; } /* * Create a new color, copied by value. */ INLINE_MAYBE color_t color_new(colorchan_t r, colorchan_t g, colorchan_t b, colorchan_t a) { color_t c; color_init(&c, r, g, b, a); return c; } #define COLOR_CLEAR color_new(S(0.0), S(0.0), S(0.0), S(0.0)) #define COLOR_BLACK color_new(S(0.0), S(0.0), S(0.0), S(1.0)) #define COLOR_RED color_new(S(1.0), S(0.0), S(0.0), S(1.0)) #define COLOR_GREEN color_new(S(0.0), S(1.0), S(0.0), S(1.0)) #define COLOR_BLUE color_new(S(0.0), S(0.0), S(1.0), S(1.0)) #define COLOR_YELLOW color_new(S(1.0), S(1.0), S(0.0), S(1.0)) #define COLOR_MAGENTA color_new(S(1.0), S(0.0), S(1.0), S(1.0)) #define COLOR_CYAN color_new(S(0.0), S(1.0), S(1.0), S(1.0)) #define COLOR_WHITE color_new(S(1.0), S(1.0), S(1.0), S(1.0)) /* * Print the color to stdout. */ INLINE_MAYBE void color_print(color_t c) { #if (SCALAR_SIZE == 8) const char* fmt = "[ %9.5lf %9.5lf %9.5lf %9.5lf ]"; #else const char* fmt = "[ %9.5f %9.5f %9.5f %9.5f ]"; #endif printf(fmt, c.r, c.g, c.b, c.a); } /* * Add two colors together. */ INLINE_MAYBE color_t color_add(color_t c1, color_t c2) { return color_new(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b, c1.a); } /* * Add three colors together. */ INLINE_MAYBE color_t color_add2(color_t c1, color_t c2, color_t c3) { return color_add(color_add(c1, c2), c3); } /* * Multiply two colors together. */ INLINE_MAYBE color_t color_mult(color_t c1, color_t c2) { c1.r *= c2.r; c1.g *= c2.g; c1.b *= c2.b; return c1; } /* * Scale a color by some scalar coefficient. */ INLINE_MAYBE color_t color_scale(color_t c, scal_t k) { c.r *= k; c.g *= k; c.b *= k; return c; } /* * Scale a color by another color and some scalar coefficient. */ INLINE_MAYBE color_t color_scale2(color_t c1, color_t c2, scal_t k) { return color_scale(color_mult(c1, c2), k); } INLINE_MAYBE color_t color_blend(color_t d, color_t s) { d.r = (S(1.0) - s.a) * d.r + s.a * s.r; d.g = (S(1.0) - s.a) * d.g + s.a * s.g; d.b = (S(1.0) - s.a) * d.b + s.a * s.b; return d; } /* * Clamp a color's channels to the normal range of 0.0 to 1.0. */ INLINE_MAYBE color_t color_clamp(color_t c) { c.r = scal_clamp(c.r, S(0.0), S(1.0)); c.g = scal_clamp(c.g, S(0.0), S(1.0)); c.b = scal_clamp(c.b, S(0.0), S(1.0)); c.a = scal_clamp(c.a, S(0.0), S(1.0)); return c; } /* * Interpolate smoothly between two colors with an alpha value. */ INLINE_MAYBE color_t color_interp(color_t c1, color_t c2, scal_t a) { return color_new(c1.r * (S(1.0) - a) + c2.r * a, c1.g * (S(1.0) - a) + c2.g * a, c1.b * (S(1.0) - a) + c2.b * a, c1.a); } /* * Interpolate smoothly between three colors with barycentric coordinates. */ INLINE_MAYBE color_t color_interp2(color_t c1, color_t c2, color_t c3, scal_t b[3]) { return color_new(c1.r * b[0] + c2.r * b[1] + c3.r * b[2], c1.g * b[0] + c2.g * b[1] + c3.g * b[2], c1.b * b[0] + c2.b * b[1] + c3.b * b[2], c1.a); } /* * Define integer types for a 32-bit RGBA color representation. */ typedef uint8_t rgbachan_t; typedef uint32_t rgba_t; /* * Create a new color from a 32-bit RGBA value. */ INLINE_MAYBE color_t color_from_rgba(rgba_t n) { colorchan_t r = (colorchan_t)UNPACK(n, 3) / S(255.0); colorchan_t g = (colorchan_t)UNPACK(n, 2) / S(255.0); colorchan_t b = (colorchan_t)UNPACK(n, 1) / S(255.0); colorchan_t a = (colorchan_t)UNPACK(n, 0) / S(255.0); return color_new(r, g, b, a); } /* * Split a color into 8-bit RGBA channels. */ INLINE_MAYBE void color_split(color_t c, rgbachan_t* r, rgbachan_t* g, rgbachan_t* b, rgbachan_t* a) { if (r) *r = (rgbachan_t)(c.r * S(255.0)); if (g) *g = (rgbachan_t)(c.g * S(255.0)); if (b) *b = (rgbachan_t)(c.b * S(255.0)); if (a) *a = (rgbachan_t)(c.a * S(255.0)); } /* * Convert a color to a 32-bit RGBA value. */ INLINE_MAYBE rgba_t rgba_from_color(color_t c) { rgbachan_t r, g, b, a; color_split(c, &r, &g, &b, &a); return ((rgba_t)r << 24) | ((rgba_t)g << 16) | ((rgba_t)b << 8) | (rgba_t)a; } #endif // _COLOR_H_