Compare commits

...

3 Commits

Author SHA1 Message Date
Nic Barker
89d6618eab
Merge f49ec15da8 into 6a9b723dcc 2024-12-26 01:17:16 +00:00
Nic Barker
f49ec15da8 README updates 2024-12-26 14:17:10 +13:00
Nic Barker
5261c1eef2 Convert clay measure text hash map size to runtime variable 2024-12-26 13:46:21 +13:00
3 changed files with 104 additions and 19 deletions

View File

@ -410,15 +410,12 @@ Clay supports C preprocessor directives to modulate functionality at compile tim
The supported directives are:
- `CLAY_MAX_ELEMENT_COUNT` - Controls the maximum number of clay elements that memory is pre-allocated for. Defaults to **8192**, which should be more than enough for the majority of use cases. Napkin math is ~450 bytes of memory overhead per element (8192 elements is ~3.5mb of memory)
- `CLAY_DISABLE_CULLING` - Disables [Visibility Culling](#visibility-culling) of render commands.
- `CLAY_WASM` - Required when targeting Web Assembly.
- `CLAY_OVERFLOW_TRAP` - By default, clay will continue to allow function calls without crashing even when it exhausts all its available pre-allocated memory. This can produce erroneous layout results that are difficult to interpret. If `CLAY_OVERFLOW_TRAP` is defined, clay will raise a `SIGTRAP` signal that will be caught by your debugger. Relies on `signal.h` being available in your environment.
- `CLAY_DEBUG` - Used for debugging clay's internal implementation. Useful if you want to modify or debug clay, or learn how things work. It enables a number of debug features such as preserving source strings for hash IDs to make debugging easier.
- `CLAY_EXTEND_CONFIG_RECTANGLE` - Provide additional struct members to `CLAY_RECTANGLE` that will be passed through with output render commands.
- `CLAY_EXTEND_CONFIG_TEXT` - Provide additional struct members to `CLAY_TEXT_CONFIG` that will be passed through with output render commands.
- `CLAY_EXTEND_CONFIG_IMAGE` - Provide additional struct members to `CLAY_IMAGE_CONFIG` that will be passed through with output render commands.
- `CLAY_EXTEND_CONFIG_CUSTOM` - Provide additional struct members to `CLAY_IMAGE_CONFIG` that will be passed through with output render commands.
- `CLAY_EXTEND_CONFIG_CUSTOM` - Provide additional struct members to `CLAY_CUSTOM_CONFIG` that will be passed through with output render commands.
### Bindings for non C
@ -485,9 +482,9 @@ Takes a pointer to a function that can be used to measure the `width, height` di
### Clay_Initialize
`void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions)`
`void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler)`
Initializes the internal memory mapping, and sets the internal dimensions for layout.
Initializes the internal memory mapping, sets the internal dimensions for layout, and binds an error handler for clay to use when something goes wrong.
### Clay_SetLayoutDimensions
@ -1770,4 +1767,77 @@ An enum value representing the current "state" of the pointer interaction. As an
---
### Clay_ErrorHandler
```C
typedef struct
{
void (*errorHandlerFunction)(Clay_ErrorData errorText);
uintptr_t userData;
} Clay_ErrorHandler;
```
**Fields**
**`.errorHandlerFunction`** - `void (Clay_ErrorData errorText) {}`
A function pointer to an error handler function, which takes `Clay_ErrorData` as an argument. This function will be called whenever Clay encounters an internal error.
---
**`.userData`** - `uintptr_t`
A generic pointer to extra userdata that is transparently passed through from `Clay_Initialize` to Clay's error handler callback. Defaults to NULL.
---
### Clay_ErrorData
```C
typedef struct
{
Clay_ErrorType errorType;
Clay_String errorText;
uintptr_t userData;
} Clay_ErrorData;
```
**Fields**
**`.errorType`** - `Clay_ErrorType`
```C
typedef enum {
CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED,
CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED,
CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED,
CLAY_ERROR_TYPE_DUPLICATE_ID,
CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND,
CLAY_ERROR_TYPE_INTERNAL_ERROR,
} Clay_ErrorType;
```
An enum representing the type of error Clay encountered. It's up to the user to handle on a case by case basis, but as some general guidance:
- `CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED` - The user is attempting to use `CLAY_TEXT` and either forgot to call [Clay_SetMeasureTextFunction](#clay_setmeasuretextfunction) or accidentally passed a null function pointer.
- `CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED` - Clay was initialized with an Arena that was too small for the configured [Clay_SetMaxElementCount](#clay_setmaxelementcount). Try using [Clay_MinMemorySize()](#clay_minmemorysize) to get the exact number of bytes required by the current configuration.
- `CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED` - The declared UI hierarchy has too many elements for the configured max element count. Use [Clay_SetMaxElementCount](#clay_setmaxelementcount) to increase the max, then call [Clay_MinMemorySize()](#clay_minmemorysize) again and reinitialize clay's memory with the required size.
- `CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED` - The declared UI hierarchy has too much text for the configured text measure cache size. Use [Clay_SetMeasureTextCacheSize](#clay_setmeasuretextcachesize) to increase the max, then call [Clay_MinMemorySize()](#clay_minmemorysize) again and reinitialize clay's memory with the required size.
- `CLAY_ERROR_TYPE_DUPLICATE_ID` - Two elements in Clays UI Hierarchy have been declared with exactly the same ID. Set a breakpoint in your error handler function for a stack trace back to exactly where this occured.
- `CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND` - A `CLAY_FLOATING` element was declared with the `.parentId` property, but no element with that ID was found. Set a breakpoint in your error handler function for a stack trace back to exactly where this occured.
- `CLAY_ERROR_TYPE_INTERNAL_ERROR` - Clay has encountered an internal logic or memory error. Please report this as a bug with a stack trace to help us fix these!
---
**`.errorText`** - `Clay_String`
A [Clay_String](#clay_string) that provides a human readable description of the error. May change in future and should not be relied on to detect error types.
---
**`.userData`** - `uintptr_t`
A generic pointer to extra userdata that is transparently passed through from `Clay_Initialize` to Clay's error handler callback. Defaults to NULL.
---

25
clay.h
View File

@ -479,6 +479,7 @@ Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array,
void Clay_SetDebugModeEnabled(bool enabled);
void Clay_SetCullingEnabled(bool enabled);
void Clay_SetMaxElementCount(uint32_t maxElementCount);
void Clay_SetMeasureTextCacheSize(uint32_t measureTextCacheSize);
// Internal API functions required by macros
void Clay__OpenElement();
@ -514,14 +515,6 @@ extern uint32_t Clay__debugViewWidth;
#ifdef CLAY_IMPLEMENTATION
#undef CLAY_IMPLEMENTATION
#ifndef CLAY__TEXT_MEASURE_HASH_BUCKET_COUNT
#define CLAY__TEXT_MEASURE_HASH_BUCKET_COUNT 16
#endif
#ifndef CLAY_MEASURE_TEXT_CACHE_SIZE
#define CLAY_MEASURE_TEXT_CACHE_SIZE Clay__maxElementCount * 2
#endif
#ifndef CLAY__NULL
#define CLAY__NULL 0
#endif
@ -531,7 +524,8 @@ extern uint32_t Clay__debugViewWidth;
#endif
bool Clay__warningsEnabled = true;
uint32_t Clay__maxElementCount = 128;
uint32_t Clay__maxElementCount = 8192;
uint32_t Clay__measureTextCacheSize = 16384;
Clay_ErrorHandler Clay__errorHandler = CLAY__INIT(Clay_ErrorHandler) { .errorHandlerFunction = Clay__Noop };
void Clay__Noop() {};
@ -1583,7 +1577,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
return NULL;
}
uint32_t id = Clay__HashTextWithConfig(text, config);
uint32_t hashBucket = id % CLAY__TEXT_MEASURE_HASH_BUCKET_COUNT;
uint32_t hashBucket = id % (Clay__measureTextCacheSize / 8);
int32_t elementIndexPrevious = 0;
int32_t elementIndex = Clay__measureTextHashMap.internalArray[hashBucket];
while (elementIndex != 0) {
@ -1653,7 +1647,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
if (!Clay__booleanWarnings.maxTextMeasureCacheExceeded) {
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED,
.errorText = CLAY_STRING("Clay has run out of space in it's internal text measurement cache. Try increasing CLAY_MEASURE_TEXT_CACHE_SIZE."),
.errorText = CLAY_STRING("Clay has run out of space in it's internal text measurement cache. Try using Clay_SetMeasureTextCacheSize() (default 16384, with 1 unit storing 1 measured word)."),
.userData = Clay__errorHandler.userData });
Clay__booleanWarnings.maxTextMeasureCacheExceeded = true;
}
@ -2034,9 +2028,9 @@ void Clay__InitializePersistentMemory(Clay_Arena *arena) {
Clay__layoutElementsHashMap = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__measuredWordsFreeList = Clay__int32_tArray_Allocate_Arena(CLAY_MEASURE_TEXT_CACHE_SIZE, arena);
Clay__measuredWordsFreeList = Clay__int32_tArray_Allocate_Arena(Clay__measureTextCacheSize, arena);
Clay__measureTextHashMap = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__measuredWords = Clay__MeasuredWordArray_Allocate_Arena(CLAY_MEASURE_TEXT_CACHE_SIZE, arena);
Clay__measuredWords = Clay__MeasuredWordArray_Allocate_Arena(Clay__measureTextCacheSize, arena);
Clay__pointerOverIds = Clay__ElementIdArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__debugElementData = Clay__DebugElementDataArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__arenaResetOffset = arena->nextAllocation;
@ -3836,6 +3830,11 @@ void Clay_SetMaxElementCount(uint32_t maxElementCount) {
Clay__maxElementCount = maxElementCount;
}
CLAY_WASM_EXPORT("Clay_SetMeasureTextCacheSize")
void Clay_SetMeasureTextCacheSize(uint32_t measureTextCacheSize) {
Clay__measureTextCacheSize = measureTextCacheSize;
}
#endif //CLAY_IMPLEMENTATION
/*

View File

@ -202,8 +202,17 @@ void UpdateDrawFrame(void)
//----------------------------------------------------------------------------------
}
bool reinitializeClay = false;
void HandleClayErrors(Clay_ErrorData errorData) {
printf("%s", errorData.errorText.chars);
if (errorData.errorType == CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED) {
reinitializeClay = true;
Clay_SetMaxElementCount(Clay__maxElementCount * 2);
} else if (errorData.errorType == CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED) {
reinitializeClay = true;
Clay_SetMeasureTextCacheSize(Clay__measureTextCacheSize * 2);
}
}
int main(void) {
@ -230,6 +239,13 @@ int main(void) {
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
if (reinitializeClay) {
Clay_SetMaxElementCount(8192);
totalMemorySize = Clay_MinMemorySize();
clayMemory = (Clay_Arena) { .label = CLAY_STRING("Clay Memory Arena"), .memory = malloc(totalMemorySize), .capacity = totalMemorySize };
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)GetScreenWidth(), (float)GetScreenHeight() }, (Clay_ErrorHandler) { HandleClayErrors });
reinitializeClay = false;
}
UpdateDrawFrame();
}
return 0;