Please help me work out how to shift bitmaps

Hi folks,

not new to arduino but certainly no expert...I've searched and searched but can not find an answer to my problem, hopefully some nice person around here can help.

So I've got a 16x8 matrix made with WS2812B's and I've been displaying 16x8 bitmaps on it no problem...if I create the array how I want to see it on the matrix. ie

const long pac1[] PROGMEM =
{
0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff,
0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff,
0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff,
0xffff00, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff,
0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0xffff00, 0xffff00, 0xffff00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
};

and calling it with;

FastLED.clear();
for(int i = 0; i < NUM_LEDS; i++) {
    leds[i] = pgm_read_dword(&(pac1[i]));
  }

FastLED.show();
delay(anim);

and that works as it should.

However, what I now want to do is have effectively a static bitmap shifted across the matrix from off screen left, to off screen right by one pixel at a time. I could do it by creating a new bitmap array for every "frame" but that would take too much memory and time...I know there will be a way to only need the one bitmap and just have it shift pixel by pixel, but I can not find a way to use the adafruit GFX library or FastLED to scroll the kind of bitmap array I want, only this kind...ie;

 {   // 2: smiley
      B00111100,
      B01000010,
      B10100101,
      B10000001,
      B10100101,
      B10011001,
      B01000010,
      B00111100 },

using..

   void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);

where I could incriment int16_x by 1 each pass.

So, could someone please point me in the direction of the correct way to display a "full" rgb (I think it's 3 bytes, 1 per R,G,B??? so, 0xff96b0) and have it shifted right one pixel at a time.

Massive thanks in advance, this is a case of I cant see the wood for the trees :slight_smile:

Gibz

I think it's 3 bytes, 1 per R,G,B???

Correct, but not relevant. Each pixel is represented by a single 'long', so you can simply manipulate the data at that level of granularity.

What you will need to change is how you access each pixel's data. Right now, the matrix is represented as a linear 128 pixel array, and your "bitmap", which is really a "pixmap" (bitmap implies 1-bit per pixel) is also a linear 128 pixel array. To do the scrolling operation, you need to be talking in terms of row and column indexes into the pixmap and calculating the linear index i = 8 16 * row + column.

So try changing your code from a single loop which iterates i from 0 to 127 to two nested loops which iterate column from 0 to 15 and row from 0 to 7. Inside the loops, calculate i as above. The result should be exactly the same as your current code, but you will be one step closer to scrolling. Post the updated code when done and we'll move on to the next step.

Thanks for the reply Paul, it's going to take a little time for me to process the info though. I do appreciate the info regarding bitmap and pixmap, thank you. Ok, reading your reply several times and scratching my head before taking the instruction literally I came out with this.....am I even close to the right track? :slight_smile: Something like;

  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 16; col++) {
      int i = (8 * row) + col;
    }
  }

If I am could you explain the working out of "i" please? I'm unsure as to why we have 8*row etc...yup, I'ma bit stupid. If I'm waaaay off track could you please give me a shove back on course? I'm very grateful....sometimes you cant work things out all on your own and you just need to ask someone, so thanks in advance.

So is:-

The result should be exactly the same as your current code,

If yes you have it right if no you haven't.

Describe what happens when that is part of your current code, then post that code.

could you explain the working out of "i" please?

i is the "how many LEDs into the strip have I got"

Sorry, I made a little mistake in that last post, I meant to say 16 * row + column

But that might not be correct either. It depends on how your matrix is wired. Hopefully you will have observed/worked out that already, so please describe it. For example, where is led #0? (Top left?) Where is led #1? (to right of led #0 or below it?) Where is led #8? (to right of led #7, below #7 or below #0?)

Often, 16x8 matrices are actually wired as 2 8x8 matrices, with LEDs #0 to #63 on the left side and #64 to #127 on the right side.

Within a matrix, the odd numbered rows may be "reversed" in direction compared to the even numbered rows, or may be in the same direction. These are sometimes called "serpentine" or normal/"raster".

