Displaying letters

Hi

I’m working on a project involving 8 Pixelblazes being coordinated by Firestorm. Each pixelblaze drives a matrix that will be displaying one letter. I’d like to make it so any of the patterns can run, but only the pixels corresponding to the selected letter will light up. I have an idea of how to pull this off, but I just want to hear from you guys if I’m on the right track.

So each pixel gets 3 values assigned to it via the mapper. Maybe I can figure out a way to use these values to describe which letters each pixel is used in (e.g. for px #13, it would light up for letter ‘N’, but stay dark for the letter ‘S’). Basically, I’m trying to map 3 - 32bit floats (I think) into 26 or more binary values.

Does the editor PB support bitwise operations? Is there a way to save the mapper values as specific bit values instead of floats?

Does the firestorm API support sending variable values (like what would come from the sensor board) that I could use to indicate the letter?

Is there a much more sensible way of going about this?

Thanks in advance!

You can send a variable to a Pixelblaze, so if you ran "alphabet matrix"on all of them and passed a letter as a variable (more likely a number), you could fire off each to display the correct letter.

That’s how I’d do it, in that circumstance.

If you want them to run ANY pattern, but only have the correct pixels light up, that’s a different scenario that I envisioned at first. In that case, you’d have to modify the pattern(s) no matter what, so I’d say add in the variable Alphabet to each pattern and it would do the same thing:

During render: if this pixel is part of my alphabet array (which is based on the variable, and each is a set of pixels to light up), then do whatever, otherwise stay dark.

You’d have a set of 26+ series of pixels, doesn’t even have to be mapped, that define each letter.
Would need this on every pattern you wanted the letter effect (and variable to work for)

Whoops, @jeff reminded me with his post, I’m thinking of https://github.com/zranger1/pixelblaze-client

Not Firestorm (yet)

1 Like

Hi!

I just got done with a 5-PB firestorm-coordinated display, so I have a some opinions on how to go about this!

I’m not sure I totally understand the final output, but I’m envisioning it as 8 matrices (so, an 8-letter word could be displayed across them all), and you want to play any pattern such that it “fills” the pixels for the letter on each matrix. But then I got a little confused about what you meant in your example for N… I understand N is the 13th letter of the alphabet, but I don’t think you want to send each Pixelblaze a letter like “N” then have just the 13th pixel on the matrix light up…

Knowing the index of each Matrix

You could duplicate your pattern to all the PBs manually, and then set a variable like “matrixNumber” differently on each Pixelblaze to values from 0-7. But I think your plan, of trying to store it in the map, is ultimately more convenient. More on why later.

The mapper will rescale all values to 0-1, so if we wanted to use the third dimension, Z, to store the matrix number, this is possible as long as you include two non-pixel points at Z extremes. For example, if each matrix was an 8x8, the map could use the default matrix map, but add a third dimension to each point for the matrix number (0-7), as wel as two additional points, as shown here:

Map

function (pixelCount) {
  let matrixNumber = 2
  let width = 8
  var map = []
  for (i = 0; i < pixelCount; i++) {
    y = Math.floor(i / width)
    x = i % width
    x = y % 2 == 1 ? width - 1 - x : x // zigzag
    map.push([x, y, matrixNumber])
  }
  map.push([0, 0, 0], [0, 0, 7]) // Add bounding Zs for 8 total matrices
  return map
}

Pattern code - recover matrixNumber

Remember, the 0…7 we pushed into z will come into render3D scaled to 0…1, so we need to multiply it back up.

matrixCount = 8
export function render3D(index, x, y, z) {
  matrixNumber = floor(z * (matrixCount - 1))
}

Why?

The benefit of pursuing this strategy over, say, creating a variable on each PB that you assign the matrix number, is that that as you debug and perfect your patterns, you can just re-clone your improved patterns to all 8 PBs without having to go back in and copy-paste snippets or re-set the matrixNumber variable.

Setting globals from Firestorm

For sending variables from Firestorm, I wanted this too, but It’s not built into the UI yet. You can set them via websockets. I made a video showing this (setting a particular ascii letter on a matrix) here.

If you wanted to contribute to Firestorm, that’d be awesome too.

Bitwise operations

Since all values in PB are 16.16 fixed point numbers, and the mapper dimensions are scaled to 0…1, you can see how you’ll have access to the lower 16 bits to the right of the fixed point (but my example above sidesteps this).

Pixelblaze has a bunch of bitwise operators. Two patterns I know of that use them are the excellent “Pew Pew Pew” by Scott Balay, and my “Scrolling Text Marquee” for matrices, which I think you might find useful for this project.

Both are in the pattern library, but since it can be a bit unwieldy at the moment, I’ve attached them here as well:

Pew-Pew-Pew!.epe (15.8 KB)
scrolling text marquee 2D.epe (12.3 KB)

Hope this helps!

1 Like

Yeah, I find the whole matrix number bit unneeded. Especially if this is meant to be changeable.

Is matrix #1 always one letter? Or do you want this to be able to write different things?

I’m not 100% sure I understand what’s trying to be achieved here, but what if you used the GP inputs to assign a fixed unique “address” to each PB, which could be read and used as an index by the pattern code?

1 Like

This is all really great information!

Exactly.

Sorry for the confusion, 13 is just an arbitrary pixel index for my example, and it’s purely coincidence that ‘N’ is also the 13th letter of the alphabet.

I realized that I don’t have all 3 mapper values to use for letter assignment, as I still want to describe the 2d matrix, so really I just have the z value to work with. Meaning I would only have a 16.16 fixed point number to describe 26 binary values… Not sure I can do that.

Jeff, I see what you’re doing using the mapper to tell each pb which matrix it’s driving, but I’m not sure that’s really necessary. Unless you were imagining that the websocket would send the entire word, and each pb would pick out the letter to display based on it’s matric index? I think the mapping resources are stretched pretty thin already.

What I have in mind is something like this:

export var myLetter // is set to 3 for letter 'C' via firestorm/websocket

export function render3D(index, x, y, z) {
  // do other pattern stuff
  var v = isPartOfThisLetter( myLetter, z ) // 1.0 or 0.0
  hsv(h, s, v)
}

And then add those few bits to each of the patterns.

Alternatively

Is it possible and would it make more sense to try this approach: Each time a letter changes, instead of sending the letter index and letting the PB figure out which pixels to turn on based on mappings, could the websocket send the entire letter layout? Each matrix is 400px. And if that was the case, I wouldn’t be limited to letters, I could send any mask I wanted…

As someone who has a bit of experience at sending data to the Pixelblaze at a relatively high rate, yes, you could definitely send the whole bitmask over websockets as needed. It would make for a really fun, flexible display!

Thanks for clarifying, @cjn566!

Something funny I realized is that “n” is actually the 14th letter of the alphabet, which is too funny given a recent tweet from wizard:

To confirm, yes, I was going for a system where you send the whole word to all Pixelblazes, and they pick out the right letter. In a scheme like that, you could enhance the pattern to scroll a message across all matrices, and you don’t need to know which letter to send to each board.

But, moving forward with the example you showed with isPartOfThisLetter(myLetter, z), would it be easier to express this 20x20 font bitmap in code instead of within the map data itself? That’s what I did in the scrolling text marquee pattern, so I might be biased to see the problem that way. If you want to tweak the font, you just reclone all the boards instead of tweaking 8 maps. If you did this, you might write it as:

isPartOfThisLetter(myLetter, x, y)

instead of

isPartOfThisLetter(myLetter, z)

However, for the sake or argument, is it possible within the Z coordinate? Since Z is in “world units” and will only have values within 0…1, you only have 16 bits of usable data (the fractional part of 16.16)*.

We need to express a yes or no value for each of 26 letters. The straightforward answer is a 26-bit binary vector, but we only have 16. That implies you’d need to use a compression scheme, and at this point, I start getting a strong sense that the more straightforward solution is to store pixel positions in the map, and the spacial definition of a character in code.

But then - yeah, what zranger1 said - you could also send all 400 bits, or 400 RGB values, to each one over websockets, and keep all the brains in your central controller code.

*In my experiments, due to the way map scaling happens, we can’t reliably set all 16 bits.

I still think you could/should put the bitmaps for each into the pattern (like the scrolling text pattern), and just send the letter OR send the word and a variable set for position in series, so send matrix #3 the variables of matrix=3, word=blahblah and it would display an A. Or it could even scroll in unison.

And my thinking instantly went this way…

I could run the same relatively simple pattern on all the Pixelblazes and have the controller send not a bit mask, but a 0…1 range alpha channel mask to each Pixelblaze. The Pixelblazes could then use the mask for complete selective brightness control per pixel, or even cross-fading between sub-patterns using one of @jeff’s methods.

The computational load on the Pixelblaze side would be very low – to control brightness, just multiply the pattern’s final brightness by the corresponding alpha mask element. Plus if you used something like Processing on the controller, you could very easily get it to cough up low-res (but still anti-aliased!) renderings of truetype characters or whatever to use as masks.

2 Likes