Help with LCDBitmap structure in C (and Arduboy ports)

I got interested into the Playdate, but I have to wait until next year to get my hands on it - so I started to play around with the Simulator and the SDK (on Linux/Ubuntu).

I have an Arduboy and some neglected projects for it - but I started them all with a port-layer (in case I want to finish them somewhen and port them to other platforms).
So I tried to port a Zelda-like Arduboy prototype to the Playdate.

The Arduboy uses C/C++, and unfortunately, the C_API documentation of the Playdate is pretty weak (especially when it comes to bitmaps and the associated datatypes).
But with some patience and analysis, I was able to port the basic bitmap draw function from the Arduboy to the Playdate!
I compared the output of pd->graphics->getBitmapData() and the raw byte data of a bitmap (created with pd->graphics->newBitmap()), and found out that the structure of the LCDBitmap datatype must look a bit like this:

typedef struct
{
    uint16_t width;
    uint16_t height;
    uint16_t rowbytes;
    ...
}
LCDBitmap;

Through some experiments I found out, that the raw bitmap data (the "data"-parameter of the pd->graphics->getBitmapData() function) is stored as a horizontal encoded bitmap!
The problem is that the Arduboy (I use the Arduboy2 library) uses vertical encoded bitmaps by default via the following method:

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

There is also a method that uses horizontal encoded bitmaps - but the problem of that method can be read in the name:

void drawSlowXYBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color);

I was lucky, cuz of my experience with the Arduboy (and some other open source handheld consoles) I always stored the vertical AND the horizontal versions of a bitmap.^^
I used the App "LCD Assistant" in the past to convert my bitmaps to code:

...but I know that there are many other tools/apps that do the same!

So I came up with the following function for my port:

void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint16_t w, uint16_t h, LCDColor color)
{
    LCDBitmap * b = NULL;
    uint8_t * data = NULL;

    b = pd->graphics->newBitmap( w, h, color );
    pd->graphics->getBitmapData( b, NULL, NULL, NULL, NULL, &data );
    ( ( uint16_t * ) b )[ 2 ] = w / 8;
    memcpy( data, bitmap, ( w / 8 ) * h );
    if( color == kColorWhite )
    {
        pd->graphics->setDrawMode( kDrawModeBlackTransparent );
        pd->graphics->drawBitmap( b, x, y, 0 );
    }
    else if( color == kColorBlack )
    {
        pd->graphics->setDrawMode( kDrawModeBlackTransparent );
        pd->graphics->drawBitmap( b, x, y, 0 );
        pd->graphics->setDrawMode( kDrawModeXOR );
        pd->graphics->drawBitmap( b, x, y, 0 );
    }
    pd->graphics->freeBitmap( b );
}

I like to code in C, so here is a more complete/detailed version:

void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint16_t w, uint16_t h, LCDColor color)
{
    LCDBitmap * b = NULL;
    uint8_t * data = NULL;

    /* The width must be a multiple of 8. */
    if( w % 8 == 0 )
    {
        /* Create a bitmap which holds just a single colored square. */
        b = pd->graphics->newBitmap( w, h, color );
        if( b != NULL )
        {
            /* Get the memory address of the raw bitmap data. */
            pd->graphics->getBitmapData( b, NULL, NULL, NULL, NULL, &data );
            if( data != NULL )
            {
                /* Set the "rowbytes" parameter. */
                ( ( uint16_t * ) b )[ 2 ] = w / 8;

                /* Copy our own bitmap to the position of the initial data. */
                if( memcpy( data, bitmap, ( w / 8 ) * h ) == data )
                {
                    /* Finally, draw the new bitmap. */
                    if( color == kColorWhite )
                    {
                        pd->graphics->setDrawMode( kDrawModeBlackTransparent );
                        pd->graphics->drawBitmap( b, x, y, 0 );
                    }
                    else if( color == kColorBlack )
                    {
                        pd->graphics->setDrawMode( kDrawModeBlackTransparent );
                        pd->graphics->drawBitmap( b, x, y, 0 );
                        pd->graphics->setDrawMode( kDrawModeXOR );
                        pd->graphics->drawBitmap( b, x, y, 0 );
                    }
                }
            }

            pd->graphics->freeBitmap( b );
        }
    }
}

Like I said in the beginning, I only used the Simulator - so I'm not pretty sure if it works on the real device...
So I woulde be happy for some response, if you use my code on the real device! :wink: