Pixelblaze V3.19 beta

,

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.

Yes, and that’s exactly the issue I’m having now:

I did a 3D map, but while my Y is correct (I made that height), my X and Z (essentially the circular components) are narrow and limited to a small range. I’m debating the right way to handle this, and so for fun, I put a controller with WLED onto it (actually onto the second unit, which I just built, and photos coming soonish) and immediately found a bug (it didn’t handle inexact matrixes correctly, so 11x27 is 297, and it would only light 3 rows till I changed it from 300 to 297 pixels) but I’m noticing that doing X as the 11 (so a wrap around the tin can) means that it’s a decent XY for things that only understand 2D.

But others don’t look right at all. There is no One True Way.

I’m going to go thru patterns with a few setups simultaneously. Like maybe a 1D strip, a 2D matrix panel, a lamp setup in 2D, a lamp setup in 3D, and see if there is a way to make “do the right thing” in all cases, or a way to at least make it a config. And yes, render_polar would be interesting, essentially when you do the X wrap on a cylinder, it’s really just polar (X becomes the angle, Y becomes the height, R is meaningless since all pixels are R from the central axis)

Now I just need to add “lava lamp simulator” to my to-do list, as my GF basically wants these giant 4-5 tall lamps to become that.

@zranger1, you’ll be happy to know that of ALL of the fire patterns, including on WLED (1D and 2D), Doom 2D 2.0 looks best on these lamps, according to her (and me too). I have to turn the dragon off though, as it’s way too much white at the base. Might want to add another dragon option with less white.

@Scruffynerf
Cube fire might be a good start for a lava lamp. I’ve played with it to make something similar on PB cubes where it moves mostly in one direction continuously. Maybe a merge of cubefire and rainbow melt.

Yeah, and I’ve seen metaballs used too. But I want a real lavalamp, so I’m looking at this code:

https://catkane-doodles.github.io/lava-lamp/

It warms the wax and those bits float upward… And as they cool, they drop back down. [warning - takes quite a while to warm up, just like a real lava lamp. I’ll have to figure out a jumpstart for it, like randomly warmer bits maybe.]

This one is built on top of a retired physics engine, but… it works.
http://wellcaffeinated.net/PhysicsJS/examples/lavalamp/

Ok, my own repo of the lava is a bit faster (massively increased heat source),

https://scruffynerf.github.io/lava-lamp/

and the code looks simple enough that a PB port will be possible, especially compared to the dozens of other projects I looked at, either more complex,.or worse: “lava lamp” (including led ones) that didn’t actually do “lava lamp” just plasma etc.

So hopefully this will be an actual lava lamp pattern, maybe first of it’s kind.

In Doom Fire, down near the end where it finally gets around to setting the pixel color, there’s a line:

hsv(baseHue+((0.05*bri)), 1.3-bri/4,baseBri * bri);

To decrease the white - the amount of desaturation of really hot pixels - change the constant 1.3 to something higher. All white will disappear at around 2.0, so maybe 1.75 or 1.8 would be about right.

I almost put a slider in for this, but figured I was already overcomplicating things. It’ll go in the next rev.

And I’m looking forward to what you come up with in the way of lavalamp. That ought to be super cool!

4 Likes