From b06f5ec4001e8b0e38430c947cbf25110f05f6d9 Mon Sep 17 00:00:00 2001 From: Matthew Jennings Date: Mon, 5 May 2025 20:33:55 +0300 Subject: [PATCH] updated to simulate setup with multiple fonts --- examples/playdate-project-example/main.c | 26 ++++++------ renderers/playdate/clay_renderer_playdate.c | 44 ++++++++++----------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/examples/playdate-project-example/main.c b/examples/playdate-project-example/main.c index e0a487b..7f47e26 100644 --- a/examples/playdate-project-example/main.c +++ b/examples/playdate-project-example/main.c @@ -1,5 +1,6 @@ #include "pd_api.h" +#include "pd_api/pd_api_gfx.h" #define CLAY_IMPLEMENTATION #include "../../clay.h" @@ -7,28 +8,27 @@ #include "clay-video-demo-playdate.c" static int update(void *userdata); -const char *fontpath = "/System/Fonts/Asheville-Sans-14-Bold.pft"; -LCDFont *font = NULL; +const char *fontPath = "/System/Fonts/Asheville-Sans-14-Bold.pft"; void HandleClayErrors(Clay_ErrorData errorData) {} struct TextUserData { - LCDFont *font; + LCDFont *font[1]; PlaydateAPI *pd; }; -static struct TextUserData testUserData = {.font = NULL, .pd = NULL}; +static struct TextUserData textUserData = {.font = {NULL, NULL}, .pd = NULL}; static Clay_Dimensions PlayDate_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) { struct TextUserData *textUserData = userData; int width = textUserData->pd->graphics->getTextWidth( - textUserData->font, + textUserData->font[config->fontId], text.chars, utf8_count_codepoints(text.chars, text.length), kUTF8Encoding, 0 ); - int height = textUserData->pd->graphics->getFontHeight(textUserData->font); + int height = textUserData->pd->graphics->getFontHeight(textUserData->font[config->fontId]); return (Clay_Dimensions){ .width = (float)width, .height = (float)height, @@ -42,14 +42,13 @@ int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t eventArg) { if (event == kEventInit) { const char *err; - font = pd->graphics->loadFont(fontpath, &err); + textUserData.font[0] = pd->graphics->loadFont(fontPath, &err); - if (font == NULL) { - pd->system->error("%s:%i Couldn't load font %s: %s", __FILE__, __LINE__, fontpath, err); + if (textUserData.font[0] == NULL) { + pd->system->error("%s:%i Couldn't load font %s: %s", __FILE__, __LINE__, fontPath, err); } - testUserData.pd = pd; - testUserData.font = font; + textUserData.pd = pd; pd->system->setUpdateCallback(update, pd); uint64_t totalMemorySize = Clay_MinMemorySize(); @@ -59,7 +58,7 @@ int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t eventArg) (Clay_Dimensions){(float)pd->display->getWidth(), (float)pd->display->getHeight()}, (Clay_ErrorHandler){HandleClayErrors} ); - Clay_SetMeasureTextFunction(PlayDate_MeasureText, &testUserData); + Clay_SetMeasureTextFunction(PlayDate_MeasureText, &textUserData); ClayVideoDemo_Initialize(); } @@ -81,7 +80,6 @@ static int update(void *userdata) { } pd->graphics->clear(kColorWhite); - pd->graphics->setFont(font); // A bit hacky, setting the cursor on to the document view so it can be // scrolled.. @@ -97,7 +95,7 @@ static int update(void *userdata) { ); Clay_RenderCommandArray renderCommands = ClayVideoDemo_CreateLayout(selectedDocumentIndex); - Clay_Playdate_Render(pd, renderCommands, font); + Clay_Playdate_Render(pd, renderCommands, textUserData.font); return 1; } diff --git a/renderers/playdate/clay_renderer_playdate.c b/renderers/playdate/clay_renderer_playdate.c index 7e17b62..a513a72 100644 --- a/renderers/playdate/clay_renderer_playdate.c +++ b/renderers/playdate/clay_renderer_playdate.c @@ -1,16 +1,15 @@ -#include "../../clay.h" #include "pd_api.h" -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#include "../../clay.h" -struct Rect { +struct Clay_Playdate_Rect { float x; float y; float w; float h; }; +// Playdate drawText function expects the number of codepoints to draw, not byte length static size_t utf8_count_codepoints(const char *str, size_t byte_len) { size_t count = 0; size_t i = 0; @@ -27,38 +26,37 @@ static size_t utf8_count_codepoints(const char *str, size_t byte_len) { 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. +// TODO: Convert to grayscale and then map the grayscale value to different dithering patterns static LCDColor clayColorToLCDColor(Clay_Color color) { - // Convert the RGB to grayscale using the standard luminance formula - unsigned char grayscale_value = (unsigned char)(0.299 * color.r + 0.587 * color.g + 0.114 * color.b); - - if (grayscale_value > 128) { + if (color.r > 0 || color.g > 0 || color.b > 0) { return kColorWhite; } return kColorBlack; } static LCDBitmapDrawMode clayColorToDrawMode(Clay_Color color) { - - if (color.r == 255 && color.g == 255 && color.b == 255) { + if (color.r > 0 || color.g > 0 || color.b > 0) { return kDrawModeFillWhite; } return kDrawModeCopy; } -static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray renderCommands, LCDFont *fonts) { - +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; - struct Rect rect = (struct Rect){ + struct Clay_Playdate_Rect rect = (struct Clay_Playdate_Rect){ .x = boundingBox.x, .y = boundingBox.y, .w = boundingBox.width, .h = boundingBox.height, }; + // TODO: support different radius for each corner like clay API allows if (config->cornerRadius.topLeft > 0) { pd->graphics->fillRoundRect( rect.x, rect.y, rect.w, rect.h, @@ -66,18 +64,18 @@ static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray render clayColorToLCDColor(config->backgroundColor) ); } else { - pd->graphics->fillRect(rect.x, rect.y, rect.w, rect.h, - clayColorToLCDColor(config->backgroundColor)); + pd->graphics->fillRect( + rect.x, rect.y, rect.w, rect.h, + clayColorToLCDColor(config->backgroundColor) + ); } break; } case CLAY_RENDER_COMMAND_TYPE_TEXT: { Clay_TextRenderData *config = &renderCommand->renderData.text; - // LCDFont *font = fonts[config->fontId]; - // TODO: support loading more than 1 font and use the fonts that clay - // layout has.. - LCDFont *font = fonts; - struct Rect destination = (struct Rect){ + LCDFont *font = fonts[config->fontId]; + pd->graphics->setFont(font); + struct Clay_Playdate_Rect destination = (struct Clay_Playdate_Rect){ .x = boundingBox.x, .y = boundingBox.y, .w = boundingBox.width, @@ -98,7 +96,7 @@ static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray render break; } case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: { - struct Rect currentClippingRectangle = (struct Rect){ + struct Clay_Playdate_Rect currentClippingRectangle = (struct Clay_Playdate_Rect){ .x = boundingBox.x, .y = boundingBox.y, .w = boundingBox.width, @@ -117,7 +115,7 @@ static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray render case CLAY_RENDER_COMMAND_TYPE_IMAGE: { Clay_ImageRenderData *config = &renderCommand->renderData.image; LCDBitmap *texture = config->imageData; - struct Rect destination = (struct Rect){ + struct Clay_Playdate_Rect destination = (struct Clay_Playdate_Rect){ .x = boundingBox.x, .y = boundingBox.y, .w = boundingBox.width, @@ -128,7 +126,7 @@ static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray render } case CLAY_RENDER_COMMAND_TYPE_BORDER: { Clay_BorderRenderData *config = &renderCommand->renderData.border; - struct Rect rect = (struct Rect){ + struct Clay_Playdate_Rect rect = (struct Clay_Playdate_Rect){ .x = boundingBox.x, .y = boundingBox.y, .w = boundingBox.width,