Compare commits

...

18 Commits

Author SHA1 Message Date
AICDG
90efdc280f
Merge e81e1ad08f into 9b2d585499 2025-01-21 14:57:34 +08:00
AICDG
e81e1ad08f
Merge branch 'main' into main 2025-01-21 14:57:31 +08:00
Nic Barker
9b2d585499 Update odin and wasm bindings 2025-01-21 19:14:22 +13:00
Nic Barker
81589ad29b [Core] Fix layout bug in SIZING_PERCENT 2025-01-21 19:11:33 +13:00
Nic Barker
16f894bb4d Fix incorrect use of corner radius 2025-01-21 18:32:33 +13:00
Timothy Hoyt
9f07f5aac8
fixed video demo padding (#205) 2025-01-21 18:31:48 +13:00
Nic Barker
01d3ab127f Update odin bindings for new text measurement API
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
2025-01-20 11:39:59 +13:00
Nic Barker
326325ffaf
[Core] Convert measureText pointer to value string slice (#214) 2025-01-20 11:27:22 +13:00
Daniel Collin
e8025cc254
SetMesureText and SetQueryScrollOffset takes userData (#212) 2025-01-20 10:59:02 +13:00
Linus Probert
8e7e30dda6
[Renderers/SDL3] Adds an example using SDL3 as a renderer (#107)
Some checks are pending
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Waiting to run
Co-authored-by: Nic Barker <contact+github@nicbarker.com>
2025-01-19 14:35:41 +13:00
AICDG
356724ed20
Merge branch 'main' into main 2025-01-13 18:10:59 +08:00
AICDG
337fc1dc92
Merge branch 'main' into main 2025-01-10 22:28:01 +08:00
AICDG
9af4b6384d
Update CMakeLists.txt 2025-01-10 22:23:31 +08:00
AICDG
faf2f926b8
Merge branch 'nicbarker:main' into main 2025-01-07 14:22:04 +08:00
AICDG
5fea1e748d
Merge branch 'main' into main 2024-12-28 19:14:06 +08:00
AICDG
13402c62ab
Merge branch 'main' into main 2024-12-27 11:00:41 +08:00
THISISAGOODNAME
9b8fd94170 update imgui demo 2024-12-27 10:59:17 +08:00
THISISAGOODNAME
b2e7eb2ee6 Create minimal ImDrawList example 2024-12-24 16:53:12 +08:00
29 changed files with 607 additions and 59 deletions

4
.gitignore vendored
View File

@ -1,5 +1,5 @@
cmake-build-debug/ cmake-build-*/
cmake-build-release/ build/
.DS_Store .DS_Store
.idea/ .idea/
node_modules/ node_modules/

View File

@ -3,12 +3,20 @@ project(clay)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if(APPLE)
enable_language(OBJC)
endif()
add_subdirectory("examples/cpp-project-example") add_subdirectory("examples/cpp-project-example")
add_subdirectory("examples/raylib-multi-context") add_subdirectory("examples/raylib-multi-context")
add_subdirectory("examples/raylib-sidebar-scrolling-container") add_subdirectory("examples/raylib-sidebar-scrolling-container")
# add_subdirectory("examples/cairo-pdf-rendering") Some issue with github actions populating cairo, disable for now # add_subdirectory("examples/cairo-pdf-rendering") Some issue with github actions populating cairo, disable for now
if(NOT MSVC) if(NOT MSVC)
add_subdirectory("examples/clay-official-website") add_subdirectory("examples/clay-official-website")
add_subdirectory("examples/introducing-clay-video-demo")
add_subdirectory("examples/SDL2-video-demo")
add_subdirectory("examples/minimal-imgui")
add_subdirectory("examples/SDL3-simple-demo")
endif() endif()
add_subdirectory("examples/introducing-clay-video-demo") add_subdirectory("examples/introducing-clay-video-demo")
add_subdirectory("examples/SDL2-video-demo") add_subdirectory("examples/SDL2-video-demo")

View File

@ -2,7 +2,7 @@ cp ../../clay.h clay.c;
# Intel Mac # Intel Mac
clang -c -DCLAY_IMPLEMENTATION -o clay.o -static -target x86_64-apple-darwin clay.c -fPIC && ar r clay-odin/macos/clay.a clay.o; clang -c -DCLAY_IMPLEMENTATION -o clay.o -static -target x86_64-apple-darwin clay.c -fPIC && ar r clay-odin/macos/clay.a clay.o;
# ARM Mac # ARM Mac
clang -c -DCLAY_IMPLEMENTATION -o clay.o -static clay.c -fPIC && ar r clay-odin/macos-arm64/clay.a clay.o; clang -c -DCLAY_IMPLEMENTATION -g -o clay.o -static clay.c -fPIC && ar r clay-odin/macos-arm64/clay.a clay.o;
# x64 Windows # x64 Windows
clang -c -DCLAY_IMPLEMENTATION -o clay-odin/windows/clay.lib -target x86_64-pc-windows-msvc -fuse-ld=llvm-lib -static clay.c; clang -c -DCLAY_IMPLEMENTATION -o clay-odin/windows/clay.lib -target x86_64-pc-windows-msvc -fuse-ld=llvm-lib -static clay.c;
# Linux # Linux

View File

@ -22,6 +22,12 @@ String :: struct {
chars: [^]c.char, chars: [^]c.char,
} }
StringSlice :: struct {
length: c.int32_t,
chars: [^]c.char,
baseChars: [^]c.char,
}
Vector2 :: [2]c.float Vector2 :: [2]c.float
Dimensions :: struct { Dimensions :: struct {
@ -305,7 +311,7 @@ foreign Clay {
PointerOver :: proc(id: ElementId) -> bool --- PointerOver :: proc(id: ElementId) -> bool ---
GetElementId :: proc(id: String) -> ElementId --- GetElementId :: proc(id: String) -> ElementId ---
GetScrollContainerData :: proc(id: ElementId) -> ScrollContainerData --- GetScrollContainerData :: proc(id: ElementId) -> ScrollContainerData ---
SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: ^String, config: ^TextElementConfig) -> Dimensions) --- SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: StringSlice, config: ^TextElementConfig, userData: uintptr) -> Dimensions, userData: uintptr) ---
RenderCommandArray_Get :: proc(array: ^ClayArray(RenderCommand), index: i32) -> ^RenderCommand --- RenderCommandArray_Get :: proc(array: ^ClayArray(RenderCommand), index: i32) -> ^RenderCommand ---
SetDebugModeEnabled :: proc(enabled: bool) --- SetDebugModeEnabled :: proc(enabled: bool) ---
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -493,8 +493,8 @@ main :: proc() {
minMemorySize: u32 = clay.MinMemorySize() minMemorySize: u32 = clay.MinMemorySize()
memory := make([^]u8, minMemorySize) memory := make([^]u8, minMemorySize)
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory) arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
clay.SetMeasureTextFunction(measureText)
clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler }) clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler })
clay.SetMeasureTextFunction(measureText, 0)
raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .WINDOW_HIGHDPI, .MSAA_4X_HINT}) raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .WINDOW_HIGHDPI, .MSAA_4X_HINT})
raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example") raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example")

View File

@ -16,7 +16,7 @@ clayColorToRaylibColor :: proc(color: clay.Color) -> raylib.Color {
raylibFonts := [10]RaylibFont{} raylibFonts := [10]RaylibFont{}
measureText :: proc "c" (text: ^clay.String, config: ^clay.TextElementConfig) -> clay.Dimensions { measureText :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: uintptr) -> clay.Dimensions {
// Measure string size for Font // Measure string size for Font
textSize: clay.Dimensions = {0, 0} textSize: clay.Dimensions = {0, 0}

50
clay.h
View File

@ -1,4 +1,4 @@
// VERSION: 0.11 // VERSION: 0.12
/* /*
NOTE: In order to use this library you must define NOTE: In order to use this library you must define
@ -191,6 +191,13 @@ CLAY__TYPEDEF(Clay__StringArray, struct {
Clay_String *internalArray; Clay_String *internalArray;
}); });
CLAY__TYPEDEF(Clay_StringSlice, struct {
int32_t length;
const char *chars;
// The source string / char* that this slice was derived from
const char *baseChars;
});
typedef struct Clay_Context Clay_Context; typedef struct Clay_Context Clay_Context;
CLAY__TYPEDEF(Clay_Arena, struct { CLAY__TYPEDEF(Clay_Arena, struct {
@ -527,8 +534,8 @@ bool Clay_Hovered(void);
void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData); void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData);
bool Clay_PointerOver(Clay_ElementId elementId); bool Clay_PointerOver(Clay_ElementId elementId);
Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id); Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config)); void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData), uintptr_t userData);
void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId)); void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, uintptr_t userData), uintptr_t userData);
Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index); Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
void Clay_SetDebugModeEnabled(bool enabled); void Clay_SetDebugModeEnabled(bool enabled);
bool Clay_IsDebugModeEnabled(void); bool Clay_IsDebugModeEnabled(void);
@ -1407,6 +1414,8 @@ struct Clay_Context {
uint32_t debugSelectedElementId; uint32_t debugSelectedElementId;
uint32_t generation; uint32_t generation;
uintptr_t arenaResetOffset; uintptr_t arenaResetOffset;
uintptr_t mesureTextUserData;
uintptr_t queryScrollOffsetUserData;
Clay_Arena internalArena; Clay_Arena internalArena;
// Layout Elements / Render Commands // Layout Elements / Render Commands
Clay_LayoutElementArray layoutElements; Clay_LayoutElementArray layoutElements;
@ -1480,11 +1489,11 @@ Clay_String Clay__WriteStringToCharBuffer(Clay__CharArray *buffer, Clay_String s
} }
#ifdef CLAY_WASM #ifdef CLAY_WASM
__attribute__((import_module("clay"), import_name("measureTextFunction"))) Clay_Dimensions Clay__MeasureText(Clay_String *text, Clay_TextElementConfig *config); __attribute__((import_module("clay"), import_name("measureTextFunction"))) Clay_Dimensions Clay__MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData);
__attribute__((import_module("clay"), import_name("queryScrollOffsetFunction"))) Clay_Vector2 Clay__QueryScrollOffset(uint32_t elementId); __attribute__((import_module("clay"), import_name("queryScrollOffsetFunction"))) Clay_Vector2 Clay__QueryScrollOffset(uint32_t elementId, uintptr_t userData);
#else #else
Clay_Dimensions (*Clay__MeasureText)(Clay_String *text, Clay_TextElementConfig *config); Clay_Dimensions (*Clay__MeasureText)(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData);
Clay_Vector2 (*Clay__QueryScrollOffset)(uint32_t elementId); Clay_Vector2 (*Clay__QueryScrollOffset)(uint32_t elementId, uintptr_t userData);
#endif #endif
Clay_LayoutElement* Clay__GetOpenLayoutElement(void) { Clay_LayoutElement* Clay__GetOpenLayoutElement(void) {
@ -1699,7 +1708,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
float lineWidth = 0; float lineWidth = 0;
float measuredWidth = 0; float measuredWidth = 0;
float measuredHeight = 0; float measuredHeight = 0;
float spaceWidth = Clay__MeasureText(&CLAY__SPACECHAR, config).width; float spaceWidth = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = 1, .chars = CLAY__SPACECHAR.chars, .baseChars = CLAY__SPACECHAR.chars }, config, context->mesureTextUserData).width;
Clay__MeasuredWord tempWord = { .next = -1 }; Clay__MeasuredWord tempWord = { .next = -1 };
Clay__MeasuredWord *previousWord = &tempWord; Clay__MeasuredWord *previousWord = &tempWord;
while (end < text->length) { while (end < text->length) {
@ -1716,8 +1725,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
char current = text->chars[end]; char current = text->chars[end];
if (current == ' ' || current == '\n') { if (current == ' ' || current == '\n') {
int32_t length = end - start; int32_t length = end - start;
Clay_String word = { .length = length, .chars = &text->chars[start] }; Clay_Dimensions dimensions = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = length, .chars = &text->chars[start], .baseChars = text->chars }, config, context->mesureTextUserData);
Clay_Dimensions dimensions = Clay__MeasureText(&word, config);
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height); measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
if (current == ' ') { if (current == ' ') {
dimensions.width += spaceWidth; dimensions.width += spaceWidth;
@ -1739,8 +1747,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
end++; end++;
} }
if (end - start > 0) { if (end - start > 0) {
Clay_String lastWord = { .length = end - start, .chars = &text->chars[start] }; Clay_Dimensions dimensions = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = end - start, .chars = &text->chars[start], .baseChars = text->chars }, config, context->mesureTextUserData);
Clay_Dimensions dimensions = Clay__MeasureText(&lastWord, config);
Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = start, .length = end - start, .width = dimensions.width, .next = -1 }, previousWord); Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = start, .length = end - start, .width = dimensions.width, .next = -1 }, previousWord);
lineWidth += dimensions.width; lineWidth += dimensions.width;
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height); measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
@ -1902,7 +1909,7 @@ void Clay__ElementPostConfiguration(void) {
scrollOffset = Clay__ScrollContainerDataInternalArray_Add(&context->scrollContainerDatas, CLAY__INIT(Clay__ScrollContainerDataInternal){.layoutElement = openLayoutElement, .scrollOrigin = {-1,-1}, .elementId = openLayoutElement->id, .openThisFrame = true}); scrollOffset = Clay__ScrollContainerDataInternalArray_Add(&context->scrollContainerDatas, CLAY__INIT(Clay__ScrollContainerDataInternal){.layoutElement = openLayoutElement, .scrollOrigin = {-1,-1}, .elementId = openLayoutElement->id, .openThisFrame = true});
} }
if (context->externalScrollHandlingEnabled) { if (context->externalScrollHandlingEnabled) {
scrollOffset->scrollPosition = Clay__QueryScrollOffset(scrollOffset->elementId); scrollOffset->scrollPosition = Clay__QueryScrollOffset(scrollOffset->elementId, context->queryScrollOffsetUserData);
} }
break; break;
} }
@ -2250,12 +2257,6 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
*childSize = (parentSize - totalPaddingAndChildGaps) * childSizing.size.percent; *childSize = (parentSize - totalPaddingAndChildGaps) * childSizing.size.percent;
if (sizingAlongAxis) { if (sizingAlongAxis) {
innerContentSize += *childSize; innerContentSize += *childSize;
if (childOffset > 0) {
innerContentSize += parentChildGap; // For children after index 0, the childAxisOffset is the gap from the previous child
totalPaddingAndChildGaps += parentChildGap;
}
} else {
innerContentSize = CLAY__MAX(*childSize, innerContentSize);
} }
} }
} }
@ -2476,9 +2477,6 @@ void Clay__CalculateFinalLayout() {
// DFS node has been visited, this is on the way back up to the root // DFS node has been visited, this is on the way back up to the root
Clay_LayoutConfig *layoutConfig = currentElement->layoutConfig; Clay_LayoutConfig *layoutConfig = currentElement->layoutConfig;
if (layoutConfig->sizing.height.type == CLAY__SIZING_TYPE_PERCENT) {
continue;
}
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
// Resize any parent containers that have grown in height along their non layout axis // Resize any parent containers that have grown in height along their non layout axis
for (int32_t j = 0; j < currentElement->childrenOrTextContent.children.length; ++j) { for (int32_t j = 0; j < currentElement->childrenOrTextContent.children.length; ++j) {
@ -3678,11 +3676,15 @@ Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset
} }
#ifndef CLAY_WASM #ifndef CLAY_WASM
void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config)) { void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData), uintptr_t userData) {
Clay_Context* context = Clay_GetCurrentContext();
Clay__MeasureText = measureTextFunction; Clay__MeasureText = measureTextFunction;
context->mesureTextUserData = userData;
} }
void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId)) { void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, uintptr_t userData), uintptr_t userData) {
Clay_Context* context = Clay_GetCurrentContext();
Clay__QueryScrollOffset = queryScrollOffsetFunction; Clay__QueryScrollOffset = queryScrollOffsetFunction;
context->queryScrollOffsetUserData = userData;
} }
#endif #endif

View File

@ -299,7 +299,10 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Error: could not load font: %s\n", TTF_GetError()); fprintf(stderr, "Error: could not load font: %s\n", TTF_GetError());
return 1; return 1;
} }
SDL2_fonts[FONT_ID_BODY_16] = (SDL2_Font) {
SDL2_Font fonts[1] = {};
fonts[FONT_ID_BODY_16] = (SDL2_Font) {
.fontId = FONT_ID_BODY_16, .fontId = FONT_ID_BODY_16,
.font = font, .font = font,
}; };
@ -315,12 +318,13 @@ int main(int argc, char *argv[]) {
uint64_t totalMemorySize = Clay_MinMemorySize(); uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize)); Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
Clay_SetMeasureTextFunction(SDL2_MeasureText);
int windowWidth = 0; int windowWidth = 0;
int windowHeight = 0; int windowHeight = 0;
SDL_GetWindowSize(window, &windowWidth, &windowHeight); SDL_GetWindowSize(window, &windowWidth, &windowHeight);
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)windowWidth, (float)windowHeight }, (Clay_ErrorHandler) { HandleClayErrors }); Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)windowWidth, (float)windowHeight }, (Clay_ErrorHandler) { HandleClayErrors });
Clay_SetMeasureTextFunction(SDL2_MeasureText, (uintptr_t)&fonts);
Uint64 NOW = SDL_GetPerformanceCounter(); Uint64 NOW = SDL_GetPerformanceCounter();
Uint64 LAST = 0; Uint64 LAST = 0;
double deltaTime = 0; double deltaTime = 0;
@ -361,7 +365,7 @@ int main(int argc, char *argv[]) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
Clay_SDL2_Render(renderer, renderCommands); Clay_SDL2_Render(renderer, renderCommands, fonts);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }

View File

@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.27)
# Project setup
project(clay_examples_sdl3_simple_demo C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
# Download SDL3
FetchContent_Declare(
SDL
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
GIT_TAG preview-3.1.6
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
message(STATUS "Using SDL via FetchContent")
FetchContent_MakeAvailable(SDL)
set_property(DIRECTORY "${sdl_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
# Download SDL_ttf
FetchContent_Declare(
SDL_ttf
GIT_REPOSITORY https://github.com/libsdl-org/SDL_ttf.git
GIT_TAG main # Slightly risky to use main branch, but it's the only one available
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
message(STATUS "Using SDL_ttf via FetchContent")
FetchContent_MakeAvailable(SDL_ttf)
set_property(DIRECTORY "${sdl_ttf_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
# Example executable
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} PRIVATE
SDL3::SDL3
SDL3_ttf::SDL3_ttf
)
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_CURRENT_BINARY_DIR}/resources
)

View File

@ -0,0 +1,185 @@
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#define CLAY_IMPLEMENTATION
#include "../../clay.h"
#include <stdio.h>
#include "../../renderers/SDL3/clay_renderer_SDL3.c"
static const Uint32 FONT_ID = 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};
typedef struct app_state {
SDL_Window *window;
SDL_Renderer *renderer;
} AppState;
static inline Clay_Dimensions SDL_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData)
{
TTF_Font *font = gFonts[config->fontId];
int width, height;
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 };
}
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({
.textColor = { 255, 255, 255, 255 },
.fontId = FONT_ID,
.fontSize = 24,
}));
}
}
static Clay_RenderCommandArray Clay_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,
},
.childGap = 10,
.padding = { 10, 10 },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}),
CLAY_RECTANGLE({
.color = COLOR_LIGHT,
})
) {
Label(CLAY_STRING("Button 1"));
Label(CLAY_STRING("Button 2"));
Label(CLAY_STRING("Button 3"));
}
return Clay_EndLayout();
}
void HandleClayErrors(Clay_ErrorData errorData) {
printf("%s", errorData.errorText.chars);
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
(void) argc;
(void) argv;
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 Demo", 640, 480, 0, &state->window, &state->renderer)) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create window and renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetWindowResizable(state->window, true);
TTF_Font *font = TTF_OpenFont("resources/Roboto-Regular.ttf", 24);
if (!font) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load font: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
gFonts[FONT_ID] = font;
/* Initialize Clay */
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = (Clay_Arena) {
.memory = SDL_malloc(totalMemorySize),
.capacity = totalMemorySize
};
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, 0);
*appstate = state;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
SDL_AppResult ret_val = SDL_APP_CONTINUE;
switch (event->type) {
case SDL_EVENT_QUIT:
ret_val = SDL_APP_SUCCESS;
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_LEFT);
break;
case SDL_EVENT_MOUSE_WHEEL:
Clay_UpdateScrollContainers(true, (Clay_Vector2) { event->motion.xrel, event->motion.yrel }, 0.01f);
break;
default:
break;
};
return ret_val;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
AppState *state = appstate;
Clay_RenderCommandArray render_commands = Clay_CreateLayout();
SDL_SetRenderDrawColor(state->renderer, 0, 0, 0, 255);
SDL_RenderClear(state->renderer);
SDL_RenderClayCommands(state->renderer, &render_commands);
SDL_RenderPresent(state->renderer);
return SDL_APP_CONTINUE;
}
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->renderer)
SDL_DestroyRenderer(state->renderer);
if (state->window)
SDL_DestroyWindow(state->window);
SDL_free(state);
}
TTF_Quit();
}

