Pixelblaze V3.19 beta

,

I agree, .replace makes the most sense…
Yeah, it’s not ES6 but we don’t even have strings, so…

It’s a nice function, mostly for the multiple set option. For a singlet, you can just assign a new value, but for more than one value replacement, this is helpful. I’m sure we’ll figure out nifty uses.
The pseudo vector stuff for sure.

Yes, I hinted at literals coming a few comments ago… I’m most excited by that, lots of good bug fixes too. Happy to beta test, of course.

Ooh might be nice to have a “automatic zero”
form, like .write

Example:

var exampleArray = [1,2,3]
vs
var exampleArray = array(3)
exampleArray.write(1,2,3)

What’s the story on reusing arrays with literals?
Is that ok?

I’d assume the length is auto set with the literal,
So my example above would allow making a longer array and just populating the first 3 elements. (Now I’m mulling over a pseudo pop/push idea… That would allow all manner of stuff we can’t do now easily)

Actually I’ve been curious about how to best copy arrays too.

Added: and to complement write, might be nice to have a .read (that did have a start position, and length) to grab, say the 2nd,3rd,4th, in an array, and do something with them as a new array. But that’s a wishlist item, and optional, as I can see how to fake it…

Yeah, once created arrays are all the same regardless if they came from array call or a literal.

Behind the scenes it’s making an array and then calling this function to fill it up. I do it in chunks to avoid blowing up the stack, so you can have arbitrarily large literal arrays up to memory limits. The overhead is much much smaller than doing a bunch of arr[n] = ....

Push/pop/shift/unshift are on my list too.

2 Likes

rgbw using rgb() calls!! I’d help Beta test this as well.

Thank you all for the ideas! Leaning towards replace and replaceAt.

Also considered setElements and setElementsAt. Felt too verbose, too much camelCase (oh how far I’ve come from my days coding enterprise Java). C++ also has assign - but this also implies updating size, and emplace which inserts/adds. Thesaurususing a little I found pave which I find hilarious but would be perfect otherwise.

BTW - length comes from the array’s size, and literals size are pre-calculated during compile. The whole array is allocated at once, and then paved bit by bit as the expressions within the literal are resolved.

@Scruffynerf, you asked about copying arrays, this isn’t too bad with existing tools:

Array copy:

arrayMapTo(src, dest, v -> v)

Partial copy e.g. starting at index 12 in src for the size of dest:

dest.mutate((v, i) -> src[i+12])

(src must be at least 12 elements larger than dest in this example)

About .read that would be slice() (docs). Also in ES6 you can consume arrays using ES6’s spread syntax as arguments or in array literals.

Continued ramblings about JS follow…

Ideally PB code could be used in JS environments with a little bit of polyfill. Strings aren’t arrays even if you can access characters using square brackets, and arrays don’t have a replace function in JS/ES6. Strings are array-like enough that you can run many of Array’s prototype functions on them though. E.g. to convert a string to an array, you can call Array’s slice() on it, setting this to the string, as if it were a member method of the string:

Array.prototype.slice.apply("123") // gives [ '1', '2', '3' ]

(String has it’s own slice that returns strings)

Or if you are brave, dumb, or smart enough, you can install it into String’s prototype, which is one of the coolest and most dangerous JavaScripty things you can do.

"abc".slice(1) // gives "bc"
String.prototype.sliceAsArray = Array.prototype.slice
"abc".sliceAsArray(1) // gives [ 'b', 'c' ]

Thats all to say that it would be possible to polyfill replace for JS code that works on arrays and doesn’t break String’s replace.

3 Likes

Beta update files!

I haven’t had a chance to add the convenient replace just replaceAt, nor get the built in docs updated.

I recommend that you upload these using the /recovery.html tool, since you can get progress information. If you need to roll back, the regular online update will revert it back to 3.18.

3 Likes

So the process is download the file and put the PB into setup mode? Then http://192.168.4.1/recovery.html ?

You don’t need to put it into setup mode. The advantage of /recovery.html over /update (note: no .html) is that recovery.html has progress info (shows you bytes loading), vs the ‘blind’ update on /update

1 Like

I like array initializers! :+1:

The size difference for a pattern that defines and renders a static 16x16 bitmap defined in an array of packRGBA(r,g,b,a) tuples:

version blob epe js
v3.18 21147 21566 16609
v3.19b 13349 15316 11138

It could be even smaller if I could do away with packRGBA(r,g,b,a) and initialize the array with 32-bit hex literals, but a literal like 0xFDB97531 gets truncated by PBscript to a 16-bit value 0x7531 with no fractional component. I could do ary = [ 0xFDB9 + (0x7531 >> 16), ...] but that’s just as bad in terms of space and even worse in terms of readability. Extending the grammar of hex literals to allow 0xFDB9.7531 might be a workable kludge; otherwise parsing all hex literals as 32-bit integers might break existing code.

I’ve been working on a Pacman simulation but I kept running out of array space and at times crashing the editor; I’ll be interested to see if the code size reductions above and the checks for exceeding global limits will make enough of a difference to help me finish it.

1 Like

we’re on the same wavelength. Yes, a 0xFFFF.FFFF would be ideal, but in the meantime, you could do a function:

function p(a,b){
    return a + (b >>16)
}

so...
 ary = [ p(0xFDB9,0x7531), ...]

that was my thought in this comment

For slightly more readability with 4 256 values, you could do:

function p(a,b,c,d){
    return (a << 8) + b + (c >> 8) + (d >> 16)
}

so...
 ary = [ p(0,255,128,0), p(0x0,0xFF,0x80,0x0)...]

I think I got the bit shift math right there, but double check me. And the forum parser doesn’t seem to like it.

Yes, that’s how I encode images:

function packRGBA(r, g, b, a) { return (r << 8) + g + (b >> 8) + (a >> 16); }

image = array(256); // allocate row storage
image = [ packRGBA(0xdf,0xbc,0x5b,0x00),packRGBA(0xe1,0xc2,0x6c,0x00),... ]

You’re right that the palette indices could be stored the same way…

1 Like

Literals are limited in range to 16.15 (31 bits). The least significant bit is used as a flag for instructions. Variables and math all work with the full 32 bits, so an expression can create the full 32 bit word, such as your packRGBA function.

As a compromise, you could represent data in your code as a real number instead of hex to get the full 31-bit range for a single literal. For example your 0xFDB97531 divided by 65536 becomes ~64953.457778 (6 decimal places is probably plenty), but once encoded would end up being 0xFDB9.7530 (dropping the least significant bit). Humans are least perceptive of red contrast, so you could re-order it so that red was in the least significant byte without losing noticeable perceptual range.

A 31-bit literal is 1 word, the full 32-bit p(0xFDB9,0x7531) expression takes 3 words, and packRGBA(0xdf,0xbc,0x5b,0x00) uese 5 words.

By the way, when using array literals you don’t want to pre-allocate an array, the array literal does that for you. Doing it twice orphans the first array making it unusable but still retaining memory.

Change this code:

image = array(256); // allocate row storage
image = [ packRGBA(0xdf,0xbc,0x5b,0x00),packRGBA(0xe1,0xc2,0x6c,0x00),... ]

to just this:

image = [ packRGBA(0xdf,0xbc,0x5b,0x00),packRGBA(0xe1,0xc2,0x6c,0x00),... ]
1 Like

Just a heads up, I’ve tried to put 3.19b through the paces and added stuff to the unit test suite - looks solid!

I see you figured out sensible behaviors for the cases we talked about, and you can watch it run out of memory as your hint that you’re using defined literals in a loop.

2 Likes

Thanks, I figured that out eventually.

So, v3.19 beta participants, how did it go for you?

  • Great! No problems!
  • Had a problem (please post details!)
  • Haven’t tried it enough to say
  • Stuck trying to figure out how to update

0 voters

PB v3 standard - the 3.19 beta fixed the app connect/startup redirect hang to pbWiFIsetup.html

1 Like

The multi-matrix example is very cool.

Feature idea: have a parm to reverse the XY loop then it could be used with panels that use a different wiring on the X and Y. cant just rotate then its mirrored backwards. What i ended up with for now is to create a ‘panel2’ function with the inner and outer loops reversed.

At first i thought that multi-map reference meant ability to bind a map to a pattern. As someone said I’d have to find the post to recall who – said it best: “sometimes i want a 2d map sometimes i want a 3d map” this is what i miss the most. So much – I’m defining multiple maps and select between them via variables/defines at the top of the mapping tab as a workaround.

Feature idea: Ability to save a custom map as a default. If i build a nice custom map. I know i can save it but if the “end user” finds the map tab, loads a map , then POOF that custom map is gone and i get a call. The low tech solution i use is to provide a document file of the configurations for any given project and put the map code in the doc file to recover from.
This would be better if there was at least one ‘custom’ Map slot to store a map and reload it from flash.

If you combine both of those it be useful to be able to have maps stored and a specific map can can be bound to a pattern via the playlist. Maybe a ring maybe a matrix maybe a 3d matrix so while 1 ‘custom’ map slot would be ok, all of the defaults should be “callable” with at least 2 custom map slots being idea.

2 Likes

I sympathize… Having built a tall lamp with a 3d map, I just relearned how many existing patterns don’t support 3D “out of the box” yet. It’s easy to fix, and once we get all of the patterns into GitHub, submitting patches to make things more uniform and universal will likely happen.

The whole point of mapping is to separate the hardware (and layout) from the patterns. Ideally you shouldn’t ever have to change your map once it’s set correctly. But we’re not quite there yet.

I think i get the power of the map, but afraid there are always going to be a lot of other patterns. hence once you get that perfect map done, and go find some other new pattern, you have to tweak the map. and it would be better to embrace the excellence of the power of the map rather than strive for every patterns perfection… make ALL patterns ‘more perfect’ by abstracting that hardware. regardless if the are written with the latest direction of the wind in mind.

My pov is have/support multiple maps and make it easy to pick one.

Every one of those EXAMPLE maps (along with the ability to customize and OVERRIDE some of the global values Pixel Count and Ex-pander board settings) ,be callable, bindable as a “config set” I’d like to be able include/exclude certain pixels to have them always on or always off, or virtually re-wire the ordering of multiple displays daisy chained. I know you can do all of that in pattern code. but dont want to do that in every pattern for every project. i want to do that more globally.

I think the map is underappreciated being cast as a simple set and forget translation layer.

1 Like

I tend to agree, and anyone can tweak a pattern to be more optimal for a given piece. I think the universality - that it can work out of the box with no modifications is powerful.

When it comes to displaying 3d patterns on 2D, the new version can do that now. It defaults to a 2D plan with a fixed Z component, which is probably not ideal but is easy to explain/understand. Perhaps there could be a way to specify how the 3d pattern renders in 2D, which of the 3 coordinates to use for the 2D, and perhaps a way to rotate/translate/transform in the style of a UI control without going in and coding it.

Going 2D to 3D is less straightforward unless you assume a cylindrical map and “wrap” the 2d around it, like a tin can label. And perhaps if we have a way to adjust how 3D patterns look in 2D, adding features like that would make sense and would have many applications. For something like that we’re previously talked about a renderPolar or something as well, to make it easier and allow a pattern to apply to different coordinate systems even if the map is cartesian.

Outside of PB, when I think of going from 3D to 2D its a projection. Like the map preview rendering 3D points in 2D browser window. I don’t know how well that would translate to low/medium density 2D LED setups though.