From seeing a few of your posts, I think you’re at the level you can definitely understand and use 2D arrays. For a recent example of their syntax, see this post.
I think I can imagine a scenario where you’re right, where it’s best to use supersampling, perhaps when trying to composite multiple sprites that were computationally expensive to compute the first time. However, I think it’s worth starting with knowing what your ultimate goal is in concrete terms for a particular pattern; supersampling might not be worth the complexity (or FPS) if there’s a different way.
Perhaps the most helpful thing I can do is go through your code and comment some things I found counterintuitive.
// ▼ Array Size Things ▼
xmax = 8 // If this is to imply an 8-LED-wide matrix, based on the 0-indexed math use below, consider 7 instead.
ymax = 8 // ditto
ss = 8 //number of samples
arrayLen = (xmax*ss)*(ymax*ss) //total size of ssarray = 4096, ok. 64 each dimension, rendered down to 8 per dimension.
hueArray = array(arrayLen)
valArray = array(arrayLen)
// ▼ SS Array Rendering Things ▼
speed = 0.1 //grids per second -> Is this supposed to mean rows or columns per second? Pixels in the large array per second? .1 "anything" per secont implies we want it to take 10 seconds to do one of a thing.
lastRendered = 15
// Currently unused - I see it in the commented out beforeRender and I see then intent, a bit.
// I could really benefit from a comment here explaining if the range for this and lastUsed is
// supposed to be in (0..ss), (0..ymax), (0..min), (0..arrayLen) etc.
lastUsed = 7
//this isn't currently used in the code below. I see it in the commented out beforeRender and that it was intended to help find the
// difference / distance between which have been rendered vs which have been used.
min = ymax*ss // So, the number of samples available to sample from for any column. Unsure why this is named min. min = 64
export var delt
export function beforeRender(delta){
delt = delta // Currently unused
t1 = time(0.015/speed)
// See comment above for defintiion of speed. .015 = 1/sec. If speed is
// ".1 grids per second", 1/.1 means t1 will loop 0->1 every 10 seconds.
rowTime = 1000/(arrayLen/ymax) //how often a row should be rendered in ms
// I thought there were 8 rendered rows in the real matrix, and 8 rows to sample from per real row
// so I'm expecting either 1000 ms divided by 8 or 64
// Instead, this is 1000ms divided by (4096/8) - IE.. 512 something, IE ~2ms... seems too fast.
colTime = 1000/(arrayLen/xmax)
if(delta > rowTime){
// From above, rowTime is about 2ms, yet delta is commonly 1-20ms on Pixelblaze3
// and on my PBv3 with 64 APA102 pixels in an 8x8 matrix, I'm getting 470FPS and delta's
// almost always 2.05 ms. So.. This loop is basically always running, but wouldn't run
// if delta somehow experienced a very quick cycle under 1.94ms.
for(i=0; i<min; i++){ //I have no idea where +9 comes from
// i from 0 to 63 based on min above...
xss = i % ymax*ss // xss from 0 to 63 still.. Maybe a mistake.
yss = i % xmax*ss
hueArray[i] = 1/xss + t1
// note the divide by zero problem here. xss can be zero.
// Ignoring that, hue value can range from 0 to (1/1 + 1) IE we wrap the hue wheel twice. 0..2
valArray[i] = 1
}
}
}
// Note from Jeff: I'm ignoring this commented beforeRender for now.
// export function beforeRender(delta) {
// t1 = time(0.1)
// diff = abs(lastRendered - lastUsed) //distance between lastRendered and lastUsed.
// if(diff < min || diff > arrayLen-min){ //check if lastUsed is too close or too far from lastRendered
// nextPix = lastRendered + 1 % arrayLen
// for(i = nextPix; i <= nextPix+2*min; i++){
// x = i % ymax*ss
// y = i % xmax*ss
// hueArray[i] = t1
// valArray[i] = 0
// lastRendered = i
// }
// }
// }
export function render2D(index, x, y) {
lastUsed = t1*min*speed
// Original comment: //min gives us the width of the ss array, speed is how many we need per second, and t1 loops every second.
// Jeff's notes: Other than setting this here, lastUsed isn't... used.
// t1 is currently configured to go 0->1 every 10 seconds.
// min is the number of rows in the big array; since speed is .1, this saw
// wave goes from 0 to "10% of the number of rows to sample from" every 10 seconds
// so I'm a little confused about what the eventual purpose of this is.
// Let's also note that this doesn't depend on index, x, or y, so whatever the
// design intent is, we are recalculating it a LOT - once for every single pixel,
// every single frame (since it's here in render()). Even if it's correct as written,
// It's definitely more effecient to do this in beforeRender() once per frame.
x2 = round(x*ss) //finding the x-coordinate of the nearest ss pixel
y2 = round(y*ss) //finding the y-coordinate of the nearest ss pixel
// Jeff: OK... an integer between 0 and ss (8) based on x (0..1) from the map.
// I can't help wonder if what is was intended here is that x2 should
// go from 0 to the width (number of columns, so xmax, not ss)
// But it happens to be close since they're both 8 for now.
// Even further, I wonder if the intent was more like:
// x2 = round(x*xmax*ss)
// IE, a decimal coordinate in 0..63 (64 samples each in x and y) to pluck from the
// big arrays, but then rounded so it's an integer for array indexing. Note
// I'd use floor() for this, because if they round() up to 64, hueArray[64*64] is out
// of bounds for a 4096-sized array.
h = hueArray[y2*ymax+x2]
// Jeff: OK - here I finally see the array layout scheme. Storing by rows, and
// 256 potential column entries in each row. However, hueArray has 8*8*8*8 = 4096
// entries; x2 and y2 can as-written, only be 0..8. So the largest index you can get
// from this in your 4096-element array is 8*8+8 = 72.
// I'm tempted to thing what's desired is:
// h = hueArray[y2*ymax]
s = 1
v = valArray[x2*xmax+y2]
// Jeff: But here I get confused - x2 and y2 are transposed; why would the scheme for values
// be different than the scheme for hues?
hsv(h, s, v)
}