Display Buffer Organization

Can anyone explain the quick and dirty of how the display Buffer is arranged? I haven’t had the time to fully research it but it appears to be (from looking at drawBitmap)


  1. bottom left of image
  2. top left of image

This is assuming an 8xN pixel image.
Is this correct?

If I remember its an array of bytes that get read in by rows within tiles?

Check out these threads and the source linked.

These were found with the search function for the community pages. It actually does a great job, and is a much more useful search function than most platforms, so try it out : )

I’ll validate later tonight but going off memory (and another oled arduino).

Each byte is 8 vertical pixels. The next byte will be the next set of 8 pixels to the right of it.

So if we look at it in a bit map (from the top left heading, heading to the right of the screen every byte)
| 0 | 8 | …
| 1 | 9 | …
| 2 | 10 | …
| 3 | 11 | …
| 4 | 12 | …
| 5 | 13 | …
| 6 | 14 | …
| 7 | 15 | …

Oh interesting, so it does start top left? Basically what I was thinking but reversed vertically. I’ll need to start toying with it to really get a handle on it. I’ve almost wrapped up my first game and from there I want to explore more complex programming if images :smile:

Thank you everyone for the help!

The bytes are indeed sent from left to right and then from top to bottom, but the first bit is not in the top left corner:

|   7  |  15  |  ... | 1023 |
|   6  |  14  |  ... | 1022 |
|   5  |  13  |  ... | 1021 |
|   4  |  12  |  ... | 1020 |
|   3  |  11  |  ... | 1019 |
|   2  |  10  |  ... | 1018 |
|   1  |   9  |  ... | 1017 |
|   0  |   8  |  ... | 1016 |
| - - -| - - -| - - -| - - -|
| 1031 | 1039 |  ...
|  ...

The thing that is confusing me is organizing the byte vertically. Are you saying the least significant bit is the first pixel? As in Byte 0, 0000 000X, bit X is pixel 0, 0?

The top-left bit IS the first bit! I just made my own set of tools and this is how it works:

A black pixel in the image will result in the bit being 1, white results in 0.
Every byte represents a vertical slice of 8 pixels from top to bottom.
For bitmaps that are more than 8 pixels in height the bytes are stored “per row”:

is stored as

Knowing that black is 1 and white is 0, the first byte in this example is (from top to bottom) 11111110 or 0x80.

Hope that makes sense to you guys, I’m not the best at explaining ^^’

I came across some old source cleaning up. This may help someone. This is designed to unpack the image buffer and draw it to a standard coordinate system.

// Unpack the Arduboy image buffer.
// image[] holds an array of chars, where each of the 8 bits
// for each char represent a pixel value to display.
void ArduEm::drawScreen(unsigned char image[])
  // counting the rows of image[] by 8 steps each iteration
  for (int j = 0; j < HEIGHT; j+=8)
    // walk the columns
    for (int i = 0; i < WIDTH; i++)
      // find the relevant cell in image[]
      unsigned char c = image[(j/8)*WIDTH+i];
      // step through those 8-bits
      for (int k = 0; k < 8; k++)
        // if the bit is set to 1, draw a pixel
        if ((c>>k)%2 > 0)
          // i is the x-coordinate and (j+k) is the y-coordinate
          SDL_RenderDrawPoint(renderer, i, j+k);    

Thanks for the replies! I finally got my method working the way I wanted. I’m making a different way of drawing images and wanted it to be as efficient as my skill will allow haha. It is interesting to work directly with bytes and the display buffer for sure.

Super thanks ekem!
That will definitely be useful in my bitmap encoding tool


1 Like

Right on. If you optimize it in any way, let me know : ) I’ll update my code.

I’m really confused, I started modifying my tool but then I recalled user @davidperrenoud said that Arduboy images are rotated 90°… which is totally incompatible with above discussion and drawScreen() method… :confounded:

Post in question is there: My freeware tools for Arduboy development

So which is it?? Again I don’t have any Arduboy nor devkit, I guess I should wait for one instead of doing blind developments…

1 Like

The images are packed in a data structure. How the image translates to a 2 dimensional coordinate space is in how you unpack the image buffer. In david’s case, the algorithm he used to unpack the buffer resulted in an image that was rotated 90 degrees in a direction, in relation to whatever coordinate orientation he was using.

Thanks Ekem. So what is the “standard” Arduboy method to display a bitmap? Is it through a call to the above drawScreen() ? Another function? Actually what would be best: is there a wiki or reference somewhere of Arduboy functions?

That drawScreen method is part of an api for some other source entirely, for like a little emulation program. Hopefully if you walk through the function you can see exactly how things are stored in the image buffer, and how to un/pack it; then you can start correctly manipulating it in your own programs. Packing it is probably what you are after, so just reverse the function I’ve provided. You probably don’t want to convert image buffer points to 2D coordinate space if you are working inside of the unit, as thats not how things are drawn to the screen, and its adding cpu time to do all the reorganizing. There have been a couple good scripts written to do things with bitmaps in the dev unit. I haven’t done anything with displaying bitmaps in the unit itself.

Check out my first reply for some links, and then the source for these demos.
They change header file names and things, but you can find the standard Arduboy api functions inside of the ArgLib.cpp file

Mougino, the way I figured out how the Buffer is organised was by creating a function that counted from 0-255 while drawing that value to the Buffer one index at a time. What I found was that each byte stores 8 pixels vertically it goes like this:

Oh EDIT: sorry my bytes are reversed. Least significant bit in Byte 0 is pixel 0,0, most significant bit is 0,7.

Byte 0
B 0. 0. 0. 0. 0. 0. 0. 0
Pixels XY
0,0. 0,1 0,2 0,3… 0,7
Byte 1
B 0. 0. 0. 0. 0. 0. 0. 0
Pixels XY
1,0. 1,1 1,2… 1,7

Increment row after 8x128 pixels. Row * WIDTH is the next byte down. Pixel 0,8 would be in byte (1 * WIDTH)

It’s kind of a funky thing to wrap your mind around at first. Especially if you don’t have your own board for visualisation. I hope that helps.

1 Like