Last active
December 30, 2022 08:00
-
-
Save louisswarren/f576ccfa74a570732c2d3ed490adb263 to your computer and use it in GitHub Desktop.
Generate all hues in the colour spectrum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Idea: We want to cycle through all hues, with maximum saturation and value, | |
* using RGB. This gives 1530 = 3! * (256 - 3!) colours: | |
000-0fe: ff 00-fe 00 | |
0ff-1fd: ff-01 ff 00 | |
1fe-2fc: 00 ff 00-fe | |
2fd-3fb: 00 ff-01 ff | |
3fc-4fa: 00-fe 00 ff | |
4fb-5f9: ff 00 ff-01 | |
* We will implement this a few ways, just for fun. | |
*/ | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <assert.h> | |
unsigned long | |
colour(unsigned int s) | |
{ | |
unsigned int t = s % 1530; | |
if (t < 0x0ff) return 0xff0000 + ((t - 0x000) << 8); | |
if (t < 0x1fe) return 0xffff00 - ((t - 0x0ff) << 16); | |
if (t < 0x2fd) return 0x00ff00 + ((t - 0x1fe) << 0); | |
if (t < 0x3fc) return 0x00ffff - ((t - 0x2fd) << 8); | |
if (t < 0x4fb) return 0x0000ff + ((t - 0x3fc) << 16); | |
if (t < 0x5fa) return 0xff00ff - ((t - 0x4fb) << 0); | |
return 0; | |
} | |
/* This is actually easier to do from memory */ | |
unsigned long | |
colour_branchless(unsigned int s) | |
{ | |
const unsigned long bases[] = { | |
0xff0000, 0xffff00, 0x00ff00, 0x00ffff, 0x0000ff, 0xff00ff | |
}; | |
const long shifts[] = { | |
0x000100, -0x010000, 0x000001, -0x000100, 0x010000, -0x000001 | |
}; | |
int t = s % 1530; | |
int section = t / 255; | |
int mul = t % 255; | |
return bases[section] + mul * shifts[section]; | |
} | |
#define RED(c) (((c) >> 16) & 0xff) | |
#define GRN(c) (((c) >> 8) & 0xff) | |
#define BLU(c) (((c) >> 0) & 0xff) | |
/* It's nice to be able to just cycle through colours */ | |
unsigned long | |
next_colour1(unsigned long c) | |
{ | |
unsigned long s = 0; | |
// Allow passing 0 to get the start of the cycle | |
c |= !c * 0xff0001; | |
s += ((RED(c) == 0xff) & (GRN(c) != 0xff) & (BLU(c) == 0x00)) * 0x000100; | |
s -= ((RED(c) != 0x00) & (GRN(c) == 0xff) & (BLU(c) == 0x00)) * 0x010000; | |
s += ((RED(c) == 0x00) & (GRN(c) == 0xff) & (BLU(c) != 0xff)) * 0x000001; | |
s -= ((RED(c) == 0x00) & (GRN(c) != 0x00) & (BLU(c) == 0xff)) * 0x000100; | |
s += ((RED(c) != 0xff) & (GRN(c) == 0x00) & (BLU(c) == 0xff)) * 0x010000; | |
s -= ((RED(c) == 0xff) & (GRN(c) == 0x00) & (BLU(c) != 0x00)) * 0x000001; | |
return c + s; | |
} | |
unsigned long | |
next_colour2(unsigned long c) | |
{ | |
/* | |
+0x000100, // r = 2, g < 2, b = 0 | |
-0x010000, // r > 0, g = 2, b = 0 | |
+0x000001, // r = 0, g = 2, b < 2 | |
-0x000100, // r = 0, g > 0, b = 2 | |
+0x010000, // r < 2, g = 0, b = 2 | |
-0x000001, // r = 2, g = 0, b > 0 | |
*/ | |
const long shifts[] = { | |
0, // 000 | |
0, // 001 | |
+0x010000, // rgb = 002 | |
0, // 010 | |
0, // 011 | |
-0x000100, // rgb = 012 | |
+0x000001, // rgb = 020 | |
+0x000001, // rgb = 021 | |
-0x000100, // rgb = 022 | |
0, // 100 | |
0, // 101 | |
+0x010000, // rgb = 102 | |
0, // 110 | |
0, // 111 | |
0, // 112 | |
-0x010000, // rgb = 120 | |
0, // 121 | |
0, // 122 | |
+0x000100, // rgb = 200 | |
-0x000001, // rgb = 201 | |
-0x000001, // rgb = 202 | |
+0x000100, // rgb = 210 | |
0, // 211 | |
0, // 212 | |
-0x010000, // rgb = 220 | |
0, // 221 | |
0, // 222 | |
}; | |
c |= !c * 0xff0001; | |
int idx = 9 * (!!RED(c) + !(~RED(c) & 0xff)) | |
+ 3 * (!!GRN(c) + !(~GRN(c) & 0xff)) | |
+ 1 * (!!BLU(c) + !(~BLU(c) & 0xff)); | |
assert(shifts[idx]); | |
return c + shifts[idx]; | |
} | |
#undef RED | |
#undef GRN | |
#undef BLU | |
int | |
main(void) | |
{ | |
unsigned long c = 0; | |
for (int i = 0; i < 1531; ++i) { | |
printf("%06lx\n", colour(i)); | |
assert(colour_branchless(i) == colour(i)); | |
assert(next_colour1(c) == colour(i)); | |
assert(next_colour2(c) == colour(i)); | |
c = colour(i); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment