Well, I’d still prefer to let the user select one or two base colors with UI sliders, then generate the rest computationally as part of the pattern. But having said that, here’s a palette-stored-in-map proof of concept, just as something to think about.
The main simplifying assumption this makes is that because we’re theoretically running ported WLED patterns, we’re driving a 1D strip, as most stock WLED patterns do. That leaves the whole 3D map available to us as storage. To try this out, install the test mapper, and run the pattern. The test palette isn’t especially inspired, but it is um, quite visible!
Here’s the test mapper, with a 5 element RGB palette:
function (pixelCount) {
paletteSize = 5;
// construct palette here. First entry is palette size,
// repeated in x,y,z. The next entries are the
// palette RGB colors, followed by low and high
// sentinel values to control normalization.
var map = [
[5,5,5],
[216,0,0],
[0,131,84],
[238,75,106],
[0,59,200],
[15,113,115],
[-1,-1,-1],
[256,256,256]
]
// fill the rest of the map with zeros
for (i = paletteSize + 3; i < pixelCount; i++) {
map.push([0, 0, 0])
}
return map
}
And here’s the demo pattern:
// This is a sneaky way of storing a palette in 3D map data
// for use in 1D patterns
var MAX_PALETTE_LENGTH = 6;
var paletteLength = 0;
var paletteR = array(MAX_PALETTE_LENGTH);
var paletteG = array(MAX_PALETTE_LENGTH);
var paletteB = array(MAX_PALETTE_LENGTH);
var drawFrame = renderGetPalette;
var paletteRetrieved = 0;
// use this renderer on the first frame to retrieve the palette from the
// 3D map data
function renderGetPalette(index,x,y,z) {
// de-normalize palette data ((x * range) - low Value)
x = (x * 257)-1;
y = (y * 257)-1;
z = (z * 257)-1;
// palette length is duplicated in first x,y,z
// entries, so if these are all identical, it's a good
// bet we've got a palette instead of a "real" map.
if (index == 0) {
if ((x == y) && (y == z)) paletteLength = floor(x);
}
else if (index <= paletteLength) {
var n = index - 1;
paletteR[n] = floor(x + 0.5) / 255;
paletteG[n] = floor(y + 0.5) / 255;
paletteB[n] = floor(z + 0.5) / 255;
}
paletteRetrieved = 1;
}
// once the palette is retrieved, use this render to draw
// onto our 1D strip.
function renderRunPattern(index,x,y,z) {
render(index);
}
export function beforeRender(delta) {
if (paletteRetrieved) drawFrame = renderRunPattern;
}
export function render3D(index,x,y,z) {
drawFrame(index,x,y,z);
}
// proof-of-concept -- just divides strips into equal segments
// with a palette color in each segment!
export function render(index) {
var n = (index/pixelCount) * paletteLength;
rgb(paletteR[n],paletteG[n],paletteB[n]);
}