These considerations are important to work out how to convert row and column into an index number.

Oh this is amazing...I was about to post my code after reading Mikes post, and explain how it worked beautifully ...for the top half of the image but the bottom was missing...then the forum warned me of a new post and to read it before replying, and as soon as I saw the "16" in your post the penny dropped!

So hang fire a sec and I'll get back to you....

Thank you guys, brb...

Ok, brilliant...this code displays a sapce invader in the middle of the screen, as it should...exactly how it does it with the old method...

#include <FastLED.h>        //Include the FastLED library
#include <avr/pgmspace.h>  // Needed to store stuff in Flash using PROGMEM

#define LED_PIN 53       //Set which pin will send data to LEDS
#define NUM_LEDS 128       //Deifine the number of leds/pixels in total
#define LED_TYPE WS2812B    //Tell arduino what type of LEDS
#define COLOR_ORDER GRB       //Sets the order of the rgb data
#define BRIGHTNESS 80       //set the brightness of the LEDS
int frameEnd = 250;
#if defined(__AVR__)
#include <avr/pgmspace.h>     // Needed to store stuff in Flash using PROGMEM
#elif defined(__PIC32MX__)
#define PROGMEM
#elif defined(__arm__)
#define PROGMEM
#endif

const long AlSk0[] PROGMEM =
{
  0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff,   0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000,
  0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000,
  0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000,
};

CRGB leds[NUM_LEDS];          //Create our leds array and tell library how many we have

void setup() {
  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);   //Create LEDS and give details
  FastLED.setBrightness(BRIGHTNESS);                              //Set the brightness
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Black;
  }
  FastLED.show();
  delay(frameEnd);             //Wait a second before doing anything
  randomSeed(millis);          //Use the millis function to generate a random seed
  FastLED.clear();
}

void loop() {
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 16; col++) {      /////////THIS IS ME FUMBLING AROUND/////////
      int i = (16 * row) + col;
      leds[i] = pgm_read_dword(&(AlSk0[i]));
    }
  }
  FastLED.show();

Well chuffed...now we need to start "displaying" it off screen to left and scroll it to the right....
I assume we need to somehow give it a negative x position and incriment it so it's however many pixels the width the image is on top of the number of columns in the matrix??? But how? :slight_smile:

PaulRB:
Hopefully you will have observed/worked out that already, so please describe it. For example, where is led #0? (Top left?) Where is led #1? (to right of led #0 or below it?) Where is led #8? (to right of led #7, below #7 or below #0?)

Often, 16x8 matrices are actually wired as 2 8x8 matrices, with LEDs #0 to #63 on the left side and #64 to #127 on the right side.

Within a matrix, the odd numbered rows may be "reversed" in direction compared to the even numbered rows, or may be in the same direction. These are sometimes called "serpentine" or normal/"raster".

These considerations are important to work out how to convert row and column into an index number.

Very sorry, got excited at seeing "16" and didnt answer this part...

Ive made it that led #0 is top left and its a "progressive" data flow not a "zigzag"

Ah, so it's a self made matrix of 8 strips of 16 LEDs? All the strips have "Din" on the left and "Dout" on the right?

Its always a "zigzag". The first strip is the "zig". Then either the second strip is the "zag", running in the opposite direction, or a data wire behind the strips is the "zag".

PaulRB:
Ah, so it's a self made matrix of 8 strips of 16 LEDs? All the strips have "Din" on the left and "Dout" on the right?

Its always a "zigzag". The first strip is the "zig". Then either the second strip is the "zag", running in the opposite direction, or a data wire behind the strips is the "zag".

Ah yes true, there is always a zigzag :slight_smile: Yes, I have cut 8 strips of 16, #0 is top left, #127(last led) is bottom right, all the D lines are running left to right, where at the end of a strip the data "zags" back to the start of next strip. Hope Ive not confused you :slight_smile:

I assume we need to somehow give it a negative x position and incriment it so it's however many pixels the width the image is on top of the number of columns in the matrix??? But how? :slight_smile:

If you want to scroll the pixmap in from the left and out to the right, then the top left of the pixmap needs to start out at column offset -16 (completely hidden off to the left) and then increment a few times per second until it hits offset +17 (completely hidden off to the right).

To update the matrix, iterate through the columns and rows as you are now. For each row/column position in the matrix, calculate the corresponding row/column position in the pixmap, by adding the column offset (and row offset, if scrolling vertically/diagonally).

Once you have calculated the corresponding row/column position in the pixmap, you then need to check that it is within the limits of the pixmap, i.e. column between 0 and 15 and row between 0 and 7. If so, use the formula to calculate the linear index into the pixmap and look up the required colour. Otherwise, colour the row/column position in the matrix black (or other background colour of your choice).

PaulRB:
If you want to scroll the pixmap in from the left and out to the right, then the top left of the pixmap needs to start out at column offset -16 (completely hidden off to the left) and then increment a few times per second until it hits offset +17 (completely hidden off to the right).

To update the matrix, iterate through the columns and rows as you are now. For each row/column position in the matrix, calculate the corresponding row/column position in the pixmap, by adding the column offset (and row offset, if scrolling vertically/diagonally).

Once you have calculated the corresponding row/column position in the pixmap, you then need to check that it is within the limits of the pixmap, i.e. column between 0 and 15 and row between 0 and 7. If so, use the formula to calculate the linear index into the pixmap and look up the required colour. Otherwise, colour the row/column position in the matrix black (or other background colour of your choice).

Right, that's going to take some digesting :slight_smile: Thank you for your help so far...please bear with me on this.

So what I need to work out then, is what part of the pixmap is shown when we're at position -17,0 through to pos 32,0 (only scrolling horizontally), and then somehow only draw that part of the pixmap??

ie;

if we're at pos -5,0 I have to display the last 11 columns of the pixmap? And there is a way to do that by creating an offset but now I'm struggling tbh.

I'm probably overthinking it or just more out of my depth than I had realised, but is there another pointer you could give me please?

Thank you.

Let's take your example: the top-left of the pixmap is at -5,0, and you now want to update the matrix to reflect that.

You start by updating row 0 column 0 of the matrix. The corresponding pixel in the pixmap is row 0 column 0-(-5)=5. That's within the boundary of the pixmap, so you can convert row 0 column 5 to an index and look up the colour from the pixmap. This is then assigned to the matrix, but remember we are updating row 0 column 0 at this point, so it's a different index (=0).

Later, you are updating row 5, column 10 of the matrix. This corresponds to row 5 column 10-(-5)=15 in the pixmap. Again, that's inside the limits of the pixmap, so similar to above.

But when you update row 5, column 11 of the matrix, the corresponding pixel in the pixmap is row 5 column 11-(-5)=16. This is outside the limits of the pixmap, so you can't calculate the index to look up the colour, instead you set it to black. Thus, the matrix index corresponding to row 5 column 11 gets set to black.

Does this help?

I must firstly thank you for your input here, and apologise for my lack of knowledge...

Your last post certainly helped me see what I need to do, but if I'm honest I dont think I have the tools required to work out how to actually write that :frowning:

I probably need another integer and for loop to iterrate through the "all the way off left" postion to the "all the way off right" position but I'm unsure how to actually convert that to display the pixmap correctly.
I guess, in a nutshell, I dont know how to start "drawing the pixmap off the screen"...so to speak.

I assume there's a way to say, "if int pos = -5(as we iterate through) then draw rows 0-8, cols 11-16" and make anything else black in a neat way that can do the conversion for me and update ;

  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 16; col++) {      /////////THIS IS ME FUMBLING AROUND/////////
      int i = (16 * row) + col;                     
      leds[i] = pgm_read_dword(&(AlSk0[i]));
    }
  }

accordingly?

I'm truly sorry if you're face-palming yourself into next week and I thank you for your patience.