This commit is contained in:
Nic Barker 2024-12-26 01:17:16 +00:00 committed by GitHub
commit 89d6618eab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 283 additions and 199 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.
---

365
clay.h
View File

@ -412,9 +412,6 @@ typedef struct
Clay_String text; // TODO I wish there was a way to avoid having to have this on every render command
uint32_t id;
Clay_RenderCommandType commandType;
#ifdef CLAY_DEBUG
Clay_String name;
#endif
} Clay_RenderCommand;
typedef struct
@ -438,12 +435,35 @@ typedef struct
Clay_PointerDataInteractionState state;
} Clay_PointerData;
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;
typedef struct
{
Clay_ErrorType errorType;
Clay_String errorText;
uintptr_t userData;
} Clay_ErrorData;
typedef struct
{
void (*errorHandlerFunction)(Clay_ErrorData errorText);
uintptr_t userData;
} Clay_ErrorHandler;
// Function Forward Declarations ---------------------------------
// Public API functions ---
uint32_t Clay_MinMemorySize();
Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset);
void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions);
void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler);
void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime);
void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
void Clay_BeginLayout();
@ -458,6 +478,8 @@ void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)
Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
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();
@ -480,7 +502,6 @@ void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig)
extern Clay_Color Clay__debugViewHighlightColor;
extern uint32_t Clay__debugViewWidth;
extern bool Clay__debugMaxElementsLatch;
#ifdef __cplusplus
}
@ -494,22 +515,6 @@ extern bool Clay__debugMaxElementsLatch;
#ifdef CLAY_IMPLEMENTATION
#undef CLAY_IMPLEMENTATION
#ifdef CLAY_OVERFLOW_TRAP
#include "signal.h"
#endif
#ifndef CLAY_MAX_ELEMENT_COUNT
#define CLAY_MAX_ELEMENT_COUNT 8192
#endif
#ifndef CLAY__TEXT_MEASURE_HASH_BUCKET_COUNT
#define CLAY__TEXT_MEASURE_HASH_BUCKET_COUNT 128
#endif
#ifndef CLAY_MEASURE_TEXT_CACHE_SIZE
#define CLAY_MEASURE_TEXT_CACHE_SIZE CLAY_MAX_ELEMENT_COUNT * 2
#endif
#ifndef CLAY__NULL
#define CLAY__NULL 0
#endif
@ -519,6 +524,9 @@ extern bool Clay__debugMaxElementsLatch;
#endif
bool Clay__warningsEnabled = true;
uint32_t Clay__maxElementCount = 8192;
uint32_t Clay__measureTextCacheSize = 16384;
Clay_ErrorHandler Clay__errorHandler = CLAY__INIT(Clay_ErrorHandler) { .errorHandlerFunction = Clay__Noop };
void Clay__Noop() {};
@ -529,7 +537,7 @@ typedef struct
{
bool maxElementsExceeded;
bool maxRenderCommandsExceeded;
bool maxStringMeasureCacheExceeded;
bool maxTextMeasureCacheExceeded;
} Clay_BooleanWarnings;
Clay_BooleanWarnings Clay__booleanWarnings;
@ -561,9 +569,10 @@ Clay__WarningArray Clay__WarningArray_Allocate_Arena(uint32_t capacity, Clay_Are
arena->nextAllocation = arenaOffsetAligned + totalSizeBytes;
}
else {
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED,
.errorText = CLAY_STRING("Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()"),
.userData = Clay__errorHandler.userData });
}
return array;
}
@ -576,11 +585,6 @@ Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning i
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
else {
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
}
return &CLAY__WARNING_DEFAULT;
}
@ -595,12 +599,10 @@ void* Clay__Array_Allocate_Arena(uint32_t capacity, uint32_t itemSize, uint32_t
return (void*)((uintptr_t)arena->memory + (uintptr_t)arenaOffsetAligned);
}
else {
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Attempting to allocate array in arena, but arena is already at capacity and would overflow.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED,
.errorText = CLAY_STRING("Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()"),
.userData = Clay__errorHandler.userData });
}
return CLAY__NULL;
}
@ -610,26 +612,22 @@ bool Clay__Array_RangeCheck(int index, uint32_t length)
if (index < length && index >= 0) {
return true;
}
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Array access out of bounds.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR,
.errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."),
.userData = Clay__errorHandler.userData });
return false;
}
bool Clay__Array_IncrementCapacityCheck(uint32_t length, uint32_t capacity)
bool Clay__Array_AddCapacityCheck(uint32_t length, uint32_t capacity)
{
if (length < capacity) {
return true;
}
if (Clay__warningsEnabled && !Clay__debugMaxElementsLatch) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Attempting to add to array that is already at capacity.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR,
.errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."),
.userData = Clay__errorHandler.userData });
return false;
}
@ -666,7 +664,7 @@ Clay_ElementId *Clay__ElementIdArray_Get(Clay__ElementIdArray *array, int index)
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__ELEMENT_ID_DEFAULT;
}
Clay_ElementId *Clay__ElementIdArray_Add(Clay__ElementIdArray *array, Clay_ElementId item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -697,7 +695,7 @@ Clay_ElementConfig *Clay__ElementConfigArray_Get(Clay__ElementConfigArray *array
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__ELEMENT_CONFIG_DEFAULT;
}
Clay_ElementConfig *Clay__ElementConfigArray_Add(Clay__ElementConfigArray *array, Clay_ElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -723,7 +721,7 @@ Clay__LayoutConfigArray Clay__LayoutConfigArray_Allocate_Arena(uint32_t capacity
return CLAY__INIT(Clay__LayoutConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_LayoutConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_LayoutConfig), CLAY__ALIGNMENT(Clay_LayoutConfig), arena)};
}
Clay_LayoutConfig *Clay__LayoutConfigArray_Add(Clay__LayoutConfigArray *array, Clay_LayoutConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -746,7 +744,7 @@ Clay__RectangleElementConfigArray Clay__RectangleElementConfigArray_Allocate_Are
return CLAY__INIT(Clay__RectangleElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_RectangleElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_RectangleElementConfig), CLAY__ALIGNMENT(Clay_RectangleElementConfig), arena)};
}
Clay_RectangleElementConfig *Clay__RectangleElementConfigArray_Add(Clay__RectangleElementConfigArray *array, Clay_RectangleElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -769,7 +767,7 @@ Clay__TextElementConfigArray Clay__TextElementConfigArray_Allocate_Arena(uint32_
return CLAY__INIT(Clay__TextElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_TextElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_TextElementConfig), CLAY__ALIGNMENT(Clay_TextElementConfig), arena)};
}
Clay_TextElementConfig *Clay__TextElementConfigArray_Add(Clay__TextElementConfigArray *array, Clay_TextElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -792,7 +790,7 @@ Clay__ImageElementConfigArray Clay__ImageElementConfigArray_Allocate_Arena(uint3
return CLAY__INIT(Clay__ImageElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_ImageElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_ImageElementConfig), CLAY__ALIGNMENT(Clay_ImageElementConfig), arena)};
}
Clay_ImageElementConfig *Clay__ImageElementConfigArray_Add(Clay__ImageElementConfigArray *array, Clay_ImageElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -815,7 +813,7 @@ Clay__FloatingElementConfigArray Clay__FloatingElementConfigArray_Allocate_Arena
return CLAY__INIT(Clay__FloatingElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_FloatingElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_FloatingElementConfig), CLAY__ALIGNMENT(Clay_FloatingElementConfig), arena)};
}
Clay_FloatingElementConfig *Clay__FloatingElementConfigArray_Add(Clay__FloatingElementConfigArray *array, Clay_FloatingElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -838,7 +836,7 @@ Clay__CustomElementConfigArray Clay__CustomElementConfigArray_Allocate_Arena(uin
return CLAY__INIT(Clay__CustomElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_CustomElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_CustomElementConfig), CLAY__ALIGNMENT(Clay_CustomElementConfig), arena)};
}
Clay_CustomElementConfig *Clay__CustomElementConfigArray_Add(Clay__CustomElementConfigArray *array, Clay_CustomElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -861,7 +859,7 @@ Clay__ScrollElementConfigArray Clay__ScrollElementConfigArray_Allocate_Arena(uin
return CLAY__INIT(Clay__ScrollElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_ScrollElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_ScrollElementConfig), CLAY__ALIGNMENT(Clay_ScrollElementConfig), arena)};
}
Clay_ScrollElementConfig *Clay__ScrollElementConfigArray_Add(Clay__ScrollElementConfigArray *array, Clay_ScrollElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -881,7 +879,7 @@ Clay__StringArray Clay__StringArray_Allocate_Arena(uint32_t capacity, Clay_Arena
return CLAY__INIT(Clay__StringArray){.capacity = capacity, .length = 0, .internalArray = (Clay_String *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_String), CLAY__ALIGNMENT(Clay_String), arena)};
}
Clay_String *Clay__StringArray_Add(Clay__StringArray *array, Clay_String item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -915,7 +913,7 @@ Clay__TextElementData *Clay__TextElementDataArray_Get(Clay__TextElementDataArray
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__TEXT_ELEMENT_DATA_DEFAULT;
}
Clay__TextElementData *Clay__TextElementDataArray_Add(Clay__TextElementDataArray *array, Clay__TextElementData item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -938,7 +936,7 @@ Clay__BorderElementConfigArray Clay__BorderElementConfigArray_Allocate_Arena(uin
return CLAY__INIT(Clay__BorderElementConfigArray){.capacity = capacity, .length = 0, .internalArray = (Clay_BorderElementConfig *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_BorderElementConfig), CLAY__ALIGNMENT(Clay_BorderElementConfig), arena)};
}
Clay_BorderElementConfig *Clay__BorderElementConfigArray_Add(Clay__BorderElementConfigArray *array, Clay_BorderElementConfig item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -955,9 +953,6 @@ typedef struct
typedef struct
{
#ifdef CLAY_DEBUG
Clay_String name;
#endif
union {
Clay__LayoutElementChildren children;
Clay__TextElementData *textElementData;
@ -984,7 +979,7 @@ Clay_LayoutElementArray Clay_LayoutElementArray_Allocate_Arena(uint32_t capacity
return CLAY__INIT(Clay_LayoutElementArray){.capacity = capacity, .length = 0, .internalArray = (Clay_LayoutElement *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_LayoutElement), CLAY__ALIGNMENT(Clay_LayoutElement), arena)};
}
Clay_LayoutElement *Clay_LayoutElementArray_Add(Clay_LayoutElementArray *array, Clay_LayoutElement item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1008,7 +1003,7 @@ Clay__LayoutElementPointerArray Clay__LayoutElementPointerArray_Allocate_Arena(u
return CLAY__INIT(Clay__LayoutElementPointerArray){.capacity = capacity, .length = 0, .internalArray = (Clay_LayoutElement* *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_LayoutElement*), CLAY__ALIGNMENT(Clay_LayoutElement*), arena)};
}
Clay_LayoutElement* *Clay__LayoutElementPointerArray_Add(Clay__LayoutElementPointerArray *array, Clay_LayoutElement* item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1037,13 +1032,13 @@ Clay_RenderCommandArray Clay_RenderCommandArray_Allocate_Arena(uint32_t capacity
return CLAY__INIT(Clay_RenderCommandArray){.capacity = capacity, .length = 0, .internalArray = (Clay_RenderCommand *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay_RenderCommand), CLAY__ALIGNMENT(Clay_RenderCommand), arena)};
}
Clay_RenderCommand *Clay_RenderCommandArray_Add(Clay_RenderCommandArray *array, Clay_RenderCommand item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
return &CLAY__RENDER_COMMAND_DEFAULT;
}
Clay_RenderCommand *Clay_RenderCommandArray_Get(Clay_RenderCommandArray *array, int32_t index) {
Clay_RenderCommand *Clay_RenderCommandArray_Get(Clay_RenderCommandArray *array, int index) {
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__RENDER_COMMAND_DEFAULT;
}
#pragma endregion
@ -1079,7 +1074,7 @@ Clay__ScrollContainerDataInternalArray Clay__ScrollContainerDataInternalArray_Al
return CLAY__INIT(Clay__ScrollContainerDataInternalArray){.capacity = capacity, .length = 0, .internalArray = (Clay__ScrollContainerDataInternal *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay__ScrollContainerDataInternal), CLAY__ALIGNMENT(Clay__ScrollContainerDataInternal), arena)};
}
Clay__ScrollContainerDataInternal *Clay__ScrollContainerDataInternalArray_Add(Clay__ScrollContainerDataInternalArray *array, Clay__ScrollContainerDataInternal item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1125,7 +1120,7 @@ Clay__DebugElementDataArray Clay__DebugElementDataArray_Allocate_Arena(uint32_t
return CLAY__INIT(Clay__DebugElementDataArray){.capacity = capacity, .length = 0, .internalArray = (Clay__DebugElementData *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay__DebugElementData), CLAY__ALIGNMENT(Clay__DebugElementData), arena)};
}
Clay__DebugElementData *Clay__DebugElementDataArray_Add(Clay__DebugElementDataArray *array, Clay__DebugElementData item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1166,7 +1161,7 @@ Clay_LayoutElementHashMapItem *Clay__LayoutElementHashMapItemArray_Get(Clay__Lay
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__LAYOUT_ELEMENT_HASH_MAP_ITEM_DEFAULT;
}
Clay_LayoutElementHashMapItem *Clay__LayoutElementHashMapItemArray_Add(Clay__LayoutElementHashMapItemArray *array, Clay_LayoutElementHashMapItem item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1200,20 +1195,13 @@ Clay__MeasuredWord *Clay__MeasuredWordArray_Get(Clay__MeasuredWordArray *array,
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__MEASURED_WORD_DEFAULT;
}
void Clay__MeasuredWordArray_Set(Clay__MeasuredWordArray *array, int index, Clay__MeasuredWord value) {
if (index < array->capacity && index >= 0) {
if (Clay__Array_RangeCheck(index, array->capacity)) {
array->internalArray[index] = value;
array->length = index < array->length ? array->length : index + 1;
} else {
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Attempting to allocate array in arena, but arena is already at capacity and would overflow.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
}
}
Clay__MeasuredWord *Clay__MeasuredWordArray_Add(Clay__MeasuredWordArray *array, Clay__MeasuredWord item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1249,23 +1237,16 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCacheItemArray_Get(Clay__MeasureTex
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT;
}
Clay__MeasureTextCacheItem *Clay__MeasureTextCacheItemArray_Add(Clay__MeasureTextCacheItemArray *array, Clay__MeasureTextCacheItem item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
return &CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT;
}
void Clay__MeasureTextCacheItemArray_Set(Clay__MeasureTextCacheItemArray *array, int index, Clay__MeasureTextCacheItem value) {
if (index < array->capacity && index >= 0) {
if (Clay__Array_RangeCheck(index, array->capacity)) {
array->internalArray[index] = value;
array->length = index < array->length ? array->length : index + 1;
} else {
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Attempting to allocate array in arena, but arena is already at capacity and would overflow.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
}
}
#pragma endregion
@ -1286,21 +1267,14 @@ int32_t Clay__int32_tArray_Get(Clay__int32_tArray *array, int index) {
return Clay__Array_RangeCheck(index, array->length) ? array->internalArray[index] : -1;
}
void Clay__int32_tArray_Add(Clay__int32_tArray *array, int32_t item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
}
}
void Clay__int32_tArray_Set(Clay__int32_tArray *array, int index, int32_t value) {
if (index < array->capacity && index >= 0) {
if (Clay__Array_RangeCheck(index, array->capacity)) {
array->internalArray[index] = value;
array->length = index < array->length ? array->length : index + 1;
} else {
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Attempting to allocate array in arena, but arena is already at capacity and would overflow.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
}
}
int32_t Clay__int32_tArray_RemoveSwapback(Clay__int32_tArray *array, int index) {
@ -1336,7 +1310,7 @@ Clay__LayoutElementTreeNodeArray Clay__LayoutElementTreeNodeArray_Allocate_Arena
return CLAY__INIT(Clay__LayoutElementTreeNodeArray){.capacity = capacity, .length = 0, .internalArray = (Clay__LayoutElementTreeNode *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay__LayoutElementTreeNode), CLAY__ALIGNMENT(Clay__LayoutElementTreeNode), arena)};
}
Clay__LayoutElementTreeNode *Clay__LayoutElementTreeNodeArray_Add(Clay__LayoutElementTreeNodeArray *array, Clay__LayoutElementTreeNode item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1371,7 +1345,7 @@ Clay__LayoutElementTreeRootArray Clay__LayoutElementTreeRootArray_Allocate_Arena
return CLAY__INIT(Clay__LayoutElementTreeRootArray){.capacity = capacity, .length = 0, .internalArray = (Clay__LayoutElementTreeRoot *)Clay__Array_Allocate_Arena(capacity, sizeof(Clay__LayoutElementTreeRoot), CLAY__ALIGNMENT(Clay__LayoutElementTreeRoot), arena)};
}
Clay__LayoutElementTreeRoot *Clay__LayoutElementTreeRootArray_Add(Clay__LayoutElementTreeRootArray *array, Clay__LayoutElementTreeRoot item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
@ -1416,7 +1390,6 @@ bool Clay__externalScrollHandlingEnabled = false;
uint32_t Clay__debugSelectedElementId = 0;
uint32_t Clay__debugViewWidth = 400;
Clay_Color Clay__debugViewHighlightColor = CLAY__INIT(Clay_Color) { 168, 66, 28, 100 };
bool Clay__debugMaxElementsLatch = false;
uint32_t Clay__generation = 0;
uint64_t Clay__arenaResetOffset = 0;
Clay_Arena Clay__internalArena;
@ -1596,8 +1569,15 @@ Clay__MeasuredWord *Clay__AddMeasuredWord(Clay__MeasuredWord word, Clay__Measure
}
Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_TextElementConfig *config) {
if (!Clay__MeasureText) {
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED,
.errorText = CLAY_STRING("Clay's internal MeasureText function is null. You may have forgotten to call Clay_SetMeasureTextFunction(), or passed a NULL function pointer by mistake."),
.userData = Clay__errorHandler.userData });
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) {
@ -1642,6 +1622,13 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
measured = Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, newItemIndex);
} else {
if (Clay__measureTextHashMapInternal.length == Clay__measureTextHashMapInternal.capacity - 1) {
if (Clay__booleanWarnings.maxTextMeasureCacheExceeded) {
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
.errorText = CLAY_STRING("Clay ran out of capacity while attempting to measure text elements. Try using Clay_SetMaxElementCount() with a higher value."),
.userData = Clay__errorHandler.userData });
Clay__booleanWarnings.maxTextMeasureCacheExceeded = true;
}
return &CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT;
}
measured = Clay__MeasureTextCacheItemArray_Add(&Clay__measureTextHashMapInternal, newCacheItem);
@ -1657,6 +1644,13 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
Clay__MeasuredWord *previousWord = &tempWord;
while (end < text->length) {
if (Clay__measuredWords.length == Clay__measuredWords.capacity - 1) {
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 using Clay_SetMeasureTextCacheSize() (default 16384, with 1 unit storing 1 measured word)."),
.userData = Clay__errorHandler.userData });
Clay__booleanWarnings.maxTextMeasureCacheExceeded = true;
}
return &CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT;
}
char current = text->chars[end];
@ -1720,9 +1714,10 @@ Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Cl
hashItem->layoutElement = layoutElement;
hashItem->debugData->collision = false;
} else { // Multiple collisions this frame - two elements have the same ID
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Duplicate ID detected for element: "), Clay__WriteStringToCharBuffer(&Clay__dynamicStringData, elementId.stringId) });
}
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_DUPLICATE_ID,
.errorText = CLAY_STRING("An element with this ID was already previously declared during this layout."),
.userData = Clay__errorHandler.userData });
if (Clay__debugModeEnabled) {
hashItem->debugData->collision = true;
}
@ -1761,13 +1756,10 @@ void Clay__GenerateIdForAnonymousElement(Clay_LayoutElement *openLayoutElement)
openLayoutElement->id = elementId.id;
Clay__AddHashMapItem(elementId, openLayoutElement);
Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId);
#ifdef CLAY_DEBUG
openLayoutElement->name = elementId.stringId;
#endif
}
void Clay__ElementPostConfiguration() {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
@ -1809,7 +1801,10 @@ void Clay__ElementPostConfiguration() {
Clay_LayoutElementHashMapItem *parentItem = Clay__GetHashMapItem(floatingConfig->parentId);
clipElementId = Clay__int32_tArray_Get(&Clay__layoutElementClipElementIds, parentItem->layoutElement - Clay__layoutElements.internalArray);
if (!parentItem) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Clay Warning: Couldn't find parent container to attach floating container to.") });
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND,
.errorText = CLAY_STRING("A floating element was declared with a parentId, but no element with that ID was found."),
.userData = Clay__errorHandler.userData });
}
}
Clay__LayoutElementTreeRootArray_Add(&Clay__layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) {
@ -1852,7 +1847,7 @@ void Clay__ElementPostConfiguration() {
}
void Clay__CloseElement() {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
@ -1946,8 +1941,8 @@ void Clay__CloseElement() {
}
void Clay__OpenElement() {
if (Clay__layoutElements.length == Clay__layoutElements.capacity - 1 || Clay__debugMaxElementsLatch) {
Clay__debugMaxElementsLatch = true;
if (Clay__layoutElements.length == Clay__layoutElements.capacity - 1 || Clay__booleanWarnings.maxElementsExceeded) {
Clay__booleanWarnings.maxElementsExceeded = true;
return;
}
Clay_LayoutElement layoutElement = CLAY__INIT(Clay_LayoutElement) {};
@ -1961,8 +1956,8 @@ void Clay__OpenElement() {
}
void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig) {
if (Clay__layoutElements.length == Clay__layoutElements.capacity - 1 || Clay__debugMaxElementsLatch) {
Clay__debugMaxElementsLatch = true;
if (Clay__layoutElements.length == Clay__layoutElements.capacity - 1 || Clay__booleanWarnings.maxElementsExceeded) {
Clay__booleanWarnings.maxElementsExceeded = true;
return;
}
Clay_LayoutElement *parentElement = Clay__GetOpenLayoutElement();
@ -1974,9 +1969,6 @@ void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig)
Clay__MeasureTextCacheItem *textMeasured = Clay__MeasureTextCached(&text, textConfig);
Clay_ElementId elementId = Clay__HashString(CLAY_STRING("Text"), parentElement->children.length, parentElement->id);
openLayoutElement->id = elementId.id;
#ifdef CLAY_DEBUG
openLayoutElement->name = CLAY_STRING("Text");
#endif
Clay__AddHashMapItem(elementId, openLayoutElement);
Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId);
Clay_Dimensions textDimensions = CLAY__INIT(Clay_Dimensions) { .width = textMeasured->unwrappedDimensions.width, .height = textConfig->lineHeight > 0 ? textConfig->lineHeight : textMeasured->unwrappedDimensions.height };
@ -1997,50 +1989,50 @@ void Clay__InitializeEphemeralMemory(Clay_Arena *arena) {
// Ephemeral Memory - reset every frame
Clay__internalArena.nextAllocation = Clay__arenaResetOffset;
Clay__layoutElementChildrenBuffer = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElements = Clay_LayoutElementArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementChildrenBuffer = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__layoutElements = Clay_LayoutElementArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay_warnings = Clay__WarningArray_Allocate_Arena(100, arena);
Clay__layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__elementConfigBuffer = Clay__ElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__elementConfigs = Clay__ElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__rectangleElementConfigs = Clay__RectangleElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__textElementConfigs = Clay__TextElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__scrollElementConfigs = Clay__ScrollElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__customElementConfigs = Clay__CustomElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__borderElementConfigs = Clay__BorderElementConfigArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__elementConfigBuffer = Clay__ElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__elementConfigs = Clay__ElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__rectangleElementConfigs = Clay__RectangleElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__textElementConfigs = Clay__TextElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__scrollElementConfigs = Clay__ScrollElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__customElementConfigs = Clay__CustomElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__borderElementConfigs = Clay__BorderElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__layoutElementIdStrings = Clay__StringArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__wrappedTextLines = Clay__StringArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementTreeNodeArray1 = Clay__LayoutElementTreeNodeArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementTreeRoots = Clay__LayoutElementTreeRootArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementChildren = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__openLayoutElementStack = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__textElementData = Clay__TextElementDataArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__imageElementPointers = Clay__LayoutElementPointerArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__renderCommands = Clay_RenderCommandArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__treeNodeVisited = Clay__BoolArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementIdStrings = Clay__StringArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__wrappedTextLines = Clay__StringArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__layoutElementTreeNodeArray1 = Clay__LayoutElementTreeNodeArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__layoutElementTreeRoots = Clay__LayoutElementTreeRootArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__layoutElementChildren = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__openLayoutElementStack = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__textElementData = Clay__TextElementDataArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__imageElementPointers = Clay__LayoutElementPointerArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__renderCommands = Clay_RenderCommandArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__treeNodeVisited = Clay__BoolArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__treeNodeVisited.length = Clay__treeNodeVisited.capacity; // This array is accessed directly rather than behaving as a list
Clay__openClipElementStack = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__reusableElementIndexBuffer = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementClipElementIds = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__dynamicStringData = Clay__CharArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__openClipElementStack = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__reusableElementIndexBuffer = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__layoutElementClipElementIds = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena);
Clay__dynamicStringData = Clay__CharArray_Allocate_Arena(Clay__maxElementCount, arena);
}
void Clay__InitializePersistentMemory(Clay_Arena *arena) {
// Persistent memory - initialized once and not reset
Clay__scrollContainerDatas = Clay__ScrollContainerDataInternalArray_Allocate_Arena(10, arena);
Clay__layoutElementsHashMapInternal = Clay__LayoutElementHashMapItemArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementsHashMap = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measuredWordsFreeList = Clay__int32_tArray_Allocate_Arena(CLAY_MEASURE_TEXT_CACHE_SIZE, arena);
Clay__measureTextHashMap = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measuredWords = Clay__MeasuredWordArray_Allocate_Arena(CLAY_MEASURE_TEXT_CACHE_SIZE, arena);
Clay__pointerOverIds = Clay__ElementIdArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__debugElementData = Clay__DebugElementDataArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__layoutElementsHashMapInternal = Clay__LayoutElementHashMapItemArray_Allocate_Arena(Clay__maxElementCount, 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__measureTextCacheSize, arena);
Clay__measureTextHashMap = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, 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;
}
@ -2304,7 +2296,13 @@ void Clay__AddRenderCommand(Clay_RenderCommand renderCommand) {
if (Clay__renderCommands.length < Clay__renderCommands.capacity - 1) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, renderCommand);
} else {
Clay__booleanWarnings.maxRenderCommandsExceeded = true;
if (!Clay__booleanWarnings.maxRenderCommandsExceeded) {
Clay__booleanWarnings.maxRenderCommandsExceeded = true;
Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
.errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
.errorText = CLAY_STRING("Clay ran out of capacity while attempting to create render commands. This is usually caused by a large amount of wrapping text elements while close to the max element capacity. Try using Clay_SetMaxElementCount() with a higher value."),
.userData = Clay__errorHandler.userData });
}
}
}
@ -2342,7 +2340,6 @@ void Clay__CalculateFinalLayout() {
int32_t wordIndex = measureTextCacheItem->measuredWordsStartIndex;
while (wordIndex != -1) {
if (Clay__wrappedTextLines.length > Clay__wrappedTextLines.capacity - 1) {
Clay__booleanWarnings.maxStringMeasureCacheExceeded = true;
break;
}
Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&Clay__measuredWords, wordIndex);
@ -2855,40 +2852,37 @@ void Clay__CalculateFinalLayout() {
}
void Clay__AttachId(Clay_ElementId elementId) {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
openLayoutElement->id = elementId.id;
Clay__AddHashMapItem(elementId, openLayoutElement);
Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId);
#ifdef CLAY_DEBUG
openLayoutElement->name = elementId.stringId;
#endif
}
void Clay__AttachLayoutConfig(Clay_LayoutConfig *config) {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay__GetOpenLayoutElement()->layoutConfig = config;
}
void Clay__AttachElementConfig(Clay_ElementConfigUnion config, Clay__ElementConfigType type) {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
openLayoutElement->elementConfigs.length++;
Clay__ElementConfigArray_Add(&Clay__elementConfigBuffer, CLAY__INIT(Clay_ElementConfig) { .type = type, .config = config });
}
Clay_LayoutConfig * Clay__StoreLayoutConfig(Clay_LayoutConfig config) { return Clay__debugMaxElementsLatch ? &CLAY_LAYOUT_DEFAULT : Clay__LayoutConfigArray_Add(&Clay__layoutConfigs, config); }
Clay_RectangleElementConfig * Clay__StoreRectangleElementConfig(Clay_RectangleElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT : Clay__RectangleElementConfigArray_Add(&Clay__rectangleElementConfigs, config); }
Clay_TextElementConfig * Clay__StoreTextElementConfig(Clay_TextElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__TEXT_ELEMENT_CONFIG_DEFAULT : Clay__TextElementConfigArray_Add(&Clay__textElementConfigs, config); }
Clay_ImageElementConfig * Clay__StoreImageElementConfig(Clay_ImageElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT : Clay__ImageElementConfigArray_Add(&Clay__imageElementConfigs, config); }
Clay_FloatingElementConfig * Clay__StoreFloatingElementConfig(Clay_FloatingElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT : Clay__FloatingElementConfigArray_Add(&Clay__floatingElementConfigs, config); }
Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay__customElementConfigs, config); }
Clay_ScrollElementConfig * Clay__StoreScrollElementConfig(Clay_ScrollElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT : Clay__ScrollElementConfigArray_Add(&Clay__scrollElementConfigs, config); }
Clay_BorderElementConfig * Clay__StoreBorderElementConfig(Clay_BorderElementConfig config) { return Clay__debugMaxElementsLatch ? &CLAY__BORDER_ELEMENT_CONFIG_DEFAULT : Clay__BorderElementConfigArray_Add(&Clay__borderElementConfigs, config); }
Clay_LayoutConfig * Clay__StoreLayoutConfig(Clay_LayoutConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY_LAYOUT_DEFAULT : Clay__LayoutConfigArray_Add(&Clay__layoutConfigs, config); }
Clay_RectangleElementConfig * Clay__StoreRectangleElementConfig(Clay_RectangleElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT : Clay__RectangleElementConfigArray_Add(&Clay__rectangleElementConfigs, config); }
Clay_TextElementConfig * Clay__StoreTextElementConfig(Clay_TextElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__TEXT_ELEMENT_CONFIG_DEFAULT : Clay__TextElementConfigArray_Add(&Clay__textElementConfigs, config); }
Clay_ImageElementConfig * Clay__StoreImageElementConfig(Clay_ImageElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT : Clay__ImageElementConfigArray_Add(&Clay__imageElementConfigs, config); }
Clay_FloatingElementConfig * Clay__StoreFloatingElementConfig(Clay_FloatingElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT : Clay__FloatingElementConfigArray_Add(&Clay__floatingElementConfigs, config); }
Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay__customElementConfigs, config); }
Clay_ScrollElementConfig * Clay__StoreScrollElementConfig(Clay_ScrollElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT : Clay__ScrollElementConfigArray_Add(&Clay__scrollElementConfigs, config); }
Clay_BorderElementConfig * Clay__StoreBorderElementConfig(Clay_BorderElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__BORDER_ELEMENT_CONFIG_DEFAULT : Clay__BorderElementConfigArray_Add(&Clay__borderElementConfigs, config); }
#pragma region DebugTools
Clay_Color CLAY__DEBUGVIEW_COLOR_1 = CLAY__INIT(Clay_Color) {58, 56, 52, 255};
@ -3514,7 +3508,7 @@ void Clay_SetLayoutDimensions(Clay_Dimensions dimensions) {
CLAY_WASM_EXPORT("Clay_SetPointerState")
void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay__pointerInfo.position = position;
@ -3581,7 +3575,7 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
}
CLAY_WASM_EXPORT("Clay_Initialize")
void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions) {
void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) {
Clay__internalArena = arena;
Clay__InitializePersistentMemory(&Clay__internalArena);
Clay__InitializeEphemeralMemory(&Clay__internalArena);
@ -3593,6 +3587,7 @@ void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions) {
}
Clay__measureTextHashMapInternal.length = 1; // Reserve the 0 value to mean "no next element"
Clay__layoutDimensions = layoutDimensions;
Clay__errorHandler = errorHandler;
}
CLAY_WASM_EXPORT("Clay_UpdateScrollContainers")
@ -3718,9 +3713,9 @@ void Clay_BeginLayout() {
if (Clay__debugModeEnabled) {
rootDimensions.width -= (float)Clay__debugViewWidth;
}
if (Clay__debugMaxElementsLatch) {
return;
}
Clay__booleanWarnings.maxElementsExceeded = false;
Clay__booleanWarnings.maxTextMeasureCacheExceeded = false;
Clay__booleanWarnings.maxRenderCommandsExceeded = false;
Clay__OpenElement();
CLAY_ID("Clay__RootContainer");
CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED((rootDimensions.width)), CLAY_SIZING_FIXED(rootDimensions.height)} });
@ -3736,16 +3731,12 @@ Clay_RenderCommandArray Clay_EndLayout()
{
Clay__CloseElement();
if (Clay__debugModeEnabled) {
#ifndef CLAY_DEBUG
Clay__warningsEnabled = false;
#endif
Clay__RenderDebugView();
#ifndef CLAY_DEBUG
Clay__warningsEnabled = true;
#endif
}
if (Clay__debugMaxElementsLatch) {
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) { .boundingBox = { Clay__layoutDimensions.width / 2 - 59 * 4, Clay__layoutDimensions.height / 2 }, .config = { .textElementConfig = &Clay__DebugView_ErrorTextConfig }, .text = CLAY_STRING("Clay Error: Layout elements exceeded CLAY_MAX_ELEMENT_COUNT"), .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT });
if (Clay__booleanWarnings.maxElementsExceeded) {
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) { .boundingBox = { Clay__layoutDimensions.width / 2 - 59 * 4, Clay__layoutDimensions.height / 2 }, .config = { .textElementConfig = &Clay__DebugView_ErrorTextConfig }, .text = CLAY_STRING("Clay Error: Layout elements exceeded Clay__maxElementCount"), .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT });
} else {
Clay__CalculateFinalLayout();
}
@ -3763,7 +3754,7 @@ Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index)
}
bool Clay_Hovered() {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return false;
}
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
@ -3780,7 +3771,7 @@ bool Clay_Hovered() {
}
void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerInfo, intptr_t userData), intptr_t userData) {
if (Clay__debugMaxElementsLatch) {
if (Clay__booleanWarnings.maxElementsExceeded) {
return;
}
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
@ -3834,6 +3825,16 @@ void Clay_SetExternalScrollHandlingEnabled(bool enabled) {
Clay__externalScrollHandlingEnabled = enabled;
}
CLAY_WASM_EXPORT("Clay_SetMaxElementCount")
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,11 +202,24 @@ 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) {
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = (Clay_Arena) { .label = CLAY_STRING("Clay Memory Arena"), .memory = malloc(totalMemorySize), .capacity = totalMemorySize };
Clay_SetMeasureTextFunction(Raylib_MeasureText);
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)GetScreenWidth(), (float)GetScreenHeight() });
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)GetScreenWidth(), (float)GetScreenHeight() }, (Clay_ErrorHandler) { HandleClayErrors });
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"));
Raylib_fonts[FONT_ID_BODY_24] = (Raylib_Font) {
@ -226,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;

View File

@ -1,5 +1,5 @@
$TYPE$ *$NAME$_Add($NAME$ *array, $TYPE$ item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}

View File

@ -1,5 +1,5 @@
void $NAME$_Add($NAME$ *array, $TYPE$ item) {
if (Clay__Array_IncrementCapacityCheck(array->length, array->capacity)) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
}
}

View File

@ -1,13 +1,6 @@
void $NAME$_Set($NAME$ *array, int index, $TYPE$ value) {
if (index < array->capacity && index >= 0) {
if (Clay__Array_RangeCheck(index, array->capacity)) {
array->internalArray[index] = value;
array->length = index < array->length ? array->length : index + 1;
} else {
if (Clay__warningsEnabled) {
Clay__WarningArray_Add(&Clay_warnings, CLAY__INIT(Clay__Warning) { CLAY_STRING("Attempting to allocate array in arena, but arena is already at capacity and would overflow.") });
}
#ifdef CLAY_OVERFLOW_TRAP
raise(SIGTRAP);
#endif
}
}