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!