From 6d8fbc2953c6ae29ee5162ca04920d6cef85d0ce Mon Sep 17 00:00:00 2001 From: rodri Date: Thu, 4 Jul 2024 14:57:00 +0000 Subject: rough color space conversion implementation. colors are now properly processed in linear RGB space for lighting, shading and blending. sRGB is assumed for any texture sampled and the destination framebuffer. it's not perfect, but it does the job for now. --- color.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 color.c (limited to 'color.c') diff --git a/color.c b/color.c new file mode 100644 index 0000000..cdd089f --- /dev/null +++ b/color.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include "libobj/obj.h" +#include "graphics.h" +#include "internal.h" + +/* + * generated with: + * % seq 0 255 | awk '{$0 = $0/255; if($0 > 0.04045) $0 = (($0+0.055)/1.055)^2.4; else $0 = $0/12.92; printf("\t0x%02X,%s", int($0*255+0.5), NR%8 == 0? "\n": "")}' + */ +static uchar srgb2lineartab[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, + 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, + 0x0A, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, + 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, + 0x11, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, + 0x14, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, + 0x19, 0x19, 0x1A, 0x1B, 0x1B, 0x1C, 0x1D, 0x1D, + 0x1E, 0x1E, 0x1F, 0x20, 0x20, 0x21, 0x22, 0x23, + 0x23, 0x24, 0x25, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, + 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4A, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x5A, 0x5B, 0x5C, 0x5D, 0x5F, 0x60, 0x61, 0x63, + 0x64, 0x65, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, + 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x79, + 0x7A, 0x7C, 0x7D, 0x7F, 0x80, 0x82, 0x83, 0x85, + 0x86, 0x88, 0x8A, 0x8B, 0x8D, 0x8E, 0x90, 0x92, + 0x93, 0x95, 0x97, 0x98, 0x9A, 0x9C, 0x9D, 0x9F, + 0xA1, 0xA3, 0xA4, 0xA6, 0xA8, 0xAA, 0xAB, 0xAD, + 0xAF, 0xB1, 0xB3, 0xB5, 0xB7, 0xB8, 0xBA, 0xBC, + 0xBE, 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, + 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, + 0xDE, 0xE0, 0xE2, 0xE5, 0xE7, 0xE9, 0xEB, 0xED, + 0xEF, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFD, 0xFF, +}; + +/* + * generated with: + * % seq 0 255 | awk '{$0 = $0/255.0; if($0 > 0.0031308) $0 = 1.055*$0^(1.0/2.4)-0.055; else $0 = $0*12.92; printf("\t0x%02X,%s", int($0*255+0.5), NR%8 == 0? "\n": "")}' + */ +static uchar linear2srgbtab[] = { + 0x00, 0x0D, 0x16, 0x1C, 0x22, 0x26, 0x2A, 0x2E, + 0x32, 0x35, 0x38, 0x3B, 0x3D, 0x40, 0x42, 0x45, + 0x47, 0x49, 0x4B, 0x4D, 0x4F, 0x51, 0x53, 0x55, + 0x56, 0x58, 0x5A, 0x5C, 0x5D, 0x5F, 0x60, 0x62, + 0x63, 0x65, 0x66, 0x68, 0x69, 0x6A, 0x6C, 0x6D, + 0x6E, 0x70, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9B, 0x9C, 0x9D, 0x9E, + 0x9F, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA3, 0xA4, + 0xA5, 0xA6, 0xA7, 0xA7, 0xA8, 0xA9, 0xAA, 0xAA, + 0xAB, 0xAC, 0xAD, 0xAD, 0xAE, 0xAF, 0xAF, 0xB0, + 0xB1, 0xB2, 0xB2, 0xB3, 0xB4, 0xB4, 0xB5, 0xB6, + 0xB6, 0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB, 0xBB, + 0xBC, 0xBD, 0xBD, 0xBE, 0xBE, 0xBF, 0xC0, 0xC0, + 0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC4, 0xC5, 0xC5, + 0xC6, 0xC7, 0xC7, 0xC8, 0xC8, 0xC9, 0xCA, 0xCA, + 0xCB, 0xCB, 0xCC, 0xCD, 0xCD, 0xCE, 0xCE, 0xCF, + 0xD0, 0xD0, 0xD1, 0xD1, 0xD2, 0xD2, 0xD3, 0xD4, + 0xD4, 0xD5, 0xD5, 0xD6, 0xD6, 0xD7, 0xD7, 0xD8, + 0xD8, 0xD9, 0xDA, 0xDA, 0xDB, 0xDB, 0xDC, 0xDC, + 0xDD, 0xDD, 0xDE, 0xDE, 0xDF, 0xDF, 0xE0, 0xE0, + 0xE1, 0xE2, 0xE2, 0xE3, 0xE3, 0xE4, 0xE4, 0xE5, + 0xE5, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xE8, 0xE9, + 0xE9, 0xEA, 0xEA, 0xEB, 0xEB, 0xEC, 0xEC, 0xED, + 0xED, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0, 0xF0, + 0xF1, 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, + 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF7, 0xF7, 0xF8, + 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, + 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, +}; + +/* + * Equations 5.32 and 5.30 from “Display Encoding”, Real-Time Rendering 4th ed. § 5.6 + */ +//static double +//_srgb2linear(double c) +//{ +// if(c > 0.04045) +// return pow((c + 0.055)/1.055, 2.4); +// return c/12.92; +//} +// +//static double +//_linear2srgb(double c) +//{ +// if(c > 0.0031308) +// return 1.055*pow(c, 1.0/2.4) - 0.055; +// return 12.92*c; +//} + +static double +_srgb2linear(double c) +{ + c = fclamp(c, 0, 1); + return srgb2lineartab[(int)(c*255)]/255.0; +} + +static double +_linear2srgb(double c) +{ + c = fclamp(c, 0, 1); + return linear2srgbtab[(int)(c*255)]/255.0; +} + +Color +srgb2linear(Color c) +{ + c.r = _srgb2linear(c.r); + c.g = _srgb2linear(c.g); + c.b = _srgb2linear(c.b); + return c; +} + +Color +linear2srgb(Color c) +{ + c.r = _linear2srgb(c.r); + c.g = _linear2srgb(c.g); + c.b = _linear2srgb(c.b); + return c; +} -- cgit v1.2.3