summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2024-07-04 14:57:00 +0000
committerrodri <rgl@antares-labs.eu>2024-07-04 14:57:00 +0000
commit6d8fbc2953c6ae29ee5162ca04920d6cef85d0ce (patch)
tree17876fc78176c7877130766ac4b1fcb126062f5a
parent32219aaa35b07d6abceb7df9f802c9758b53eb72 (diff)
downloadlibgraphics-6d8fbc2953c6ae29ee5162ca04920d6cef85d0ce.tar.gz
libgraphics-6d8fbc2953c6ae29ee5162ca04920d6cef85d0ce.tar.bz2
libgraphics-6d8fbc2953c6ae29ee5162ca04920d6cef85d0ce.zip
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.
-rw-r--r--color.c138
-rw-r--r--graphics.h4
-rw-r--r--mkfile1
-rw-r--r--render.c4
-rw-r--r--texture.c18
5 files changed, 150 insertions, 15 deletions
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 <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <geometry.h>
+#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;
+}
diff --git a/graphics.h b/graphics.h
index 7b46ed7..335b4b0 100644
--- a/graphics.h
+++ b/graphics.h
@@ -339,6 +339,10 @@ Point2 modulapt2(Point2, Point2);
Point3 modulapt3(Point3, Point3);
Memimage *rgb(ulong);
+/* color */
+Color srgb2linear(Color);
+Color linear2srgb(Color);
+
/* shadeop */
double sign(double);
double step(double, double);
diff --git a/mkfile b/mkfile
index 16559b9..ffdd953 100644
--- a/mkfile
+++ b/mkfile
@@ -13,6 +13,7 @@ OFILES=\
alloc.$O\
fb.$O\
shadeop.$O\
+ color.$O\
util.$O\
nanosec.$O\
diff --git a/render.c b/render.c
index 7fb3ae5..563df69 100644
--- a/render.c
+++ b/render.c
@@ -41,9 +41,9 @@ pixel(Framebuf *fb, Point p, Color c)
ulong *dst;
dst = fb->cb;
- dc = ul2col(dst[Dx(fb->r)*p.y + p.x]);
+ dc = srgb2linear(ul2col(dst[Dx(fb->r)*p.y + p.x]));
c = lerp3(dc, c, c.a); /* SoverD */
- dst[Dx(fb->r)*p.y + p.x] = col2ul(c);
+ dst[Dx(fb->r)*p.y + p.x] = col2ul(linear2srgb(c));
}
static void
diff --git a/texture.c b/texture.c
index 158bcb6..d51076e 100644
--- a/texture.c
+++ b/texture.c
@@ -29,18 +29,6 @@ uv2tp(Point2 uv, Memimage *i)
}
static Color
-ul2col(ulong l)
-{
- Color c;
-
- c.a = (l & 0xff)/255.0;
- c.b = (l>>8 & 0xff)/255.0;
- c.g = (l>>16 & 0xff)/255.0;
- c.r = (l>>24 & 0xff)/255.0;
- return c;
-}
-
-static Color
cbuf2col(uchar b[4])
{
Color c;
@@ -72,7 +60,11 @@ _memreadcolor(Memimage *i, Point sp)
break;
}
- return cbuf2col(cbuf);
+ /* TODO
+ * not all textures require color space conversion. implement a better
+ * interface to let the user decide.
+ */
+ return srgb2linear(cbuf2col(cbuf));
}
/*