colour.c
#include <math.h>
#include "inc.h"
lil_ColourLab lil_rgb2Lab(lil_Colour col){
lil_Number rgb[3];
for(int i = 0; i < 3; i++){
lil_Number val = (lil_Number)col.arr[i] / 255.0;
if(val > 0.04045)
val = pow((val + 0.055) / 1.055, 2.4);
else
val = val / 12.92;
rgb[i] = val * 100.;
}
lil_Number xyz[3];
lil_Number x = rgb[0] * 0.4124 + rgb[1] * 0.3576 + rgb[2] * 0.1805;
lil_Number y = rgb[0] * 0.2126 + rgb[1] * 0.7152 + rgb[2] * 0.0722;
lil_Number z = rgb[0] * 0.0193 + rgb[1] * 0.1192 + rgb[2] * 0.9505;
xyz[0] = x / 95.047;
xyz[1] = y / 100.0;
xyz[2] = z / 108.883;
for(int i = 0; i < 3; i++){
lil_Number val = xyz[i];
if(val > 0.008856)
val = pow(val, 1./3.);
else
val = (7.787 * val) + (16. / 116.);
xyz[i] = val;
}
lil_ColourLab Lab = {
.L = ((116. * xyz[1]) - 16.) ,
.a = (500. * (xyz[0] - xyz[1])),
.b = (200. * (xyz[1] - xyz[2]))
};
return Lab;
}
lil_ColourHsv lil_rgb2hsv(lil_Colour col){
lil_ColourHsv hsv;
lil_Number r = col.r / (lil_Number)0xff;
lil_Number g = col.g / (lil_Number)0xff;
lil_Number b = col.b / (lil_Number)0xff;
lil_Number cmax = max(max(r, g), b);
lil_Number cmin = min(min(r, g), b);
lil_Number diff = cmax - cmin;
if(cmax == cmin) {
hsv.h = 0;
} else if(cmax == r){
hsv.h = fmod(60 * ((g - b) / diff) + 360, 360);
} else if(cmax == g){
hsv.h = fmod(60 * ((b - r) / diff) + 120, 360);
} else if(cmax == b){
hsv.h = fmod(60 * ((r - g) / diff) + 240, 360);
}
if(cmax == 0)
hsv.s = 0;
else
hsv.s = (diff / cmax) * 100;
hsv.v = cmax * 100;
return hsv;
}
lil_Colour lil_hsv2rgb(lil_ColourHsv hsv){
assert(hsv.h <= 360 && hsv.h >= 0);
assert(hsv.s <= 100 && hsv.s >= 0);
assert(hsv.v <= 100 && hsv.v >= 0);
hsv.s /= 100;
hsv.v /= 100;
if(hsv.h == 360) hsv.h = 0;
else hsv.h = hsv.h / 60;
int i = hsv.h;
lil_Number f, p, q, t;
f = hsv.h - i;
p = hsv.v * (1.0 - hsv.s);
q = hsv.v * (1.0 - (hsv.s * f));
t = hsv.v * (1.0 - (hsv.s * (1.0 - f)));
lil_Number r, g, b;
switch(i){
case 0:
r = hsv.v;
g = t;
b = p;
break;
case 1:
r = q;
g = hsv.v;
b = p;
break;
case 2:
r = p;
g = hsv.v;
b = t;
break;
case 3:
r = p;
g = q;
b = hsv.v;
break;
case 4:
r = t;
g = p;
b = hsv.v;
break;
default:
r = hsv.v;
g = p;
b = q;
break;
}
lil_Colour rgb;
rgb.a = 0xff;
rgb.r = r * 255;
rgb.g = g * 255;
rgb.b = b * 255;
return rgb;
}
#define ENTRY(id) static LUAFUNC(colour_ ## id)
ENTRY(parseColour){
lil_Colour col = lil_getColour(L, 1, NULL);
for(int i = 0; i < 4; i++)
lua_pushnumber(L, col.arr[i] / (lil_Number)0xff);
return 4;
}
ENTRY(rgb2hsv){
lil_Colour col = lil_getColour(L, 1, NULL);
lil_ColourHsv hsv = lil_rgb2hsv(col);
for(int i = 0; i < 3; i++)
lua_pushnumber(L, hsv.arr[i]);
lua_pushnumber(L, col.a);
return 4;
}
ENTRY(hsv2rgb){
lil_ColourHsv hsv;
for(int i = 0; i < 3; i++)
hsv.arr[i] = luaL_checknumber(L, i+1);
lil_Colour rgb = lil_hsv2rgb(hsv);
int st = lua_type(L, 4);
for(int i = 0; i < 3; i++)
lua_pushnumber(L, rgb.arr[i] / (lil_Number)0xff);
switch(st){
case LUA_TNONE:
break;
case LUA_TNUMBER:
lua_pushvalue(L, 4);
return 4;
default:
luaL_argerror(L, 4, "Not a number");
}
lua_pushnumber(L, 1);
return 4;
}
#undef ENTRY
#define ENTRY(id) { #id, LUAFUNCD(colour_ ## id) }
LUAREG(colourLib) = {
ENTRY(parseColour),
ENTRY(rgb2hsv),
ENTRY(hsv2rgb),
{ NULL, NULL }
};
#undef ENTRY