This is for the 3-axis accelerometer on my sword, which was destroyed the first time someone swung it with any force.
code
export var accelerometer
export var x = 0
export var y = 0
export var z = 0
export var total
// configuration
var max_total = 20 // maximum total value to prevent overload
var streak_count = 20 // streak count
// tuning
var scale_acceleration = 50.0 // acceleration scale to ~ [-1,1]
var scale_speed = 50.0 // speed scale to ~10x
var scale_brightness = 8.0 // scale rgb by 1/scale_brightness before summing
// streak state storage
var s_age = array(streak_count)
var s_hue = array(streak_count)
var s_spd = array(streak_count)
var s_len = array(streak_count)
var hPc = pixelCount/2 // half pixelCount
// output framebuffer
var fb_Red = array(hPc)
var fb_Green = array(hPc)
var fb_Blue = array(hPc)
// export var angle = 0
// export var max_spd = 0
var r, g, b // filled by HSVtoRGB
function HSVtoRGB(h, s, v) {
var i, f, p, q, t;
i = floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
im6 = i % 6
if (im6 == 0) {
r = v; g = t; b = p;
} else { if (im6 == 1) {
r = q; g = v; b = p;
} else { if (im6 == 2) {
r = p; g = v; b = t;
} else { if (im6 == 3) {
r = p; g = q; b = v;
} else { if (im6 == 4) {
r = t; g = p; b = v;
} else {if (im6 == 5) {
r = v; g = p; b = q;
}}}}}}
}
export function beforeRender(delta) {
// current acceleration, with a 1-sample smoothing window
var nx = clamp((x + (accelerometer[2]*scale_acceleration))/2.0,-1,1)
var ny = clamp((y + (accelerometer[0]*scale_acceleration))/2.0,-1,1)
var nz = clamp((z + (accelerometer[1]*scale_acceleration))/2.0,-1,1)
// angle = acos(((x*nx)+(y*ny)+(z*nz))/(sqrt(x*x+y*y+z*z)*sqrt(nx*nx+ny*ny+nz*nz)))
// clear framebuffer
for (n = 0; n < hPc; n++) {
fb_Red[n] = 0
fb_Green[n] = 0
fb_Blue[n] = 0
}
// create a new streak if change in acceleration is low
if (abs(sqrt(x*x+y*y+z*z) - sqrt(nx*nx+ny*ny+nz*nz)) < 0.125) {
s_new = 1
}
// render streaks
for (n = 0; n < streak_count; n++) {
// if we are creating a new streak, and this slot is empty, fill it
if (s_new && s_age[n] == 0) {
s_age[n] = 1/32767
s_hue[n] = random(1) // or angle/PI // or (abs(nx-ny))
s_spd[n] = scale_speed * sqrt(abs(nz * nx * ny) * (2 + random(4)))
s_len[n] = max(15 - s_spd[n] + random(3), 3)
// max_spd = max(max_spd, s_spd[n])
s_new = 0
}
if (s_age[n] > 0) {
len = s_len[n]
pix = s_spd[n] / scale_speed * s_age[n] / 6
if ((pix-len) >= hPc) {
s_age[n] = 0
if (s_new) { n-- } // render this streak
} else {
s_age[n] += delta
hue = s_hue[n]
remaining = len
for (pn = ceil(pix); remaining > 0 && pn >= 0; remaining--) {
if (pn < hPc) {
fade = remaining/len
HSVtoRGB(hue, sqrt(clamp(1.5 - fade,0,1)), pow(clamp((1-pn/hPc) * fade * fade,0,1),1.5) )
fb_Red[pn] += r/scale_brightness
fb_Green[pn] += g/scale_brightness
fb_Blue[pn] += b/scale_brightness
}
pn--
}
}
}
}
// Calculate the sum of all pixels in the framebuffer ...
total = 0
for (n = 0; n < hPc; n++) {
fb_Red[n] = min(1,fb_Red[n])
fb_Green[n] = min(1,fb_Green[n])
fb_Blue[n] = min(1,fb_Blue[n])
total += fb_Red[n] + fb_Green[n] + fb_Blue[n]
}
// ... and scale them all down if necessary!
if (total > max_total) {
adjust = max_total / total
for (n = 0; n < hPc; n++) {
fb_Red[n] *= adjust
fb_Green[n] *= adjust
fb_Blue[n] *= adjust
}
}
// Store current values for smoothing on next frame
x = nx
y = ny
z = nz
}
export function render(index) {
// The PB is at one end of the strip, and the strip is folded in half
// Use \"^hPc - [...]\"\" instead of \"[...] - 1$\" if PB is at the other end
pindex = ( (index < hPc) ? (hPc - index) : (index - hPc + 1) ) - 1
rgb(fb_Red[pindex], fb_Green[pindex], fb_Blue[pindex])
}