Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create minimal SDL2 example #69

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.