Ok, this demo of the concept is WAY overkill. But it demos most of the potential ways to use this. Has KITT, Spirals, SlowShifts, pulses, and more. I should enter this as my ‘art on the wall’ but I actually have better taste than this.
/*
Multiple Maps, multiple patterns - by ScruffyNerf beta v0.9
inspired by various code bits by zranger, Jeff Vyduna and Ben Hencke
Spiral Code Pattern by ChrisNZ
While single strips or 3d maps could be used, that's beyond this demo, but the principle is the same.
Requirements: Matrix with a 2D map
This allows you to split a matrix of any size into multiple sub maps, by formula (to carve the range up),
and can run different patterns on each. (You could even change patterns, over time, not implemented here)
Consolidate any code needed from beforerender() into a single function (because it's not index/map based),
but you can run entirely different render() codes for each pattern
Remapping x/y values can either be renormalized (the new map is now 0..1)
OR retain the partial map (so perhaps x=0.5->1,y=0.5->1)
*/
// These are the map functions it will consider.
// Order matters, it will consider only the FIRST return of true
// This allows overlapping maps, with the first (0) being "on top",
// and potentially this also allows a background/default map (matching none of the submaps listed)
// these functions take index,x,y and modify a set of globals
// isInMap is set to true, if the pixel is in this submap
// NewIndex is the "new" index value, if any
// NewPixelCount is the pixelcount of the newmap, if any
// NewX is the new value of x for that pixel, might be renormalized, might not, still in range of 0..1
// NewY is the new value of y for that pixel, might be renormalized, might not, still in range of 0..1
var isInMap = false;
var NewIndex = 0;
var NewPixelCount = 0;
var NewX = 0;
var NewY = 0;
var matched = false;
var centerx;
var centery;
var totalMaps = 5 // maximum number of maps
var mapCount = 5 // active number of maps
var maps = array(totalMaps)
maps[0] = inmap0
maps[1] = inmap1
maps[2] = inmap2
maps[3] = inmap3
maps[4] = inmap4
var patternCount = 5 // total number of patterns
var patterns = array(patternCount)
patterns[0] = blinkWRGB
patterns[1] = pulseBlue
patterns[2] = pulseGreen
patterns[3] = spirals
patterns[4] = slowcolorshift
export var tBlink // used for pattern timing
export var tRotate // used for pattern timing
function inmap0(index, x, y) {
centerx = x - 0.5;
centery = y - 0.5;
if (centerx * centerx + centery * centery < 0.02) { // is this in the very center 'circle'?
isInMap = true;
NewX = centerx;
NewY = centery;
}
}
function inmap1(index, x, y) {
if (x + y > .25 && x - y > .25 && atan2(y, x) < tBlink * 1.8) {
// Left corner, slowly growing outward...
isInMap = true;
}
}
function inmap2(index, x, y) {
centerx = x - 0.5;
centery = y - 0.5;
if (centerx * centerx + centery * centery < 0.075 && ((PI + atan2(centerx, centery)) / PI2 > tRotate)) {
// is this in the bigger center circle, as we count down? This makes it into a disappearing band
isInMap = true;
NewX = centerx;
NewY = centery;
}
}
function inmap3(index, x, y) {
if (x > .6) {
if (y > .6) { // this should match the lower right corner... for a spiral
isInMap = true;
NewX = renormalize(x, .6, 1)
NewY = renormalize(y, .6, 1)
}
}
}
function inmap4(index, x, y) {
if (x < .14) { // is this in the very top few lines?, but let's remove the topmost line...
if (x > .03) {
isInMap = true;
NewPixelCount = 16;
NewIndex = index - 16;
}
}
}
function blinkWRGB() {
step = floor(16 * tBlink) // 0123456789.....16
h = floor(step % 8 / 2) / 3 // RRGGBBrrRRGGBBrr
v = step < 6 || step < 13 && (step - 7) % 2 == 1 // 1111110010101000
hsv(h, step > 6, v) // WWWWWW__R_G_B___
}
function pulseBlue() {
hsv(.6, 1, wave(tBlink * 1.5))
}
function pulseGreen() {
hsv(.3, 1, wave(tBlink))
}
// spiral controls
export var twistSpeed = .002
export var rotateSpeed = .001
var startingColor = .5
var colorSpeed = .1
var twist, rotation, colorShift, arms
// How quickly the spiral should rotate back and forth
export function sliderTwistSpeed(v) {
twistSpeed = v = 0 ? 0 : .015 / v
}
// How quickly the entire pattern should rotate
export function sliderRotationSpeed(v) {
rotateSpeed = v = 0 ? 0 : .005 / v
}
// How many arms of symmetry the pattern should have (1-3)
export function sliderArms(v) {
arms = 1 + floor(v * 2.999)
}
function spirals(index, x0, y0) {
twist = wave(time(twistSpeed)) * 2 - 1
rotation = time(rotateSpeed)
colorShift = time(colorSpeed)
x = (NewX - .5) * 2
y = (NewY - .5) * 2
dist = sqrt(x * x + y * y)
angle = (atan2(y, x) + PI) / PI / 2
angle += dist * twist / 2
h = angle * arms - rotation + 10
h = h - floor(h)
v = (1.07 - dist) * (h < .5 ? h * h * h : h)
h = (h + startingColor) / 2 + colorShift
hsv(h, 1, v)
}
/*
Slow color shift pattern
*/
function slowcolorshift() {
t1 = time(.15) * PI2
t2 = time(.1)
h = (t2 + 1 + sin(NewIndex / 2 + 5 * sin(t1)) / 5) + NewIndex / (NewPixelCount * 4)
v = wave((NewIndex / 2 + 5 * sin(t1)) / PI2)
v = v * v * v * v
hsv(h, 1, v)
}
function kitt() {
tailPct = .6
speed = .05
pct1 = NewY / 2 - time(speed)
pct2 = -NewY / 2 - time(speed)
v = max(0, (tailPct - 1 + triangle(pct1) * square(pct1, .5)) / tailPct) +
max(0, (tailPct - 1 + triangle(pct2) * square(pct2, .5)) / tailPct)
hsv(0, 1, v * v * v)
}
function renormalize(value, rangestart, rangeend) {
return ((value - rangestart) / (rangeend - rangestart))
}
export function beforeRender(delta) {
tBlink = time(twistSpeed)
tRotate = time(rotateSpeed)
}
export function render2D(index, x, y) {
matched = false;
NewIndex = index;
NewPixelCount = pixelCount;
for (var p = 0; p < mapCount; p++) {
isInMap = false;
maps[p](index, x, y);
if (isInMap) {
patterns[p]();
matched = true;
p = mapCount;
}
}
if (matched == false) {
NewY = y;
kitt();
}
}
export function render(index) {
render2D(index, index / pixelCount, 0)
}
Running on a 16x16 panel, I’m getting 33FPS, not bad for running 6 different patterns, overlapping some…
I stripped out a few Spiral controls, and borrowed 2 of the 3 sliders left to use for timing on other patterns.
Note the spiral is overlapped by the green and blue, but not the red KITT, it’s also renormalized, and thinks it’s running on a smaller area… Blue and Green show other patterns underneath if they aren’t lit, and Green is behind Blue.
it’s hella noisy, but it’s a good demo of the ability to run multiple patterns AND multiple maps, with very little rewriting of the originals. I did use globals to make code cleaner, and not be passing X and Ys all over, so most of the code rewriting was for that. (I used the fancy new arrayless KITT too)