Skip to content

Instantly share code, notes, and snippets.

@DraperDanMan
Created November 20, 2024 20:39
Show Gist options
  • Select an option

  • Save DraperDanMan/7d7df20ec71038b6db6afea6cda30597 to your computer and use it in GitHub Desktop.

Select an option

Save DraperDanMan/7d7df20ec71038b6db6afea6cda30597 to your computer and use it in GitHub Desktop.
Playdate CrankIndicator C port
#include "crank_indicator.h"
int clockwise = 1;
int crankIndicatorY = 210;
int textOffset = 76;
unsigned currentScale = 1;
int currentFrame = 1;
int frameCount = 0;
int textFrameCount = 14;
unsigned lastTime = 0;
LCDBitmapFlip bubbleFlip;
LCDBitmap *bubbleImage = NULL;
int bubbleX = 0;
int bubbleY = 0;
int bubbleWidth = 0;
int bubbleHeight = 0;
LCDBitmapTable *crankFrames = NULL;
int crankFrameCount = 0;
int crankFrameWidth = 0;
int crankFrameHeight = 0;
LCDBitmap *textFrameImage = NULL;
int textWidth = 0;
int textHeight = 0;
PlaydateAPI *pd = NULL;
static LCDBitmap *loadImageAtPath( const char *path )
{
const char *outErr = NULL;
LCDBitmap *img = pd->graphics->loadBitmap( path, &outErr );
if ( outErr != NULL )
{
pd->system->logToConsole( "Error loading image at path '%s': %s", path, outErr );
}
return img;
}
static LCDBitmapTable *loadImageTableAtPath( const char *path )
{
const char *outErr = NULL;
LCDBitmapTable *result = pd->graphics->loadBitmapTable( path, &outErr );
if ( outErr != NULL )
{
pd->system->logToConsole( "Error loading image table at path '%s' : %s", path, outErr );
}
return result;
}
void initCrankIndicator( PlaydateAPI *playdate, int scale, unsigned flipped )
{
pd = playdate;
lastTime = 0;
currentFrame = 0;
currentScale = scale;
crankIndicatorY = 210 / scale;
char *imgPath;
pd->system->formatString( &imgPath, "images/crank/crank-notice-bubble-%dx", scale );
if ( bubbleImage )
{
pd->graphics->freeBitmap( bubbleImage );
}
bubbleImage = loadImageAtPath( imgPath );
pd->system->realloc( imgPath, 0 );
pd->graphics->getBitmapData( bubbleImage, &bubbleWidth, &bubbleHeight, 0, 0, 0 );
if ( flipped )
{
bubbleX = 0;
bubbleY = pd->display->getHeight() - crankIndicatorY - bubbleHeight / 2;
bubbleFlip = kBitmapFlippedXY;
textOffset = 100 / scale;
}
else
{
bubbleX = playdate->display->getWidth() - bubbleWidth;
bubbleY = crankIndicatorY - bubbleHeight / 2;
bubbleFlip = kBitmapUnflipped;
textOffset = 76 / scale;
}
pd->system->formatString( &imgPath, "images/crank/crank-frames-%dx", scale );
if ( crankFrames )
{
pd->graphics->freeBitmapTable( crankFrames );
}
crankFrames = loadImageTableAtPath( imgPath );
pd->system->realloc( imgPath, 0 );
pd->graphics->getBitmapTableInfo( crankFrames, &crankFrameCount, 0 );
LCDBitmap *frame = pd->graphics->getTableBitmap( crankFrames, 0 );
pd->graphics->getBitmapData( frame, &crankFrameWidth, &crankFrameHeight, 0, 0, 0 );
frameCount = crankFrameCount * 3;
if ( scale <= 2 )
{
pd->system->formatString( &imgPath, "images/crank/crank-notice-text-%dx", scale );
if ( textFrameImage )
{
pd->graphics->freeBitmap( textFrameImage );
}
textFrameImage = loadImageAtPath( imgPath );
pd->system->realloc( imgPath, 0 );
pd->graphics->getBitmapData( textFrameImage, &textWidth, &textHeight, 0, 0, 0 );
textFrameCount = 14;
frameCount += textFrameCount;
}
else
{
textFrameImage = NULL;
textFrameCount = 0;
}
}
void drawCrankIndicator( int xOffset, int yOffset )
{
const unsigned currentTime = pd->system->getCurrentTimeMilliseconds();
unsigned delta = currentTime - lastTime;
// reset to start frame if draw() hasn't been called in more than a second
if ( delta > 1000 )
{
currentFrame = 0;
delta = 0;
lastTime = currentTime;
}
// calculate how many frames the animation should jump ahead (how long has it been since this was last called?)
while ( delta >= 49 )
{
lastTime += 50;
delta -= 50;
currentFrame += 1;
if ( currentFrame > frameCount )
{
currentFrame = 0;
}
}
pd->graphics->drawBitmap( bubbleImage, bubbleX + xOffset, bubbleY + yOffset, bubbleFlip );
if ( currentScale > 2 || currentFrame > textFrameCount )
{
// draw crank frames
int frameNo = ( currentFrame - textFrameCount - 1 ) % crankFrameCount;
if ( !clockwise )
{
frameNo = crankFrameCount - frameNo;
}
LCDBitmap *frame = pd->graphics->getTableBitmap( crankFrames, frameNo );
if ( currentScale == 2 || currentScale == 4 )
{
yOffset += 1;
}
pd->graphics->drawBitmap( frame, bubbleX + xOffset + ( textOffset - crankFrameWidth ) / 2,
bubbleY + yOffset + ( bubbleHeight - crankFrameHeight ) / 2, kBitmapUnflipped );
}
else
{
// draw text
if ( textFrameImage )
{
if ( currentScale == 2 )
{
xOffset -= 1;
}
pd->graphics->drawBitmap( textFrameImage, bubbleX + xOffset + ( textOffset - textWidth ) / 2,
bubbleY + yOffset + ( bubbleHeight - textHeight ) / 2, kBitmapUnflipped );
}
}
}
void resetCrankIndicator( void )
{
lastTime = pd->system->getCurrentTimeMilliseconds();
currentFrame = 1;
}
PDRect getCrankIndicatorBounds( int xOffset, int yOffset )
{
PDRect result;
result.x = ( float )( bubbleX + xOffset );
result.y = ( float )( bubbleY + yOffset );
result.width = ( float )bubbleWidth;
result.height = ( float )bubbleHeight;
return result;
}
#ifndef crank_indicator_h
#define crank_indicator_h
#include <pd_api.h>
void initCrankIndicator( PlaydateAPI *playdate, unsigned int scale );
void drawCrankIndicator( int xOffset, int yOffset );
void resetCrankIndicator( void );
PDRect getCrankIndicatorBounds( int xOffset, int yOffset );
#endif /* crank_indicator_h */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment