From c576229cc54c0fb963967751281e6a42fc9230ea Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 17 Nov 2009 22:59:29 -0500 Subject: Use CIE 1931 RGB for dmnsn_color_illuminate(). --- libdimension/color.c | 104 ++++++++++++++++++++++++++++++++++------- libdimension/dimension/color.h | 9 +++- tests/libdimension/tests.c | 12 ++--- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/libdimension/color.c b/libdimension/color.c index 79def12..0ec9e0b 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -28,9 +28,41 @@ const dmnsn_CIE_XYZ dmnsn_whitepoint = { .X = 0.9504060171449392, /* Standard colors */ const dmnsn_color dmnsn_black = { .X = 0.0, .Y = 0.0, .Z = 0.0 }; -const dmnsn_color dmnsn_white = { .X = 0.9504060171449392, - .Y = 0.9999085943425312, - .Z = 1.089062231497274 }; +const dmnsn_color dmnsn_white = { + .X = 0.9504060171449392, + .Y = 0.9999085943425312, + .Z = 1.089062231497274 +}; +const dmnsn_color dmnsn_red = { + .X = 0.4123808838268995, + .Y = 0.2126198631048975, + .Z = 0.0193434956789248 +}; +const dmnsn_color dmnsn_green = { + .X = 0.3575728355732478, + .Y = 0.7151387878413206, + .Z = 0.1192121694056356 +}; +const dmnsn_color dmnsn_blue = { + .X = 0.1804522977447919, + .Y = 0.0721499433963131, + .Z = 0.950506566412713 +}; +const dmnsn_color dmnsn_magenta = { + .X = 0.5928331815716914, + .Y = 0.2847698065012106, + .Z = 0.9698500620916378 +}; +const dmnsn_color dmnsn_yellow = { + .X = 0.7699537194001473, + .Y = 0.9277586509462181, + .Z = 0.1385556650845604 +}; +const dmnsn_color dmnsn_cyan = { + .X = 0.5380251333180397, + .Y = 0.7872887312376337, + .Z = 1.069718735818349 +}; /* Convert a CIE XYZ color to a dmnsn_color (actually a no-op) */ dmnsn_color @@ -45,11 +77,26 @@ dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ) dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY) { - dmnsn_color ret = { .X = xyY.Y*xyY.x/xyY.y, - .Y = xyY.Y, - .Z = xyY.Y*(1.0 - xyY.x - xyY.y)/xyY.y, - .filter = 0.0, - .trans = 0.0 }; + dmnsn_color ret = { + .X = xyY.Y*xyY.x/xyY.y, + .Y = xyY.Y, + .Z = xyY.Y*(1.0 - xyY.x - xyY.y)/xyY.y, + .filter = 0.0, + .trans = 0.0 + }; + return ret; +} + +dmnsn_color +dmnsn_color_from_RGB(dmnsn_CIE_RGB RGB) +{ + dmnsn_color ret = { + .X = 0.49*RGB.R + 0.31*RGB.G + 0.20*RGB.B, + .Y = 0.17697*RGB.R + 0.81240*RGB.G + 0.01063*RGB.B, + .Z = 0.00*RGB.R + 0.01*RGB.G + 0.99*RGB.B, + .filter = 0.0, + .trans = 0.0 + }; return ret; } @@ -168,9 +215,25 @@ dmnsn_XYZ_from_color(dmnsn_color color) dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color) { - dmnsn_CIE_xyY ret = { .x = color.X/(color.X + color.Y + color.Z), - .y = color.Y/(color.X + color.Y + color.Z), - .Y = color.Y }; + dmnsn_CIE_xyY ret = { + .x = color.X/(color.X + color.Y + color.Z), + .y = color.Y/(color.X + color.Y + color.Z), + .Y = color.Y + }; + return ret; +} + +dmnsn_CIE_RGB +dmnsn_RGB_from_color(dmnsn_color color) +{ + dmnsn_CIE_RGB ret = { + .R = 2.36461384653836548*color.X + -0.89654057073966797*color.Y + + -0.46807327579869740*color.Z, + .G = -0.51516620844788796*color.X + 1.42640810385638872*color.Y + + 0.08875810459149917*color.Z, + .B = 0.00520369907523119*color.X + -0.01440816266521605*color.Y + + 1.00920446358998483*color.Z + }; return ret; } @@ -298,15 +361,20 @@ dmnsn_color_mul(double n, dmnsn_color color) dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color) { - /* TODO: make this work in a perceptually uniform colorspace */ - dmnsn_sRGB sRGB1 = dmnsn_sRGB_from_color(light); - dmnsn_sRGB sRGB2 = dmnsn_sRGB_from_color(color); + static dmnsn_CIE_RGB white = { 0.0 }; + if (!white.R) + white = dmnsn_RGB_from_color(dmnsn_white); + + dmnsn_CIE_RGB RGB1 = dmnsn_RGB_from_color(light); + dmnsn_CIE_RGB RGB2 = dmnsn_RGB_from_color(color); - dmnsn_sRGB sRGB = { .R = sRGB1.R*sRGB2.R, - .G = sRGB1.G*sRGB2.G, - .B = sRGB1.B*sRGB2.B }; + dmnsn_CIE_RGB RGB = { + .R = RGB1.R*RGB2.R/white.R, + .G = RGB1.G*RGB2.G/white.G, + .B = RGB1.B*RGB2.B/white.B + }; - dmnsn_color ret = dmnsn_color_from_sRGB(sRGB); + dmnsn_color ret = dmnsn_color_from_RGB(RGB); ret.filter = color.filter; ret.trans = color.trans; diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index a72de98..ad50334 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -45,6 +45,10 @@ typedef struct { white */ } dmnsn_CIE_xyY; +typedef struct { + double R, G, B; /* CIE 1931 RGB, a linear transformation of CIE XYZ */ +} dmnsn_CIE_RGB; + typedef struct { double L, a, b; /* L is luminence (100 = diffuse white); a and b are color- opponent dimensions. This color space is used for color @@ -61,7 +65,8 @@ typedef struct { } dmnsn_sRGB; /* Standard colors */ -extern const dmnsn_color dmnsn_black, dmnsn_white; +extern const dmnsn_color dmnsn_black, dmnsn_white, dmnsn_red, dmnsn_green, + dmnsn_blue, dmnsn_magenta, dmnsn_yellow, dmnsn_cyan; /* Standard whitepoint, determined by the conversion of sRGB white to CIE XYZ */ extern const dmnsn_CIE_XYZ dmnsn_whitepoint; @@ -70,12 +75,14 @@ extern const dmnsn_CIE_XYZ dmnsn_whitepoint; 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_RGB(dmnsn_CIE_RGB RGB); dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white); dmnsn_color dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white); dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB); dmnsn_CIE_XYZ dmnsn_XYZ_from_color(dmnsn_color color); dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color); +dmnsn_CIE_RGB dmnsn_RGB_from_color(dmnsn_color color); 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); diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c index 62c4454..b2670f8 100644 --- a/tests/libdimension/tests.c +++ b/tests/libdimension/tests.c @@ -22,17 +22,15 @@ dmnsn_scene * dmnsn_new_default_scene() { - dmnsn_scene *scene; - /* Allocate a new scene */ - scene = dmnsn_new_scene(); + dmnsn_scene *scene = dmnsn_new_scene(); if (!scene) { return NULL; } /* Default finish */ - scene->default_texture->finish = dmnsn_new_phong_finish(1.0, 0.2, 50.0); + scene->default_texture->finish = dmnsn_new_phong_finish(1.0, 0.5, 50.0); if (!scene->default_texture->finish) { dmnsn_delete_scene(scene); return NULL; @@ -90,7 +88,7 @@ dmnsn_new_default_scene() return NULL; } - sphere->texture->pigment = dmnsn_new_solid_pigment(dmnsn_white); + sphere->texture->pigment = dmnsn_new_solid_pigment(dmnsn_yellow); if (!sphere->texture->pigment) { dmnsn_delete_scene(scene); return NULL; @@ -111,7 +109,7 @@ dmnsn_new_default_scene() return NULL; } - cube->texture->pigment = dmnsn_new_solid_pigment(dmnsn_white); + cube->texture->pigment = dmnsn_new_solid_pigment(dmnsn_magenta); if (!cube->texture->pigment) { dmnsn_delete_scene(scene); return NULL; @@ -123,7 +121,7 @@ dmnsn_new_default_scene() dmnsn_light *light = dmnsn_new_point_light( dmnsn_vector_construct(-15.0, 20.0, 10.0), - dmnsn_white + dmnsn_cyan ); if (!light) { dmnsn_delete_scene(scene); -- cgit v1.2.3