Skip to content

Commit

Permalink
Add minimal SDL2 example
Browse files Browse the repository at this point in the history
  • Loading branch information
juniorrantila committed Dec 21, 2024
1 parent 0602565 commit b5b47b2
Show file tree
Hide file tree
Showing 3 changed files with 261 additions and 0 deletions.
41 changes: 41 additions & 0 deletions examples/minimal-sdl2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.27)
project(minimal_sdl2 C)
set(CMAKE_C_STANDARD 99)

set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)

include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)

FetchContent_Declare(
SDL2
GIT_REPOSITORY "https://github.com/libsdl-org/SDL.git"
GIT_TAG "release-2.30.10"
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(SDL2)

FetchContent_Declare(
SDL2_ttf
GIT_REPOSITORY "https://github.com/libsdl-org/SDL_ttf.git"
GIT_TAG "release-2.22.0"
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(SDL2_ttf)

add_executable(minimal_sdl2 main.c)

target_compile_options(minimal_sdl2 PUBLIC)
target_include_directories(minimal_sdl2 PUBLIC .)

target_link_libraries(minimal_sdl2 PUBLIC SDL2 SDL2_ttf)
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Werror -DCLAY_DEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")

add_custom_command(
TARGET minimal_sdl2 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_CURRENT_BINARY_DIR}/resources)
220 changes: 220 additions & 0 deletions examples/minimal-sdl2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#define CLAY_IMPLEMENTATION
#include "../../clay.h"

#include <SDL.h>
#include <SDL_ttf.h>

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>


static const uint32_t FONT_ID_BODY_24 = 0;
static const Clay_Color COLOR_ORANGE = (Clay_Color) {225, 138, 50, 255};
static const Clay_Color COLOR_BLUE = (Clay_Color) {111, 173, 162, 255};
static const Clay_Color COLOR_LIGHT = (Clay_Color) {224, 215, 210, 255};


static void Label(Clay_String text) {
CLAY(CLAY_LAYOUT({ .padding = {16, 8} }),
CLAY_RECTANGLE({ .color = Clay_Hovered() ? COLOR_BLUE : COLOR_ORANGE })
) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
.fontId = FONT_ID_BODY_24,
.fontSize = 24,
.textColor = { 255, 255, 255, 255 },
}));
}
}


static Clay_RenderCommandArray CreateLayout() {
Clay_BeginLayout();
CLAY(CLAY_ID("MainContent"),
CLAY_LAYOUT({
.sizing = {
.width = CLAY_SIZING_GROW(),
.height = CLAY_SIZING_GROW(),
},
.childAlignment = {
.x = CLAY_ALIGN_X_CENTER,
.y = CLAY_ALIGN_Y_CENTER,
}
}),
CLAY_RECTANGLE({
.color = COLOR_LIGHT,
})
) {
Label(CLAY_STRING("Hello, World!"));
}
return Clay_EndLayout();
}


typedef struct
{
uint32_t fontId;
TTF_Font *font;
} Font;
static Font fonts[1];


static Clay_Dimensions measureText(Clay_String *text, Clay_TextElementConfig *config);
static void render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands);


int main(void) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "Error: could not initialize SDL: %s\n", SDL_GetError());
return 1;
}
if (TTF_Init() < 0) {
fprintf(stderr, "Error: could not initialize TTF: %s\n", TTF_GetError());
return 1;
}

TTF_Font *font = TTF_OpenFont("resources/Roboto-Regular.ttf", 24);
if (!font) {
fprintf(stderr, "Error: could not load font: %s\n", TTF_GetError());
return 1;
}
fonts[FONT_ID_BODY_24] = (Font) {
.font = font,
.fontId = FONT_ID_BODY_24,
};

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
if (SDL_CreateWindowAndRenderer(800, 600, SDL_WINDOW_RESIZABLE, &window, &renderer) < 0) {
fprintf(stderr, "Error: could not create window and renderer: %s", SDL_GetError());
}

uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = (Clay_Arena) {
.label = CLAY_STRING("Clay Memory Arena"),
.memory = malloc(totalMemorySize),
.capacity = totalMemorySize,
};

Clay_SetMeasureTextFunction(measureText);

int windowWidth = 0;
int windowHeight = 0;
SDL_GetWindowSize(window, &windowWidth, &windowHeight);
Clay_Initialize(clayMemory, (Clay_Dimensions) { windowWidth, windowHeight });

while (true) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT: goto quit;
}
}
int mouseX = 0;
int mouseY = 0;
Uint32 mouseState = SDL_GetMouseState(&mouseX, &mouseY);
Clay_Vector2 mousePosition = (Clay_Vector2){ mouseX, mouseY };
Clay_SetPointerState((Clay_Vector2){ mouseX, mouseY }, mouseState & SDL_BUTTON(1));

SDL_GetWindowSize(window, &windowWidth, &windowHeight);
Clay_SetLayoutDimensions((Clay_Dimensions) { windowWidth, windowHeight });

Clay_RenderCommandArray renderCommands = CreateLayout();
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);

render(renderer, renderCommands);

SDL_RenderPresent(renderer);
}
quit:

SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
SDL_Quit();
return 0;
}


static Clay_Dimensions measureText(Clay_String *text, Clay_TextElementConfig *config)
{
TTF_Font *font = fonts[config->fontId].font;
char *chars = (char *)calloc(text->length + 1, 1);
memcpy(chars, text->chars, text->length);
int width = 0;
int height = 0;
if (TTF_SizeUTF8(font, chars, &width, &height) < 0) {
fprintf(stderr, "Error: could not measure text: %s\n", TTF_GetError());
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
exit(1);
}
free(chars);
return (Clay_Dimensions) {
.width = width,
.height = height,
};
}


static void render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands)
{
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_RectangleElementConfig *config = renderCommand->config.rectangleElementConfig;
Clay_Color color = config->color;
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_FRect rect = (SDL_FRect) {
.x = boundingBox.x,
.y = boundingBox.y,
.w = boundingBox.width,
.h = boundingBox.height,
};
SDL_RenderFillRectF(renderer, &rect);
break;
}
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
Clay_TextElementConfig *config = renderCommand->config.textElementConfig;
Clay_String text = renderCommand->text;
char *cloned = (char *)calloc(text.length + 1, 1);
memcpy(cloned, text.chars, text.length);
TTF_Font* font = fonts[config->fontId].font;
SDL_Surface *surface = TTF_RenderUTF8_Blended(font, cloned, (SDL_Color) {
.r = config->textColor.r,
.g = config->textColor.g,
.b = config->textColor.b,
.a = config->textColor.a,
});
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);

SDL_Rect destination = (SDL_Rect){
.x = boundingBox.x,
.y = boundingBox.y,
.w = boundingBox.width,
.h = boundingBox.height,
};
SDL_RenderCopy(renderer, texture, NULL, &destination);

SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);
free(cloned);
break;
}
default: {
fprintf(stderr, "Error: unhandled render command: %d\n", renderCommand->commandType);
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
exit(1);
}
}
}
}
Binary file not shown.

0 comments on commit b5b47b2

Please sign in to comment.