Skip to content

Instantly share code, notes, and snippets.

@louisswarren
Last active December 30, 2022 08:00
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save louisswarren/f576ccfa74a570732c2d3ed490adb263 to your computer and use it in GitHub Desktop.
Generate all hues in the colour spectrum
/*
* 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