#include "colours.h" int c_round(double a) { return a - (int)a > 0.5 ? (int)a + 1 : (int)a; } struct colour get_random_color(void) { int red = rand() % 255; int blue = rand() % 255; int green = rand() % 255; struct colour col; col.r = red; col.g = green; col.b = blue; col.a = 255; return col; } SDL_Colour get_sdlcolour(struct colour col, int alpha) { struct colour c = get_rgb(col); return (SDL_Color){c.r, c.g, c.b, alpha}; } double m_min(double arr[], int len) { double largest = arr[0]; for (int i = 0; i < len; i ++) { if (arr[i] < largest) { largest = arr[i]; } } return largest; } double m_max(double arr[], int len) { double largest = arr[0]; for (int i = 0; i < len; i ++) { if (arr[i] > largest) { largest = arr[i]; } } return largest; } bool m_equal(double a, double b) { return (a - b) * (a - b) < 0.00001; } // https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB // h = [0,360], s = [0,1], v = [0,1] // if s == 0, then h = -1 (undefined) struct colour get_hs_l_v(struct colour c, enum colour_space sp) { struct colour ret = {}; double r = (double)c.r / 255; double g = (double)c.g / 255; double b = (double)c.b / 255; double arr[] = {r, g, b}; double max = m_max(arr, 3); double min = m_min(arr, 3); ret.v = max; double chroma = max - min; double lum = (max + min) / 2; ret.l = lum; if (m_equal(chroma, 0)) { ret.h = 0; } else if (m_equal(ret.v,r)) { ret.h = (g - b) / chroma; } else if (m_equal(max,g)) { ret.h = 2 + (b - r) / chroma; } else if (m_equal(max,b)) { ret.h = 4 + (r - g) / chroma; } else { printf("NOPE BAD ERROR\n"); } ret.h *= 60; ret.h = fmod(ret.h, 360); if (ret.h < 0) { ret.h += 360; } if (sp == CS_HSV) { if (m_equal(max,0)) { ret.s = 0; } else { ret.s = chroma / max; } } else { double arr[] = {ret.l, 1 - ret.l}; if (m_equal(0, lum) || m_equal(1, lum)) { ret.s = 0; } else { ret.s = (ret.v - ret.l) / m_min(arr, 2); } } ret.sp = CS_HSL; return ret; } struct colour get_hsl(struct colour c) { return get_hs_l_v(c, CS_HSL); } struct colour get_hsv(struct colour c) { return get_hs_l_v(c, CS_HSV); } double magic_hsv_function(int n, struct colour c) { double res = 0; double k = fmod(n + (c.h / 60), 6); double arr[] = {k, 4 - k, 1}; double k_b = m_min(arr, 3); double k_c = 0 > k_b ? 0 : k_b; res = c.v - c.v * c.s * k_c; return res; } struct colour get_rgb_from_hsv(struct colour c) { double r = magic_hsv_function(5, c); double g = magic_hsv_function(3, c); double b = magic_hsv_function(1, c); struct colour res; res.r = c_round(r * 255); res.g = c_round(g * 255); res.b = c_round(b * 255); return res; } double magic_hsl_function(int n, struct colour c) { double a = c.s * ( c.l < (1-c.l) ? c.l : 1 - c.l ); double k = fmod(n + c.h / 30, 12); double b[] = {k - 3, 9 -k, 1}; double d[] = {-1, m_min(b, 3)}; return c.l - a * (d[0] > d[1] ? d[0] : d[1]); } struct colour get_rgb_from_hsl(struct colour c) { double r = magic_hsl_function(0, c); double g = magic_hsl_function(8, c); double b = magic_hsl_function(4, c); struct colour res; res.r = c_round(r * 255); res.g = c_round(g * 255); res.b = c_round(b * 255); return res; } struct colour get_rgb(struct colour c) { if (c.sp & CS_RGB){ return c; } if (c.sp & CS_HSL) { return get_rgb_from_hsl(c); } if (c.sp & CS_HSV) { return get_rgb_from_hsv(c); } return c; } int compare_perceived_lum(const void* c1, const void* c2) { struct colour rgb_c1 = *(struct colour*)c1; struct colour rgb_c2 = *(struct colour*)c2; double lum1 = 0.299*rgb_c1.r + 0.587*rgb_c1.g + 0.114*rgb_c1.b; double lum2 = 0.299*rgb_c2.r + 0.587*rgb_c2.g + 0.114*rgb_c2.b; return lum1 - lum2; } struct colour *get_adjacent(struct colour base, int deg, int num) { struct colour col = get_hsl(base); num += 1; struct colour* colours = alloca(sizeof(struct colour) * num); for (int i = 0; i < num; i++) { int m = (i % 2 == 0) ? -i : i; colours[i] = col; colours[i].h += m * deg; colours[i].h += fmod(colours[i].h, 360); } struct colour *ret_colours = calloc(num, sizeof(struct colour) * num); for (int i = 0; i < num; i++) { ret_colours[i] = get_rgb(colours[i]); } // sort from dark to bright qsort(ret_colours, num, sizeof(struct colour), compare_perceived_lum); return ret_colours; } void print_colour(struct colour c) { char *colour = calloc(20, sizeof(char)); sprintf(colour, "#%02x%02x%02x (%d)", c.r, c.g, c.b, c.a); printf("\x1b[38;2;%d;%d;%dm%s\x1b[0m\n", c.r, c.g, c.b, colour); free(colour); } void test(int seed) { struct colour c = get_random_color(); struct colour *adj = get_adjacent(c, 5, 4); for (int i = 0; i < 5; i++) { print_colour(adj[i]); } free(adj); printf("\n"); } void test_print_wheel() { struct colour c; c.s = 0.999; c.v = 0.99; c.l = 0.5; c.sp = CS_HSV; for(int i = 0; i < 360; i+=5) { c.h = (double)i; struct colour rgb = get_rgb(c); print_colour(rgb); } }