mirror of
https://github.com/nicbarker/clay.git
synced 2026-02-06 12:48:49 +00:00
[Renderers/Playdate] Playdate console example (#404)
This commit is contained in:
parent
eb1d85f2a6
commit
e2f94f17f6
9 changed files with 845 additions and 0 deletions
273
renderers/playdate/clay_renderer_playdate.c
Normal file
273
renderers/playdate/clay_renderer_playdate.c
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
#include "pd_api.h"
|
||||
#include "../../clay.h"
|
||||
|
||||
// Playdate drawText function expects the number of codepoints to draw, not byte length
|
||||
static size_t Clay_Playdate_CountUtf8Codepoints(const char *str, size_t byteLen) {
|
||||
size_t count = 0;
|
||||
size_t i = 0;
|
||||
while (i < byteLen) {
|
||||
uint8_t c = (uint8_t)str[i];
|
||||
if ((c & 0xC0) != 0x80) {
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// As the playdate can only display black and white, we need to resolve Clay_color to either black or white
|
||||
// for both color and draw mode.
|
||||
static LCDColor clayColorToLCDColor(Clay_Color color) {
|
||||
if (color.r > 0 || color.g > 0 || color.b > 0) {
|
||||
return kColorWhite;
|
||||
}
|
||||
return kColorBlack;
|
||||
}
|
||||
|
||||
static LCDBitmapDrawMode clayColorToDrawMode(Clay_Color color) {
|
||||
if (color.r > 0 || color.g > 0 || color.b > 0) {
|
||||
return kDrawModeFillWhite;
|
||||
}
|
||||
return kDrawModeCopy;
|
||||
}
|
||||
|
||||
static float clampCornerRadius(float yAxisSize, float radius) {
|
||||
if (radius < 1.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (radius > yAxisSize / 2) {
|
||||
return yAxisSize / 2;
|
||||
}
|
||||
// Trying to draw a 2x2 ellipse seems to result in just a dot, so if
|
||||
// there is a corner radius at minimum it must be 2
|
||||
return CLAY__MAX(2, radius);
|
||||
}
|
||||
|
||||
static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray renderCommands, LCDFont **fonts) {
|
||||
for (uint32_t i = 0; i < renderCommands.length; i++) {
|
||||
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, i);
|
||||
Clay_BoundingBox boundingBox = renderCommand->boundingBox;
|
||||
|
||||
switch (renderCommand->commandType) {
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
Clay_RectangleRenderData *config = &renderCommand->renderData.rectangle;
|
||||
|
||||
float radiusTl = clampCornerRadius(boundingBox.height, config->cornerRadius.topLeft);
|
||||
float radiusTr = clampCornerRadius(boundingBox.height, config->cornerRadius.topRight);
|
||||
float radiusBl = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomLeft);
|
||||
float radiusBr = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomRight);
|
||||
|
||||
pd->graphics->fillEllipse(
|
||||
boundingBox.x, boundingBox.y,
|
||||
radiusTl * 2, radiusTl * 2,
|
||||
-90.0f, 0.0f,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
pd->graphics->fillEllipse(
|
||||
boundingBox.x + boundingBox.width - radiusTr * 2, boundingBox.y,
|
||||
radiusTr * 2, radiusTr * 2,
|
||||
0.0f, 90.0f,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
pd->graphics->fillEllipse(
|
||||
boundingBox.x + boundingBox.width - radiusBr * 2,
|
||||
boundingBox.y + boundingBox.height - radiusBr * 2,
|
||||
radiusBr * 2, radiusBr * 2,
|
||||
90.0f, 180.0f,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
pd->graphics->fillEllipse(
|
||||
boundingBox.x,
|
||||
boundingBox.y + boundingBox.height - radiusBl * 2,
|
||||
radiusBl * 2, radiusBl * 2,
|
||||
180.0f, 270.0f,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
// Top chunk
|
||||
pd->graphics->fillRect(
|
||||
boundingBox.x + radiusTl, boundingBox.y,
|
||||
boundingBox.width - radiusTl - radiusTr,
|
||||
CLAY__MAX(radiusTl, radiusTr),
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
// bottom chunk
|
||||
int bottomChunkHeight = CLAY__MAX(radiusBl, radiusBr);
|
||||
pd->graphics->fillRect(
|
||||
boundingBox.x + radiusBl, boundingBox.y + boundingBox.height - bottomChunkHeight,
|
||||
boundingBox.width - radiusBl - radiusBr,
|
||||
bottomChunkHeight,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
// Middle chunk
|
||||
int middleChunkHeight = boundingBox.height - CLAY__MIN(radiusBr, radiusBl) - CLAY__MIN(radiusTr, radiusTl);
|
||||
pd->graphics->fillRect(
|
||||
boundingBox.x + CLAY__MIN(radiusTl, radiusBl), boundingBox.y + CLAY__MIN(radiusTr, radiusTl),
|
||||
boundingBox.width - radiusBl - radiusBr,
|
||||
middleChunkHeight,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
// Left chunk
|
||||
int leftChunkHeight = boundingBox.height - radiusTl - radiusBl;
|
||||
int leftChunkWidth = CLAY__MAX(radiusTl, radiusBl);
|
||||
pd->graphics->fillRect(
|
||||
boundingBox.x, boundingBox.y + radiusTl,
|
||||
leftChunkWidth,
|
||||
leftChunkHeight,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
|
||||
// Right chunk
|
||||
int rightChunkHeight = boundingBox.height - radiusTr - radiusBr;
|
||||
int rightChunkWidth = CLAY__MAX(radiusTr, radiusBr);
|
||||
pd->graphics->fillRect(
|
||||
boundingBox.x + boundingBox.width - rightChunkWidth, boundingBox.y + radiusTr,
|
||||
rightChunkWidth,
|
||||
rightChunkHeight,
|
||||
clayColorToLCDColor(config->backgroundColor)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||
Clay_TextRenderData *config = &renderCommand->renderData.text;
|
||||
LCDFont *font = fonts[config->fontId];
|
||||
pd->graphics->setFont(font);
|
||||
pd->graphics->setDrawMode(clayColorToDrawMode(config->textColor));
|
||||
pd->graphics->drawText(
|
||||
renderCommand->renderData.text.stringContents.chars,
|
||||
Clay_Playdate_CountUtf8Codepoints(
|
||||
renderCommand->renderData.text.stringContents.chars,
|
||||
renderCommand->renderData.text.stringContents.length
|
||||
),
|
||||
kUTF8Encoding,
|
||||
boundingBox.x,
|
||||
boundingBox.y
|
||||
);
|
||||
pd->graphics->setDrawMode(kDrawModeCopy);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
|
||||
pd->graphics->setClipRect(
|
||||
boundingBox.x,boundingBox.y,
|
||||
boundingBox.width, boundingBox.height
|
||||
);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
|
||||
pd->graphics->clearClipRect();
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||
Clay_ImageRenderData *config = &renderCommand->renderData.image;
|
||||
LCDBitmap *texture = config->imageData;
|
||||
int texWidth;
|
||||
int texHeight;
|
||||
pd->graphics->getBitmapData(texture, &texWidth, &texHeight, NULL, NULL, NULL);
|
||||
if (texWidth != boundingBox.width || texHeight != boundingBox.height) {
|
||||
pd->graphics->drawScaledBitmap(
|
||||
texture,
|
||||
boundingBox.x, boundingBox.y,
|
||||
boundingBox.width / texWidth,
|
||||
boundingBox.height / texHeight
|
||||
);
|
||||
} else {
|
||||
pd->graphics->drawBitmap(texture, boundingBox.x, boundingBox.y, kBitmapUnflipped);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
|
||||
Clay_BorderRenderData *config = &renderCommand->renderData.border;
|
||||
|
||||
float radiusTl = clampCornerRadius(boundingBox.height, config->cornerRadius.topLeft);
|
||||
float radiusTr = clampCornerRadius(boundingBox.height, config->cornerRadius.topRight);
|
||||
float radiusBl = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomLeft);
|
||||
float radiusBr = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomRight);
|
||||
|
||||
if (config->width.top > 0) {
|
||||
pd->graphics->drawEllipse(
|
||||
boundingBox.x, boundingBox.y,
|
||||
radiusTl * 2, radiusTl * 2,
|
||||
config->width.top,
|
||||
-90.0f, 0.0f,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
|
||||
pd->graphics->drawLine(
|
||||
boundingBox.x + radiusTl, boundingBox.y,
|
||||
boundingBox.x + boundingBox.width - radiusTr - config->width.right, boundingBox.y,
|
||||
config->width.top,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
|
||||
pd->graphics->drawEllipse(
|
||||
boundingBox.x + boundingBox.width - radiusTr * 2, boundingBox.y,
|
||||
radiusTr * 2, radiusTr * 2,
|
||||
config->width.top,
|
||||
0.0f, 90.0f,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
}
|
||||
|
||||
if (config->width.right > 0 && radiusTr + radiusBr <= boundingBox.height) {
|
||||
pd->graphics->drawLine(
|
||||
boundingBox.x + boundingBox.width - config->width.right,
|
||||
boundingBox.y + radiusTr,
|
||||
boundingBox.x + boundingBox.width - config->width.right,
|
||||
boundingBox.y + boundingBox.height - radiusBr - config->width.bottom,
|
||||
config->width.right,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
}
|
||||
|
||||
if (config->width.bottom > 0) {
|
||||
pd->graphics->drawEllipse(
|
||||
boundingBox.x + boundingBox.width - radiusBr * 2,
|
||||
boundingBox.y + boundingBox.height - radiusBr * 2,
|
||||
radiusBr * 2, radiusBr * 2,
|
||||
config->width.bottom,
|
||||
90.0f, 180.0f,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
|
||||
pd->graphics->drawLine(
|
||||
boundingBox.x + boundingBox.width - radiusBr - config->width.right,
|
||||
boundingBox.y + boundingBox.height - config->width.bottom,
|
||||
boundingBox.x + radiusBl,
|
||||
boundingBox.y + boundingBox.height - config->width.bottom,
|
||||
config->width.bottom,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
|
||||
pd->graphics->drawEllipse(
|
||||
boundingBox.x,
|
||||
boundingBox.y + boundingBox.height - radiusBl * 2,
|
||||
radiusBl * 2, radiusBl * 2,
|
||||
config->width.bottom,
|
||||
180.0f, 270.0f,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
}
|
||||
|
||||
if (config->width.left > 0 && radiusBl + radiusTl < boundingBox.height) {
|
||||
pd->graphics->drawLine(
|
||||
boundingBox.x, boundingBox.y + boundingBox.height - radiusBl - config->width.bottom,
|
||||
boundingBox.x, boundingBox.y + radiusTl,
|
||||
config->width.left,
|
||||
clayColorToLCDColor(config->color)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pd->system->logToConsole("Error: unhandled render command: %d\n", renderCommand->commandType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue