#define SDL_MAIN_USE_CALLBACKS #include #include #include #define CLAY_IMPLEMENTATION #include "../include/clay.h" #include "clay_renderer_SDL3.c" #include "../include/shared_layout.c" #include "../include/uart_func.c" #include typedef struct app_state { SDL_Window *window; Clay_SDL3RendererData rendererData; Uint64 NOW; Uint64 LAST; double deltaTime; } AppState; uart_data uart_message_data; static Clay_Dimensions SDL_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) { TTF_Font **fonts = userData; TTF_Font *font = fonts[config->fontId]; int width, height; TTF_SetFontSize(font, config->fontSize); if (!TTF_GetStringSize(font, text.chars, text.length, &width, &height)) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to measure text: %s", SDL_GetError()); } return (Clay_Dimensions) { (float) width, (float) height }; } void HandleClayErrors(const Clay_ErrorData errorData) { printf("Error: %s\n", errorData.errorText.chars); } SDL_AppResult SDL_AppInit(void **appstate, const int argc, char *argv[]) { (void) argc; (void) argv; uart_message_data.serial_port = open_uart_port("/dev/ttyUSB0"); if (uart_message_data.serial_port < 0) { return SDL_APP_FAILURE; } if (!TTF_Init()) { return SDL_APP_FAILURE; } AppState *state = SDL_calloc(1, sizeof(AppState)); if (!state) { return SDL_APP_FAILURE; } *appstate = state; if (!SDL_CreateWindowAndRenderer("Clay Test", 640, 480, 0, &state->window, &state->rendererData.renderer)) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create engine from renderer: %s", SDL_GetError()); return SDL_APP_FAILURE; } SDL_SetWindowResizable(state->window, true); SDL_SetWindowMinimumSize(state->window, 640, 480); state->rendererData.textEngine = TTF_CreateRendererTextEngine(state->rendererData.renderer); if (!state->rendererData.textEngine) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create text engine from renderer: %s", SDL_GetError()); return SDL_APP_FAILURE; } state->rendererData.fonts = SDL_calloc(2, sizeof(TTF_Font *)); if (!state->rendererData.fonts) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to allocate memory for the font array: %s", SDL_GetError()); } FILE* FontFile = fopen("resources/JetBrainsMonoNerdFont-Regular.ttf", "rb"); fseek(FontFile, 0, SEEK_END); const long FontSize = ftell(FontFile); fseek(FontFile, 0, SEEK_SET); char* FontBuffer = malloc(FontSize + 1); const size_t bytesRead = fread(FontBuffer, 1, FontSize, FontFile); fclose(FontFile); SDL_IOStream* file_rw = SDL_IOFromConstMem(FontBuffer, bytesRead); TTF_Font* font = TTF_OpenFontIO(file_rw, true, 12); if (!font) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load font: %s", SDL_GetError()); return SDL_APP_FAILURE; } state->rendererData.fonts[MAIN_FONT] = font; /* Initialise Clay */ const uint64_t totalMemorySize = Clay_MinMemorySize(); const Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, SDL_malloc(totalMemorySize)); /* Initialise text buffers */ uart_message_data.buffer.length = 20; uart_message_data.buffer.chars = malloc(uart_message_data.buffer.length * sizeof(char)); modal_message.chars = uart_message_data.buffer.chars; modal_message.length = 0; int width, height; SDL_GetWindowSize(state->window, &width, &height); Clay_Initialize(clayMemory, (Clay_Dimensions) { (float) width, (float) height }, (Clay_ErrorHandler) { HandleClayErrors }); Clay_SetMeasureTextFunction(SDL_MeasureText, state->rendererData.fonts); state->NOW = SDL_GetPerformanceCounter(); *appstate = state; return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void *appstate) { AppState *state = appstate; Clay_RenderCommandArray render_commands = Clay_CreateLayout(&uart_message_data); SDL_SetRenderDrawColor(state->rendererData.renderer, 0, 0, 0, 255); SDL_RenderClear(state->rendererData.renderer); SDL_Clay_RenderClayCommands(&state->rendererData, &render_commands); SDL_RenderPresent(state->rendererData.renderer); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { const AppState *state = appstate; SDL_AppResult ret_val = SDL_APP_CONTINUE; switch (event->type) { case SDL_EVENT_QUIT: ret_val = SDL_APP_SUCCESS; break; case SDL_EVENT_KEY_UP: switch (event->key.scancode) { #ifndef NDEBUG case SDL_SCANCODE_D: Clay_SetDebugModeEnabled(!Clay_IsDebugModeEnabled()); break; #endif case SDL_SCANCODE_Q: ret_val = SDL_APP_SUCCESS; break; default: break; } break; case SDL_EVENT_WINDOW_RESIZED: Clay_SetLayoutDimensions((Clay_Dimensions) { (float) event->window.data1, (float) event->window.data2 }); break; case SDL_EVENT_MOUSE_MOTION: Clay_SetPointerState((Clay_Vector2) { event->motion.x, event->motion.y }, event->motion.state & SDL_BUTTON_LMASK); break; case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: Clay_SetPointerState((Clay_Vector2) { event->motion.x, event->motion.y }, event->button.down); break; #ifndef NDEBUG case SDL_EVENT_MOUSE_WHEEL: Clay_UpdateScrollContainers(true, (Clay_Vector2) {event->wheel.x, event->wheel.y}, state->deltaTime); #endif default: break; } return ret_val; } void SDL_AppQuit(void *appstate, SDL_AppResult result) { (void) result; if (result != SDL_APP_SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Application failed to run"); } AppState *state = appstate; if (state) { if (state->rendererData.renderer) SDL_DestroyRenderer(state->rendererData.renderer); if (state->window) SDL_DestroyWindow(state->window); if (state->rendererData.fonts) { for (size_t i = 0; i < sizeof(state->rendererData.fonts) / sizeof(*state->rendererData.fonts); ++i) { TTF_CloseFont(state->rendererData.fonts[i]); } SDL_free(state->rendererData.fonts); } if (state->rendererData.textEngine) TTF_DestroyRendererTextEngine(state->rendererData.textEngine); SDL_free(state); } TTF_Quit(); }