drawPixel (horizontal / vertical pixel bytes)

Hoping someone with a more intimate understanding can shed some light for me on what each line of drawPixel is doing here:

uint8_t row = (uint8_t)y / 8;

if (color)
{
  sBuffer[(row*WIDTH) + (uint8_t)x] |=   _BV((uint8_t)y % 8);
}
else
{
  sBuffer[(row*WIDTH) + (uint8_t)x] &= ~ _BV((uint8_t)y % 8);
}

…in relation to the way the Arduboy’s SSD1306 LCD controller stores pixel data:

And, what changes would need to be made to drawPixel in order to store pixel data in horizontal rather than vertical bytes for use with a different LCD controller? like so:

Any enlightenment would be greatly appreciated! :smiley:

Many other parts of the core library (drawSprite, drawImage, etc) also depend on the data orientation… other than replacing everything with slow calls to a new drawPixel (which you make aware of your hardware) you’re looking at a LOT of work to fix the entire library and be able to compile the most popular games.

What does it matter what orientation the pixels are drawn / stored in? Why would you want to change it? As long as your conversion program does its job in the right direction the data will be valid.

Well, actually maybe… if it’s still 8 bits (just horizontal) AND you changed the WIDTH/HEIGHT constants and re-jiggered all the conversion software to output in the new format…

But I think the idea here is to make EXISTING programs compile and work as-is… so they don’t want to have to re-generate C sprite data for every single game every published, etc.

And just fixing drawPixel alone doesn’t give you that since it would be 1000x slower than the hand optimized assembler for sprites, which means most (or all) of the TeamArg games wouldn’t be playable, etc… hence my original comment.

The best bet for someone building their own Arduboy clone and expecting it to “just work” is to get a LCD/OLED screen with a vertical byte orientation.

// calculate position in the screen buffer of the byte we need to change
(row*WIDTH) + (uint8_t)x]
// figure out which bit of the bit we want to light up (or not)
 _BV((uint8_t)y % 8)
// turn that bit of the byte on or off
|=
&= ~

Fixing drawPixel would take 5 minutes. The real problem is that for anything else to work (without rewriting/regenerating all the sprite data) you’d have to do a x-y transform on every sprite. So (best case) you’d have to read in say 8 vertical bytes, and then with a ton of bit shifting math transfer all 64 bits into horizontal orientation in 8 newly horizontally oriented bytes. These AVR chips are NOT good at tons of bit-shifting operations. Even if done assembly the transform itself would be likely two orders of magnitude slower - rendering most of the serious games unplayable.

I don’t know if I have missed the backstory here, but the original question posed was literally just asking a technical question. OP didn’t state anywhere here that he cares a fig for compiling with the TeamArg games, or any of the others for that fact.

As for where it could be useful, well, the procedural generation I use to pack large sprites into a couple numbers works by building a sprite row by row. If I could write pixel data to the buffer horizontally I could use 4 writes to the buffer for each row of the sprite as opposed to 32 writes (to stick each pixel into the vertical bytes). Obviously I leverage other parts of the library so the tradeoff was that it was simpler to not ask this question (I nearly did) and just work with the penalty.

All you guys have done is discuss the downside of making existing games unplayable, but I’m not really sure that is what OP was asking for. As far as I can tell, if you wrote the code for horizontal sbuffer, it would work fine for you game, and then when you compile and run a teamArg game, that would also work fine.

No, because of the cost of transforming the teamArg graphics form vertical to horizontal encoding on the fly will cost way too much time.

But you are right that the intention isn’t clear from the original posting. But this is the Arduboy forum… so that’s how I reached the conclusions I did.

If I build my horizontal sBuffer game with my own graphics pipeline, that will work fine. And if I then build the TeamArg game with the normal library and its normal graphics pipeline, that should work still. There shouldn’t be any cross pollution of the code bases, unless I am grossly misunderstanding how the arduboy handles things.

They are talking about using a different LCD controller… any teamArg game would be completely garbled on a horizontal data oriented LCD if compiled and used as is without any type of transformation of that data.

Now if you wrote a program to transform the data in the C code itself… you might be onto something.

OOOOOOOOHHHHH right, I get you, i think. So the thing they are talking about coding up is not even included in the sketch of any game itself?

1 Like

Correct, I was thinking towards adapting the base library for a different LCD controller system that would store the pixel bytes horizontally - but hoping to be able to maintain compatibility with existing sketches… I hadn’t thought all the way ahead to sprite routines though!

Seems like the options would be to A. sacrifice compatibility, or B. keep the vertically orientated buffer for pixel storage and do the x/y translation work at the ‘paintScreen’ stage, or external to the microcontroller, or a combination of both without losing too much speed…

If “external to the micro-controller” means you re-write the sketch’s image assets before you compile it to fix the data then, ok… but otherwise you can’t do this on the chip. It doesn’t matter whether it’s done in the draw routine or the paint routine… the transform is just going to be WAY too slow.

Otherwise I’m not exactly sure what “external to the micro-controller” means…

Well, one thought I had was to use parallel output, pushing the eight bits of each vertical byte out on eight pins of the same port. And then by feeding these parallel outputs into the 1st, 16th, 32nd, and 48th ‘taps’ of a dual 64-bit shift register in the right sequence, the pixels can be reorganised into horizontal bytes on the fly! At least in 16 by 8 grids of 128 pixels at a time that is! :smiley:

Ok, now you have the right idea… but I think the problem is that for some games there just isn’t any room to spare. Some games are pushing 90-100% CPU usage… and with the optimized assembly pushing sprites to the screen it’s very, very tight. About as fast as it’s going to be without loop unrolling.

So now instead of just writing a byte to RAM you want to 1. output it over a port 2. maybe wait? 3. read it back in over a different port. 4. write it to RAM.

I’m not sure if you need a wait-state or not or if your register could simply keep up with 16mhz… And add more instructions if you need to flip another pin to tell the register to perform the shift operation, etc. Actually the original code has to read from Flash also… 1.read 2.write… but I’m not convinced there is room inside that loop for what you’re needing.
It’d be easy enough to test though.

Take one of the popular teamArg games that makes extensive use of the assembly sprite rendering. Figure out (at a low level) what instructions you’d need to add for the external shifting. Add NOOP assembly to kill an equivalent number of cycles… compile and test the games at the new slow speed.