Binary file not shown.

View File

@ -314,7 +314,7 @@
const importObject = { const importObject = {
clay: { clay: {
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig) => { measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig, userData) => {
let stringLength = memoryDataView.getUint32(textToMeasure, true); let stringLength = memoryDataView.getUint32(textToMeasure, true);
let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true); let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true);
let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition); let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition);

View File

@ -314,7 +314,7 @@
const importObject = { const importObject = {
clay: { clay: {
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig) => { measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig, userData) => {
let stringLength = memoryDataView.getUint32(textToMeasure, true); let stringLength = memoryDataView.getUint32(textToMeasure, true);
let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true); let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true);
let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition); let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition);

View File

@ -84,7 +84,7 @@ int main(void) {
.width = GetScreenWidth(), .width = GetScreenWidth(),
.height = GetScreenHeight() .height = GetScreenHeight()
}, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published }, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published
Clay_SetMeasureTextFunction(Raylib_MeasureText); Clay_SetMeasureTextFunction(Raylib_MeasureText, 0);
Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) { Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) {
.font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400), .font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400),
.fontId = FONT_ID_BODY_16 .fontId = FONT_ID_BODY_16
@ -117,7 +117,7 @@ int main(void) {
Clay_RectangleElementConfig contentBackgroundConfig = { Clay_RectangleElementConfig contentBackgroundConfig = {
.color = { 90, 90, 90, 255 }, .color = { 90, 90, 90, 255 },
.cornerRadius = 8 .cornerRadius = CLAY_CORNER_RADIUS(8)
}; };
Clay_BeginLayout(); Clay_BeginLayout();
@ -141,7 +141,7 @@ int main(void) {
.height = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60),
.width = CLAY_SIZING_GROW(0) .width = CLAY_SIZING_GROW(0)
}, },
.padding = { 16 }, .padding = { 16, 16, 0, 0 },
.childGap = 16, .childGap = 16,
.childAlignment = { .childAlignment = {
.y = CLAY_ALIGN_Y_CENTER .y = CLAY_ALIGN_Y_CENTER
@ -151,10 +151,10 @@ int main(void) {
// Header buttons go here // Header buttons go here
CLAY( CLAY(
CLAY_ID("FileButton"), CLAY_ID("FileButton"),
CLAY_LAYOUT({ .padding = { 16, 8 }}), CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_RECTANGLE({ CLAY_RECTANGLE({
.color = { 140, 140, 140, 255 }, .color = { 140, 140, 140, 255 },
.cornerRadius = 5 .cornerRadius = CLAY_CORNER_RADIUS(5)
}) })
) { ) {
CLAY_TEXT(CLAY_STRING("File"), CLAY_TEXT_CONFIG({ CLAY_TEXT(CLAY_STRING("File"), CLAY_TEXT_CONFIG({
@ -177,7 +177,7 @@ int main(void) {
}, },
}), }),
CLAY_LAYOUT({ CLAY_LAYOUT({
.padding = {0, 8 } .padding = {0, 0, 8, 8 }
}) })
) { ) {
CLAY( CLAY(
@ -189,7 +189,7 @@ int main(void) {
}), }),
CLAY_RECTANGLE({ CLAY_RECTANGLE({
.color = { 40, 40, 40, 255 }, .color = { 40, 40, 40, 255 },
.cornerRadius = 8 .cornerRadius = CLAY_CORNER_RADIUS(8)
}) })
) { ) {
// Render dropdown items here // Render dropdown items here
@ -236,7 +236,7 @@ int main(void) {
CLAY_LAYOUT(sidebarButtonLayout), CLAY_LAYOUT(sidebarButtonLayout),
CLAY_RECTANGLE({ CLAY_RECTANGLE({
.color = { 120, 120, 120, 255 }, .color = { 120, 120, 120, 255 },
.cornerRadius = 8, .cornerRadius = CLAY_CORNER_RADIUS(8),
}) })
) { ) {
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({ CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
@ -252,7 +252,7 @@ int main(void) {
Clay_Hovered() Clay_Hovered()
? CLAY_RECTANGLE({ ? CLAY_RECTANGLE({
.color = { 120, 120, 120, 120 }, .color = { 120, 120, 120, 120 },
.cornerRadius = 8 .cornerRadius = CLAY_CORNER_RADIUS(8)
}) })
: 0 : 0
) { ) {

View File

@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.27)
project(minimal_imgui)
set(CMAKE_C_STANDARD 99)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
#add_subdirectory(3rd_party)
include(FetchContent)
FetchContent_Declare(
sokol
GIT_REPOSITORY "https://github.com/floooh/sokol.git"
GIT_COMMIT "789d97071d17cbab4e3835a0b0b8b379e98c114f"
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
)
FetchContent_Declare(
imgui
GIT_REPOSITORY "https://github.com/ocornut/imgui.git"
GIT_TAG "v1.91.6"
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(sokol imgui)
add_executable(minimal_imgui
main.cpp
${imgui_SOURCE_DIR}/imgui.cpp
${imgui_SOURCE_DIR}/imgui_demo.cpp
${imgui_SOURCE_DIR}/imgui_draw.cpp
${imgui_SOURCE_DIR}/imgui_tables.cpp
${imgui_SOURCE_DIR}/imgui_widgets.cpp
)
target_compile_options(minimal_imgui PUBLIC)
target_include_directories(minimal_imgui PUBLIC .)
#set(CMAKE_CXX_FLAGS_DEBUG "-DCLAY_DEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
target_include_directories(minimal_imgui PUBLIC ${sokol_SOURCE_DIR} ${imgui_SOURCE_DIR})
if(WIN32)
target_link_libraries(minimal_imgui PUBLIC kernel32 user32 shell32 gdi32)
elseif(APPLE)
target_link_libraries(minimal_imgui PUBLIC "-framework Cocoa" "-framework QuartzCore" "-framework OpenGL")
elseif(UNIX AND NOT APPLE)
target_link_libraries(minimal_imgui PUBLIC X11 Xi Xcursor GL dl pthread m)
endif()

View File

@ -0,0 +1,196 @@
#define CLAY_IMPLEMENTATION
#include "../../clay.h"
#define SOKOL_IMPL
#define SOKOL_NO_ENTRY
#define SOKOL_GLCORE
#include "sokol_app.h"
#include "sokol_gfx.h"
#include "sokol_glue.h"
#include "sokol_log.h"
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui.h"
#define SOKOL_IMGUI_IMPL
#include "util/sokol_imgui.h"
#include <stdio.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
sg_pass_action pass_action = {};
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};
void init();
void frame();
void cleanup();
void input(const sapp_event* event);
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({
.textColor = { 255, 255, 255, 255 },
.fontId = FONT_ID_BODY_24,
.fontSize = 24,
}));
}
}
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();
}
Clay_Dimensions measureText(Clay_String *text, Clay_TextElementConfig *config);
void render(Clay_RenderCommandArray renderCommands);
int main(int argc, char** args) {
//-----------------------------------------------------------------------
// Setup Clay
//-----------------------------------------------------------------------
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = (Clay_Arena) {
.label = CLAY_STRING("Clay Memory Arena"),
.capacity = totalMemorySize,
.memory = (char*)malloc(totalMemorySize),
};
Clay_SetMeasureTextFunction(measureText);
Clay_Initialize(clayMemory, (Clay_Dimensions) { SCREEN_WIDTH, SCREEN_HEIGHT });
//-----------------------------------------------------------------------
// Setup Sokol
//-----------------------------------------------------------------------
sapp_desc desc = {0};
desc.init_cb = init;
desc.frame_cb = frame;
desc.cleanup_cb = cleanup,
desc.event_cb = input,
desc.width = SCREEN_WIDTH,
desc.height = SCREEN_HEIGHT,
desc.window_title = "sokol + puredoom",
desc.icon.sokol_default = true,
desc.logger.func = slog_func;
sapp_run(&desc);
return 0;
}
void init() {
sg_desc desc = {0};
desc.environment = sglue_environment();
desc.logger.func = slog_func;
sg_setup(&desc);
pass_action.colors[0] = (sg_color_attachment_action){ .load_action=SG_LOADACTION_CLEAR, .clear_value={0.2f, 0.1f, 0.3f, 1.0f} };
simgui_desc_t simgui_desc = {0};
simgui_setup(&simgui_desc);
}
void frame() {
// const double dt = sapp_frame_duration();
const int width = sapp_width();
const int height = sapp_height();
simgui_new_frame({ width, height, sapp_frame_duration(), sapp_dpi_scale() });
// imgui
{
// ImGui::ShowDemoWindow();
ImGui::SetNextWindowSize(ImVec2{SCREEN_WIDTH, SCREEN_HEIGHT});
ImGui::SetNextWindowPos(ImVec2{0, 0});
ImGui::Begin("Text rendering", NULL, ImGuiWindowFlags_NoBackground|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoSavedSettings);
Clay_RenderCommandArray renderCommands = CreateLayout();
render(renderCommands);
ImGui::End();
}
sg_begin_pass({ .action = pass_action, .swapchain = sglue_swapchain() });
simgui_render();
sg_end_pass();
sg_commit();
}
void cleanup() {
simgui_shutdown();
sg_shutdown();
}
void input(const sapp_event* event) {
simgui_handle_event(event);
}
Clay_Dimensions measureText(Clay_String *text, Clay_TextElementConfig *config)
{
ImVec2 size = ImGui::CalcTextSize(text->chars, nullptr);
return (Clay_Dimensions) {
.width = size.x,
.height = size.y,
};
}
void render(Clay_RenderCommandArray renderCommands)
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetCursorScreenPos();
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;
draw_list->AddRectFilled(p+ImVec2(boundingBox.x, boundingBox.y), p+ImVec2(boundingBox.x+boundingBox.width, boundingBox.y+boundingBox.height), ImColor(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a/255.0f));
break;
}
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
Clay_TextElementConfig *config = renderCommand->config.textElementConfig;
draw_list->AddText(p+ImVec2(boundingBox.x, boundingBox.y), ImColor(config->textColor.r/255.0f, config->textColor.g/255.0f, config->textColor.b/255.0f, config->textColor.a/255.0f), renderCommand->text.chars);
break;
}
default: {
fprintf(stderr, "Error: unhandled render command: %d\n", renderCommand->commandType);
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
exit(1);
}
}
}
}

View File

@ -247,7 +247,7 @@ int main(void) {
.height = GetScreenHeight() / 2 .height = GetScreenHeight() / 2
}, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published }, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published
Clay_SetMeasureTextFunction(Raylib_MeasureText); Clay_SetMeasureTextFunction(Raylib_MeasureText, 0);
Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) { Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) {
.font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400), .font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400),
.fontId = FONT_ID_BODY_16 .fontId = FONT_ID_BODY_16

View File

@ -218,8 +218,8 @@ void HandleClayErrors(Clay_ErrorData errorData) {
int main(void) { int main(void) {
uint64_t totalMemorySize = Clay_MinMemorySize(); uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize)); Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
Clay_SetMeasureTextFunction(Raylib_MeasureText);
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)GetScreenWidth(), (float)GetScreenHeight() }, (Clay_ErrorHandler) { HandleClayErrors }); Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)GetScreenWidth(), (float)GetScreenHeight() }, (Clay_ErrorHandler) { HandleClayErrors });
Clay_SetMeasureTextFunction(Raylib_MeasureText, 0);
Clay_Raylib_Initialize(1024, 768, "Clay - Raylib Renderer Example", FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT); Clay_Raylib_Initialize(1024, 768, "Clay - Raylib Renderer Example", FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT);
profilePicture = LoadTextureFromImage(LoadImage("resources/profile-picture.png")); profilePicture = LoadTextureFromImage(LoadImage("resources/profile-picture.png"));
Raylib_fonts[FONT_ID_BODY_24] = (Raylib_Font) { Raylib_fonts[FONT_ID_BODY_24] = (Raylib_Font) {

View File

@ -12,13 +12,14 @@ typedef struct
TTF_Font *font; TTF_Font *font;
} SDL2_Font; } SDL2_Font;
static SDL2_Font SDL2_fonts[1];
static Clay_Dimensions SDL2_MeasureText(Clay_String *text, Clay_TextElementConfig *config) static Clay_Dimensions SDL2_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData)
{ {
TTF_Font *font = SDL2_fonts[config->fontId].font; SDL2_Font *fonts = (SDL2_Font*)userData;
char *chars = (char *)calloc(text->length + 1, 1);
memcpy(chars, text->chars, text->length); 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 width = 0;
int height = 0; int height = 0;
if (TTF_SizeUTF8(font, chars, &width, &height) < 0) { if (TTF_SizeUTF8(font, chars, &width, &height) < 0) {
@ -34,7 +35,7 @@ static Clay_Dimensions SDL2_MeasureText(Clay_String *text, Clay_TextElementConfi
SDL_Rect currentClippingRectangle; SDL_Rect currentClippingRectangle;
static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands) static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands, SDL2_Font *fonts)
{ {
for (uint32_t i = 0; i < renderCommands.length; i++) for (uint32_t i = 0; i < renderCommands.length; i++)
{ {
@ -60,7 +61,7 @@ static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray ren
Clay_String text = renderCommand->text; Clay_String text = renderCommand->text;
char *cloned = (char *)calloc(text.length + 1, 1); char *cloned = (char *)calloc(text.length + 1, 1);
memcpy(cloned, text.chars, text.length); memcpy(cloned, text.chars, text.length);
TTF_Font* font = SDL2_fonts[config->fontId].font; TTF_Font* font = fonts[config->fontId].font;
SDL_Surface *surface = TTF_RenderUTF8_Blended(font, cloned, (SDL_Color) { SDL_Surface *surface = TTF_RenderUTF8_Blended(font, cloned, (SDL_Color) {
.r = (Uint8)config->textColor.r, .r = (Uint8)config->textColor.r,
.g = (Uint8)config->textColor.g, .g = (Uint8)config->textColor.g,

6
renderers/SDL3/README Normal file
View File

@ -0,0 +1,6 @@
Please note, the SDL3 renderer is not 100% feature complete. It is currently missing:
- Rounded rectangle corners
- Borders
- Images
- Scroll / Scissor handling

View File

@ -0,0 +1,41 @@
#include "../../clay.h"
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
/* This needs to be global because the "MeasureText" callback doesn't have a
* user data parameter */
static TTF_Font *gFonts[1];
static void SDL_RenderClayCommands(SDL_Renderer *renderer, Clay_RenderCommandArray *rcommands)
{
for (size_t i = 0; i < rcommands->length; i++) {
Clay_RenderCommand *rcmd = Clay_RenderCommandArray_Get(rcommands, i);
Clay_BoundingBox bounding_box = rcmd->boundingBox;
const SDL_FRect rect = { bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height };
switch (rcmd->commandType) {
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
Clay_RectangleElementConfig *config = rcmd->config.rectangleElementConfig;
Clay_Color color = config->color;
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderFillRect(renderer, &rect);
} break;
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
Clay_TextElementConfig *config = rcmd->config.textElementConfig;
Clay_String *text = &rcmd->text;
SDL_Color color = { config->textColor.r, config->textColor.g, config->textColor.b, config->textColor.a };
TTF_Font *font = gFonts[config->fontId];
SDL_Surface *surface = TTF_RenderText_Blended(font, text->chars, text->length, color);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderTexture(renderer, texture, NULL, &rect);
SDL_DestroySurface(surface);
SDL_DestroyTexture(texture);
} break;
default:
SDL_Log("Unknown render command type: %d", rcmd->commandType);
}
}
}

View File

@ -83,7 +83,7 @@ static inline char *Clay_Cairo__NullTerminate(Clay_String *str) {
} }
// Measure text using cairo's *toy* text API. // Measure text using cairo's *toy* text API.
static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_String *str, Clay_TextElementConfig *config) { static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_String *str, Clay_TextElementConfig *config, uintptr_t userData) {
// Edge case: Clay computes the width of a whitespace character // Edge case: Clay computes the width of a whitespace character
// once. Cairo does not factor in whitespaces when computing text // once. Cairo does not factor in whitespaces when computing text
// extents, this edge-case serves as a short-circuit to introduce // extents, this edge-case serves as a short-circuit to introduce

View File

@ -89,7 +89,7 @@ Ray GetScreenToWorldPointWithZDistance(Vector2 position, Camera camera, int scre
uint32_t measureCalls = 0; uint32_t measureCalls = 0;
static inline Clay_Dimensions Raylib_MeasureText(Clay_String *text, Clay_TextElementConfig *config) { static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData) {
measureCalls++; measureCalls++;
// Measure string size for Font // Measure string size for Font
Clay_Dimensions textSize = { 0 }; Clay_Dimensions textSize = { 0 };
@ -101,14 +101,14 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_String *text, Clay_TextEle
Font fontToUse = Raylib_fonts[config->fontId].font; Font fontToUse = Raylib_fonts[config->fontId].font;
float scaleFactor = config->fontSize/(float)fontToUse.baseSize; float scaleFactor = config->fontSize/(float)fontToUse.baseSize;
for (int i = 0; i < text->length; ++i) for (int i = 0; i < text.length; ++i)
{ {
if (text->chars[i] == '\n') { if (text.chars[i] == '\n') {
maxTextWidth = fmax(maxTextWidth, lineTextWidth); maxTextWidth = fmax(maxTextWidth, lineTextWidth);
lineTextWidth = 0; lineTextWidth = 0;
continue; continue;
} }
int index = text->chars[i] - 32; int index = text.chars[i] - 32;
if (fontToUse.glyphs[index].advanceX != 0) lineTextWidth += fontToUse.glyphs[index].advanceX; if (fontToUse.glyphs[index].advanceX != 0) lineTextWidth += fontToUse.glyphs[index].advanceX;
else lineTextWidth += (fontToUse.recs[index].width + fontToUse.glyphs[index].offsetX); else lineTextWidth += (fontToUse.recs[index].width + fontToUse.glyphs[index].offsetX);
} }