Compare commits

...

6 Commits

Author SHA1 Message Date
Johann Muszynski
6b4ee6c851
Merge 517442381c into 08e4c5b198 2025-03-26 07:16:20 +00:00
Johann Muszynski
517442381c Add struct names to public structs 2025-03-26 09:16:08 +02:00
Nic Barker
08e4c5b198 [Core] Fix a bug where ID aliases werent copied on hash collision
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
2025-03-26 09:35:15 +13:00
ellie-but-backwards
b1c72a0647
[Bindings/Odin] Remove field hashStringContents in odin bindings (#350) 2025-03-26 09:21:35 +13:00
Igor Karatayev
aee4baee1c
[Core] Guard against hashmap item null dereference (#338) 2025-03-26 09:19:50 +13:00
Nic Barker
47d1d84bc8
[Core] Switch text content hashing to default behaviour (#335)
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-03-25 10:13:04 +13:00
8 changed files with 187 additions and 76 deletions

View File

@ -17,6 +17,7 @@ when ODIN_OS == .Windows {
} }
String :: struct { String :: struct {
isStaticallyAllocated: c.bool,
length: c.int32_t, length: c.int32_t,
chars: [^]c.char, chars: [^]c.char,
} }
@ -110,7 +111,6 @@ TextElementConfig :: struct {
lineHeight: u16, lineHeight: u16,
wrapMode: TextWrapMode, wrapMode: TextWrapMode,
textAlignment: TextAlignment, textAlignment: TextAlignment,
hashStringContents: bool,
} }
ImageElementConfig :: struct { ImageElementConfig :: struct {
@ -419,7 +419,13 @@ UI :: proc() -> proc (config: ElementDeclaration) -> bool {
return ConfigureOpenElement return ConfigureOpenElement
} }
Text :: proc(text: string, config: ^TextElementConfig) { Text :: proc($text: string, config: ^TextElementConfig) {
wrapped := MakeString(text)
wrapped.isStaticallyAllocated = true
_OpenTextElement(wrapped, config)
}
TextDynamic :: proc(text: string, config: ^TextElementConfig) {
_OpenTextElement(MakeString(text), config) _OpenTextElement(MakeString(text), config)
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -62,7 +62,7 @@ border2pxRed := clay.BorderElementConfig {
color = COLOR_RED color = COLOR_RED
} }
LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, text: string, image: ^raylib.Texture2D) { LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, $text: string, image: ^raylib.Texture2D) {
if clay.UI()({ if clay.UI()({
id = clay.ID("HeroBlob", index), id = clay.ID("HeroBlob", index),
layout = { sizing = { width = clay.SizingGrow({ max = 480 }) }, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{ y = .Center } }, layout = { sizing = { width = clay.SizingGrow({ max = 480 }) }, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{ y = .Center } },
@ -252,7 +252,7 @@ ColorLerp :: proc(a: clay.Color, b: clay.Color, amount: f32) -> clay.Color {
return clay.Color{a.r + (b.r - a.r) * amount, a.g + (b.g - a.g) * amount, a.b + (b.b - a.b) * amount, a.a + (b.a - a.a) * amount} return clay.Color{a.r + (b.r - a.r) * amount, a.g + (b.g - a.g) * amount, a.b + (b.b - a.b) * amount, a.a + (b.a - a.a) * amount}
} }
LOREM_IPSUM_TEXT := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." LOREM_IPSUM_TEXT :: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) { HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
if clay.UI()({ id = clay.ID("PerformanceLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) { if clay.UI()({ id = clay.ID("PerformanceLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
@ -321,7 +321,7 @@ HighPerformancePageMobile :: proc(lerpValue: f32) {
} }
} }
RendererButtonActive :: proc(index: i32, text: string) { RendererButtonActive :: proc(index: i32, $text: string) {
if clay.UI()({ if clay.UI()({
layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) }, layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) },
backgroundColor = COLOR_RED, backgroundColor = COLOR_RED,
@ -331,7 +331,7 @@ RendererButtonActive :: proc(index: i32, text: string) {
} }
} }
RendererButtonInactive :: proc(index: u32, text: string) { RendererButtonInactive :: proc(index: u32, $text: string) {
if clay.UI()({ border = border2pxRed }) { if clay.UI()({ border = border2pxRed }) {
if clay.UI()({ if clay.UI()({
id = clay.ID("RendererButtonInactiveInner", index), id = clay.ID("RendererButtonInactiveInner", index),

245
clay.h
View File

@ -96,9 +96,9 @@
#define CLAY__ENSURE_STRING_LITERAL(x) ("" x "") #define CLAY__ENSURE_STRING_LITERAL(x) ("" x "")
// Note: If an error led you here, it's because CLAY_STRING can only be used with string literals, i.e. CLAY_STRING("SomeString") and not CLAY_STRING(yourString) // Note: If an error led you here, it's because CLAY_STRING can only be used with string literals, i.e. CLAY_STRING("SomeString") and not CLAY_STRING(yourString)
#define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) }) #define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .isStaticallyAllocated = true, .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) })
#define CLAY_STRING_CONST(string) { .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) } #define CLAY_STRING_CONST(string) { .isStaticallyAllocated = true, .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) }
static uint8_t CLAY__ELEMENT_DEFINITION_LATCH; static uint8_t CLAY__ELEMENT_DEFINITION_LATCH;
@ -184,7 +184,10 @@ extern "C" {
// Note: Clay_String is not guaranteed to be null terminated. It may be if created from a literal C string, // Note: Clay_String is not guaranteed to be null terminated. It may be if created from a literal C string,
// but it is also used to represent slices. // but it is also used to represent slices.
typedef struct { typedef struct Clay_String {
// Set this boolean to true if the char* data underlying this string will live for the entire lifetime of the program.
// This will automatically be set for strings created with CLAY_STRING, as the macro requires a string literal.
bool isStaticallyAllocated;
int32_t length; int32_t length;
// The underlying character memory. Note: this will not be copied and will not extend the lifetime of the underlying memory. // The underlying character memory. Note: this will not be copied and will not extend the lifetime of the underlying memory.
const char *chars; const char *chars;
@ -192,7 +195,7 @@ typedef struct {
// Clay_StringSlice is used to represent non owning string slices, and includes // Clay_StringSlice is used to represent non owning string slices, and includes
// a baseChars field which points to the string this slice is derived from. // a baseChars field which points to the string this slice is derived from.
typedef struct { typedef struct Clay_StringSlice {
int32_t length; int32_t length;
const char *chars; const char *chars;
const char *baseChars; // The source string / char* that this slice was derived from const char *baseChars; // The source string / char* that this slice was derived from
@ -202,33 +205,33 @@ typedef struct Clay_Context Clay_Context;
// Clay_Arena is a memory arena structure that is used by clay to manage its internal allocations. // Clay_Arena is a memory arena structure that is used by clay to manage its internal allocations.
// Rather than creating it by hand, it's easier to use Clay_CreateArenaWithCapacityAndMemory() // Rather than creating it by hand, it's easier to use Clay_CreateArenaWithCapacityAndMemory()
typedef struct { typedef struct Clay_Arena {
uintptr_t nextAllocation; uintptr_t nextAllocation;
size_t capacity; size_t capacity;
char *memory; char *memory;
} Clay_Arena; } Clay_Arena;
typedef struct { typedef struct Clay_Dimensions {
float width, height; float width, height;
} Clay_Dimensions; } Clay_Dimensions;
typedef struct { typedef struct Clay_Vector2 {
float x, y; float x, y;
} Clay_Vector2; } Clay_Vector2;
// Internally clay conventionally represents colors as 0-255, but interpretation is up to the renderer. // Internally clay conventionally represents colors as 0-255, but interpretation is up to the renderer.
typedef struct { typedef struct Clay_Color {
float r, g, b, a; float r, g, b, a;
} Clay_Color; } Clay_Color;
typedef struct { typedef struct Clay_BoundingBox {
float x, y, width, height; float x, y, width, height;
} Clay_BoundingBox; } Clay_BoundingBox;
// Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros. // Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
// Represents a hashed string ID used for identifying and finding specific clay UI elements, required // Represents a hashed string ID used for identifying and finding specific clay UI elements, required
// by functions such as Clay_PointerOver() and Clay_GetElementData(). // by functions such as Clay_PointerOver() and Clay_GetElementData().
typedef struct { typedef struct Clay_ElementId {
uint32_t id; // The resulting hash generated from the other fields. uint32_t id; // The resulting hash generated from the other fields.
uint32_t offset; // A numerical offset applied after computing the hash from stringId. uint32_t offset; // A numerical offset applied after computing the hash from stringId.
uint32_t baseId; // A base hash value to start from, for example the parent element ID is used when calculating CLAY_ID_LOCAL(). uint32_t baseId; // A base hash value to start from, for example the parent element ID is used when calculating CLAY_ID_LOCAL().
@ -237,7 +240,7 @@ typedef struct {
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images. // Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
// The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels. // The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
typedef struct { typedef struct Clay_CornerRadius {
float topLeft; float topLeft;
float topRight; float topRight;
float bottomLeft; float bottomLeft;
@ -287,20 +290,20 @@ typedef CLAY_PACKED_ENUM {
} Clay__SizingType; } Clay__SizingType;
// Controls how child elements are aligned on each axis. // Controls how child elements are aligned on each axis.
typedef struct { typedef struct Clay_ChildAlignment {
Clay_LayoutAlignmentX x; // Controls alignment of children along the x axis. Clay_LayoutAlignmentX x; // Controls alignment of children along the x axis.
Clay_LayoutAlignmentY y; // Controls alignment of children along the y axis. Clay_LayoutAlignmentY y; // Controls alignment of children along the y axis.
} Clay_ChildAlignment; } Clay_ChildAlignment;
// Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to, // Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to,
// overriding sizing types such as FIT or GROW. // overriding sizing types such as FIT or GROW.
typedef struct { typedef struct Clay_SizingMinMax {
float min; // The smallest final size of the element on this axis will be this value in pixels. float min; // The smallest final size of the element on this axis will be this value in pixels.
float max; // The largest final size of the element on this axis will be this value in pixels. float max; // The largest final size of the element on this axis will be this value in pixels.
} Clay_SizingMinMax; } Clay_SizingMinMax;
// Controls the sizing of this element along one axis inside its parent container. // Controls the sizing of this element along one axis inside its parent container.
typedef struct { typedef struct Clay_SizingAxis {
union { union {
Clay_SizingMinMax minMax; // Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to, overriding sizing types such as FIT or GROW. Clay_SizingMinMax minMax; // Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to, overriding sizing types such as FIT or GROW.
float percent; // Expects 0-1 range. Clamps the axis size to a percent of the parent container's axis size minus padding and child gaps. float percent; // Expects 0-1 range. Clamps the axis size to a percent of the parent container's axis size minus padding and child gaps.
@ -309,14 +312,14 @@ typedef struct {
} Clay_SizingAxis; } Clay_SizingAxis;
// Controls the sizing of this element along one axis inside its parent container. // Controls the sizing of this element along one axis inside its parent container.
typedef struct { typedef struct Clay_Sizing {
Clay_SizingAxis width; // Controls the width sizing of the element, along the x axis. Clay_SizingAxis width; // Controls the width sizing of the element, along the x axis.
Clay_SizingAxis height; // Controls the height sizing of the element, along the y axis. Clay_SizingAxis height; // Controls the height sizing of the element, along the y axis.
} Clay_Sizing; } Clay_Sizing;
// Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children // Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children
// will be placed. // will be placed.
typedef struct { typedef struct Clay_Padding {
uint16_t left; uint16_t left;
uint16_t right; uint16_t right;
uint16_t top; uint16_t top;
@ -327,7 +330,7 @@ CLAY__WRAPPER_STRUCT(Clay_Padding);
// Controls various settings that affect the size and position of an element, as well as the sizes and positions // Controls various settings that affect the size and position of an element, as well as the sizes and positions
// of any child elements. // of any child elements.
typedef struct { typedef struct Clay_LayoutConfig {
Clay_Sizing sizing; // Controls the sizing of this element inside it's parent container, including FIT, GROW, PERCENT and FIXED sizing. Clay_Sizing sizing; // Controls the sizing of this element inside it's parent container, including FIT, GROW, PERCENT and FIXED sizing.
Clay_Padding padding; // Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children will be placed. Clay_Padding padding; // Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children will be placed.
uint16_t childGap; // Controls the gap in pixels between child elements along the layout axis (horizontal gap for LEFT_TO_RIGHT, vertical gap for TOP_TO_BOTTOM). uint16_t childGap; // Controls the gap in pixels between child elements along the layout axis (horizontal gap for LEFT_TO_RIGHT, vertical gap for TOP_TO_BOTTOM).
@ -360,7 +363,7 @@ typedef CLAY_PACKED_ENUM {
} Clay_TextAlignment; } Clay_TextAlignment;
// Controls various functionality related to text elements. // Controls various functionality related to text elements.
typedef struct { typedef struct Clay_TextElementConfig {
// A pointer that will be transparently passed through to the resulting render command. // A pointer that will be transparently passed through to the resulting render command.
void *userData; void *userData;
// The RGBA color of the font to render, conventionally specified as 0-255. // The RGBA color of the font to render, conventionally specified as 0-255.
@ -384,10 +387,6 @@ typedef struct {
// CLAY_TEXT_ALIGN_CENTER - Horizontally aligns wrapped lines of text to the center of their bounding box. // CLAY_TEXT_ALIGN_CENTER - Horizontally aligns wrapped lines of text to the center of their bounding box.
// CLAY_TEXT_ALIGN_RIGHT - Horizontally aligns wrapped lines of text to the right hand side of their bounding box. // CLAY_TEXT_ALIGN_RIGHT - Horizontally aligns wrapped lines of text to the right hand side of their bounding box.
Clay_TextAlignment textAlignment; Clay_TextAlignment textAlignment;
// When set to true, clay will hash the entire text contents of this string as an identifier for its internal
// text measurement cache, rather than just the pointer and length. This will incur significant performance cost for
// long bodies of text.
bool hashStringContents;
} Clay_TextElementConfig; } Clay_TextElementConfig;
CLAY__WRAPPER_STRUCT(Clay_TextElementConfig); CLAY__WRAPPER_STRUCT(Clay_TextElementConfig);
@ -419,7 +418,7 @@ typedef CLAY_PACKED_ENUM {
} Clay_FloatingAttachPointType; } Clay_FloatingAttachPointType;
// Controls where a floating element is offset relative to its parent element. // Controls where a floating element is offset relative to its parent element.
typedef struct { typedef struct Clay_FloatingAttachPoints {
Clay_FloatingAttachPointType element; // Controls the origin point on a floating element that attaches to its parent. Clay_FloatingAttachPointType element; // Controls the origin point on a floating element that attaches to its parent.
Clay_FloatingAttachPointType parent; // Controls the origin point on the parent element that the floating element attaches to. Clay_FloatingAttachPointType parent; // Controls the origin point on the parent element that the floating element attaches to.
} Clay_FloatingAttachPoints; } Clay_FloatingAttachPoints;
@ -448,7 +447,7 @@ typedef CLAY_PACKED_ENUM {
// Controls various settings related to "floating" elements, which are elements that "float" above other elements, potentially overlapping their boundaries, // Controls various settings related to "floating" elements, which are elements that "float" above other elements, potentially overlapping their boundaries,
// and not affecting the layout of sibling or parent elements. // and not affecting the layout of sibling or parent elements.
typedef struct { typedef struct Clay_FloatingElementConfig {
// Offsets this floating element by the provided x,y coordinates from its attachPoints. // Offsets this floating element by the provided x,y coordinates from its attachPoints.
Clay_Vector2 offset; Clay_Vector2 offset;
// Expands the boundaries of the outer floating element without affecting its children. // Expands the boundaries of the outer floating element without affecting its children.
@ -481,7 +480,7 @@ CLAY__WRAPPER_STRUCT(Clay_FloatingElementConfig);
// Custom ----------------------------- // Custom -----------------------------
// Controls various settings related to custom elements. // Controls various settings related to custom elements.
typedef struct { typedef struct Clay_CustomElementConfig {
// A transparent pointer through which you can pass custom data to the renderer. // A transparent pointer through which you can pass custom data to the renderer.
// Generates CUSTOM render commands. // Generates CUSTOM render commands.
void* customData; void* customData;
@ -492,7 +491,7 @@ CLAY__WRAPPER_STRUCT(Clay_CustomElementConfig);
// Scroll ----------------------------- // Scroll -----------------------------
// Controls the axis on which an element switches to "scrolling", which clips the contents and allows scrolling in that direction. // Controls the axis on which an element switches to "scrolling", which clips the contents and allows scrolling in that direction.
typedef struct { typedef struct Clay_ScrollElementConfig {
bool horizontal; // Clip overflowing elements on the X axis and allow scrolling left and right. bool horizontal; // Clip overflowing elements on the X axis and allow scrolling left and right.
bool vertical; // Clip overflowing elements on the YU axis and allow scrolling up and down. bool vertical; // Clip overflowing elements on the YU axis and allow scrolling up and down.
} Clay_ScrollElementConfig; } Clay_ScrollElementConfig;
@ -502,7 +501,7 @@ CLAY__WRAPPER_STRUCT(Clay_ScrollElementConfig);
// Border ----------------------------- // Border -----------------------------
// Controls the widths of individual element borders. // Controls the widths of individual element borders.
typedef struct { typedef struct Clay_BorderWidth {
uint16_t left; uint16_t left;
uint16_t right; uint16_t right;
uint16_t top; uint16_t top;
@ -514,7 +513,7 @@ typedef struct {
} Clay_BorderWidth; } Clay_BorderWidth;
// Controls settings related to element borders. // Controls settings related to element borders.
typedef struct { typedef struct Clay_BorderElementConfig {
Clay_Color color; // Controls the color of all borders with width > 0. Conventionally represented as 0-255, but interpretation is up to the renderer. Clay_Color color; // Controls the color of all borders with width > 0. Conventionally represented as 0-255, but interpretation is up to the renderer.
Clay_BorderWidth width; // Controls the widths of individual borders. At least one of these should be > 0 for a BORDER render command to be generated. Clay_BorderWidth width; // Controls the widths of individual borders. At least one of these should be > 0 for a BORDER render command to be generated.
} Clay_BorderElementConfig; } Clay_BorderElementConfig;
@ -524,7 +523,7 @@ CLAY__WRAPPER_STRUCT(Clay_BorderElementConfig);
// Render Command Data ----------------------------- // Render Command Data -----------------------------
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
typedef struct { typedef struct Clay_TextRenderData {
// A string slice containing the text to be rendered. // A string slice containing the text to be rendered.
// Note: this is not guaranteed to be null terminated. // Note: this is not guaranteed to be null terminated.
Clay_StringSlice stringContents; Clay_StringSlice stringContents;
@ -540,7 +539,7 @@ typedef struct {
} Clay_TextRenderData; } Clay_TextRenderData;
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
typedef struct { typedef struct Clay_RectangleRenderData {
// The solid background color to fill this rectangle with. Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer. // The solid background color to fill this rectangle with. Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
Clay_Color backgroundColor; Clay_Color backgroundColor;
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images. // Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
@ -549,7 +548,7 @@ typedef struct {
} Clay_RectangleRenderData; } Clay_RectangleRenderData;
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_IMAGE // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_IMAGE
typedef struct { typedef struct Clay_ImageRenderData {
// The tint color for this image. Note that the default value is 0,0,0,0 and should likely be interpreted // The tint color for this image. Note that the default value is 0,0,0,0 and should likely be interpreted
// as "untinted". // as "untinted".
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer. // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
@ -564,7 +563,7 @@ typedef struct {
} Clay_ImageRenderData; } Clay_ImageRenderData;
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM
typedef struct { typedef struct Clay_CustomRenderData {
// Passed through from .backgroundColor in the original element declaration. // Passed through from .backgroundColor in the original element declaration.
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer. // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
Clay_Color backgroundColor; Clay_Color backgroundColor;
@ -576,13 +575,13 @@ typedef struct {
} Clay_CustomRenderData; } Clay_CustomRenderData;
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START || commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_END // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START || commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_END
typedef struct { typedef struct Clay_ScrollRenderData {
bool horizontal; bool horizontal;
bool vertical; bool vertical;
} Clay_ScrollRenderData; } Clay_ScrollRenderData;
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER
typedef struct { typedef struct Clay_BorderRenderData {
// Controls a shared color for all this element's borders. // Controls a shared color for all this element's borders.
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer. // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
Clay_Color color; Clay_Color color;
@ -594,7 +593,7 @@ typedef struct {
} Clay_BorderRenderData; } Clay_BorderRenderData;
// A struct union containing data specific to this command's .commandType // A struct union containing data specific to this command's .commandType
typedef union { typedef union Clay_RenderData {
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
Clay_RectangleRenderData rectangle; Clay_RectangleRenderData rectangle;
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
@ -612,7 +611,7 @@ typedef union {
// Miscellaneous Structs & Enums --------------------------------- // Miscellaneous Structs & Enums ---------------------------------
// Data representing the current internal state of a scrolling element. // Data representing the current internal state of a scrolling element.
typedef struct { typedef struct Clay_ScrollContainerData {
// Note: This is a pointer to the real internal scroll position, mutating it may cause a change in final layout. // Note: This is a pointer to the real internal scroll position, mutating it may cause a change in final layout.
// Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling. // Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling.
Clay_Vector2 *scrollPosition; Clay_Vector2 *scrollPosition;
@ -627,7 +626,7 @@ typedef struct {
} Clay_ScrollContainerData; } Clay_ScrollContainerData;
// Bounding box and other data for a specific UI element. // Bounding box and other data for a specific UI element.
typedef struct { typedef struct Clay_ElementData {
// The rectangle that encloses this UI element, with the position relative to the root of the layout. // The rectangle that encloses this UI element, with the position relative to the root of the layout.
Clay_BoundingBox boundingBox; Clay_BoundingBox boundingBox;
// Indicates whether an actual Element matched the provided ID or if the default struct was returned. // Indicates whether an actual Element matched the provided ID or if the default struct was returned.
@ -654,7 +653,7 @@ typedef CLAY_PACKED_ENUM {
CLAY_RENDER_COMMAND_TYPE_CUSTOM, CLAY_RENDER_COMMAND_TYPE_CUSTOM,
} Clay_RenderCommandType; } Clay_RenderCommandType;
typedef struct { typedef struct Clay_RenderCommand {
// A rectangular box that fully encloses this UI element, with the position relative to the root of the layout. // A rectangular box that fully encloses this UI element, with the position relative to the root of the layout.
Clay_BoundingBox boundingBox; Clay_BoundingBox boundingBox;
// A struct union containing data specific to this command's commandType. // A struct union containing data specific to this command's commandType.
@ -679,7 +678,7 @@ typedef struct {
} Clay_RenderCommand; } Clay_RenderCommand;
// A sized array of render commands. // A sized array of render commands.
typedef struct { typedef struct Clay_RenderCommandArray {
// The underlying max capacity of the array, not necessarily all initialized. // The underlying max capacity of the array, not necessarily all initialized.
int32_t capacity; int32_t capacity;
// The number of initialized elements in this array. Used for loops and iteration. // The number of initialized elements in this array. Used for loops and iteration.
@ -701,7 +700,7 @@ typedef CLAY_PACKED_ENUM {
} Clay_PointerDataInteractionState; } Clay_PointerDataInteractionState;
// Information on the current state of pointer interactions this frame. // Information on the current state of pointer interactions this frame.
typedef struct { typedef struct Clay_PointerData {
// The position of the mouse / touch / pointer relative to the root of the layout. // The position of the mouse / touch / pointer relative to the root of the layout.
Clay_Vector2 position; Clay_Vector2 position;
// Represents the current state of interaction with clay this frame. // Represents the current state of interaction with clay this frame.
@ -712,7 +711,7 @@ typedef struct {
Clay_PointerDataInteractionState state; Clay_PointerDataInteractionState state;
} Clay_PointerData; } Clay_PointerData;
typedef struct { typedef struct Clay_ElementDeclaration {
// Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros. // Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
// Represents a hashed string ID used for identifying and finding specific clay UI elements, required by functions such as Clay_PointerOver() and Clay_GetElementData(). // Represents a hashed string ID used for identifying and finding specific clay UI elements, required by functions such as Clay_PointerOver() and Clay_GetElementData().
Clay_ElementId id; Clay_ElementId id;
@ -763,7 +762,7 @@ typedef CLAY_PACKED_ENUM {
} Clay_ErrorType; } Clay_ErrorType;
// Data to identify the error that clay has encountered. // Data to identify the error that clay has encountered.
typedef struct { typedef struct Clay_ErrorData {
// Represents the type of error clay encountered while computing layout. // Represents the type of error clay encountered while computing layout.
// CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED - A text measurement function wasn't provided using Clay_SetMeasureTextFunction(), or the provided function was null. // CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED - A text measurement function wasn't provided using Clay_SetMeasureTextFunction(), or the provided function was null.
// CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED - Clay attempted to allocate its internal data structures but ran out of space. The arena passed to Clay_Initialize was created with a capacity smaller than that required by Clay_MinMemorySize(). // CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED - Clay attempted to allocate its internal data structures but ran out of space. The arena passed to Clay_Initialize was created with a capacity smaller than that required by Clay_MinMemorySize().
@ -876,8 +875,7 @@ CLAY_DLL_EXPORT int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
// Modifies the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache. // Modifies the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
// This may require reallocating additional memory, and re-calling Clay_Initialize(); // This may require reallocating additional memory, and re-calling Clay_Initialize();
CLAY_DLL_EXPORT void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount); CLAY_DLL_EXPORT void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
// Resets Clay's internal text measurement cache, useful if memory to represent strings is being re-used. // Resets Clay's internal text measurement cache. Useful if font mappings have changed or fonts have been reloaded.
// Similar behaviour can be achieved on an individual text element level by using Clay_TextElementConfig.hashStringContents
CLAY_DLL_EXPORT void Clay_ResetMeasureTextCache(void); CLAY_DLL_EXPORT void Clay_ResetMeasureTextCache(void);
// Internal API functions required by macros ---------------------- // Internal API functions required by macros ----------------------
@ -1348,26 +1346,140 @@ Clay_ElementId Clay__HashString(Clay_String key, const uint32_t offset, const ui
return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = offset, .baseId = base + 1, .stringId = key }; // Reserve the hash result of zero as "null id" return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = offset, .baseId = base + 1, .stringId = key }; // Reserve the hash result of zero as "null id"
} }
uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *config) { #if !defined(CLAY_DISABLE_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64))
uint32_t hash = 0; static inline __m128i Clay__SIMDRotateLeft(__m128i x, int r) {
uintptr_t pointerAsNumber = (uintptr_t)text->chars; return _mm_or_si128(_mm_slli_epi64(x, r), _mm_srli_epi64(x, 64 - r));
}
if (config->hashStringContents) { static inline void Clay__SIMDARXMix(__m128i* a, __m128i* b) {
uint32_t maxLengthToHash = CLAY__MIN(text->length, 256); *a = _mm_add_epi64(*a, *b);
for (uint32_t i = 0; i < maxLengthToHash; i++) { *b = _mm_xor_si128(Clay__SIMDRotateLeft(*b, 17), *a);
hash += text->chars[i]; }
hash += (hash << 10);
hash ^= (hash >> 6); uint64_t Clay__HashData(const uint8_t* data, size_t length) {
// Pinched these constants from the BLAKE implementation
__m128i v0 = _mm_set1_epi64x(0x6a09e667f3bcc908ULL);
__m128i v1 = _mm_set1_epi64x(0xbb67ae8584caa73bULL);
__m128i v2 = _mm_set1_epi64x(0x3c6ef372fe94f82bULL);
__m128i v3 = _mm_set1_epi64x(0xa54ff53a5f1d36f1ULL);
uint8_t overflowBuffer[16] = { 0 }; // Temporary buffer for small inputs
while (length > 0) {
__m128i msg;
if (length >= 16) {
msg = _mm_loadu_si128((const __m128i*)data);
data += 16;
length -= 16;
} }
} else { else {
hash += pointerAsNumber; for (int i = 0; i < length; i++) {
overflowBuffer[i] = data[i];
}
msg = _mm_loadu_si128((const __m128i*)overflowBuffer);
length = 0;
}
v0 = _mm_xor_si128(v0, msg);
Clay__SIMDARXMix(&v0, &v1);
Clay__SIMDARXMix(&v2, &v3);
v0 = _mm_add_epi64(v0, v2);
v1 = _mm_add_epi64(v1, v3);
}
Clay__SIMDARXMix(&v0, &v1);
Clay__SIMDARXMix(&v2, &v3);
v0 = _mm_add_epi64(v0, v2);
v1 = _mm_add_epi64(v1, v3);
uint64_t result[2];
_mm_storeu_si128((__m128i*)result, v0);
return result[0] ^ result[1];
}
#elif !defined(CLAY_DISABLE_SIMD) && defined(__aarch64__)
static inline uint64x2_t Clay__SIMDRotateLeft(uint64x2_t x, int r) {
return vorrq_u64(vshlq_n_u64(x, 17), vshrq_n_u64(x, 64 - 17));
}
static inline void Clay__SIMDARXMix(uint64x2_t* a, uint64x2_t* b) {
*a = vaddq_u64(*a, *b);
*b = veorq_u64(Clay__SIMDRotateLeft(*b, 17), *a);
}
uint64_t Clay__HashData(const uint8_t* data, size_t length) {
// Pinched these constants from the BLAKE implementation
uint64x2_t v0 = vdupq_n_u64(0x6a09e667f3bcc908ULL);
uint64x2_t v1 = vdupq_n_u64(0xbb67ae8584caa73bULL);
uint64x2_t v2 = vdupq_n_u64(0x3c6ef372fe94f82bULL);
uint64x2_t v3 = vdupq_n_u64(0xa54ff53a5f1d36f1ULL);
uint8_t overflowBuffer[8] = { 0 };
while (length > 0) {
uint64x2_t msg;
if (length > 16) {
msg = vld1q_u64((const uint64_t*)data);
data += 16;
length -= 16;
}
else if (length > 8) {
msg = vcombine_u64(vld1_u64((const uint64_t*)data), vdup_n_u64(0));
data += 8;
length -= 8;
}
else {
for (int i = 0; i < length; i++) {
overflowBuffer[i] = data[i];
}
uint8x8_t lower = vld1_u8(overflowBuffer);
msg = vcombine_u8(lower, vdup_n_u8(0));
length = 0;
}
v0 = veorq_u64(v0, msg);
Clay__SIMDARXMix(&v0, &v1);
Clay__SIMDARXMix(&v2, &v3);
v0 = vaddq_u64(v0, v2);
v1 = vaddq_u64(v1, v3);
}
Clay__SIMDARXMix(&v0, &v1);
Clay__SIMDARXMix(&v2, &v3);
v0 = vaddq_u64(v0, v2);
v1 = vaddq_u64(v1, v3);
uint64_t result[2];
vst1q_u64(result, v0);
return result[0] ^ result[1];
}
#else
uint64_t Clay__HashData(const uint8_t* data, size_t length) {
uint64_t hash = 0;
for (int32_t i = 0; i < length; i++) {
hash += data[i];
hash += (hash << 10); hash += (hash << 10);
hash ^= (hash >> 6); hash ^= (hash >> 6);
} }
return hash;
}
#endif
hash += text->length; uint32_t Clay__HashStringContentsWithConfig(Clay_String *text, Clay_TextElementConfig *config) {
hash += (hash << 10); uint32_t hash = 0;
hash ^= (hash >> 6); if (text->isStaticallyAllocated) {
hash += (uintptr_t)text->chars;
hash += (hash << 10);
hash ^= (hash >> 6);
hash += text->length;
hash += (hash << 10);
hash ^= (hash >> 6);
} else {
hash = Clay__HashData((const uint8_t *)text->chars, text->length) % UINT32_MAX;
}
hash += config->fontId; hash += config->fontId;
hash += (hash << 10); hash += (hash << 10);
@ -1377,18 +1489,10 @@ uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *con
hash += (hash << 10); hash += (hash << 10);
hash ^= (hash >> 6); hash ^= (hash >> 6);
hash += config->lineHeight;
hash += (hash << 10);
hash ^= (hash >> 6);
hash += config->letterSpacing; hash += config->letterSpacing;
hash += (hash << 10); hash += (hash << 10);
hash ^= (hash >> 6); hash ^= (hash >> 6);
hash += config->wrapMode;
hash += (hash << 10);
hash ^= (hash >> 6);
hash += (hash << 3); hash += (hash << 3);
hash ^= (hash >> 11); hash ^= (hash >> 11);
hash += (hash << 15); hash += (hash << 15);
@ -1423,7 +1527,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
return &Clay__MeasureTextCacheItem_DEFAULT; return &Clay__MeasureTextCacheItem_DEFAULT;
} }
#endif #endif
uint32_t id = Clay__HashTextWithConfig(text, config); uint32_t id = Clay__HashStringContentsWithConfig(text, config);
uint32_t hashBucket = id % (context->maxMeasureTextCacheWordCount / 32); uint32_t hashBucket = id % (context->maxMeasureTextCacheWordCount / 32);
int32_t elementIndexPrevious = 0; int32_t elementIndexPrevious = 0;
int32_t elementIndex = context->measureTextHashMap.internalArray[hashBucket]; int32_t elementIndex = context->measureTextHashMap.internalArray[hashBucket];
@ -1566,6 +1670,7 @@ Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Cl
item.nextIndex = hashItem->nextIndex; item.nextIndex = hashItem->nextIndex;
if (hashItem->generation <= context->generation) { // First collision - assume this is the "same" element if (hashItem->generation <= context->generation) { // First collision - assume this is the "same" element
hashItem->elementId = elementId; // Make sure to copy this across. If the stringId reference has changed, we should update the hash item to use the new one. hashItem->elementId = elementId; // Make sure to copy this across. If the stringId reference has changed, we should update the hash item to use the new one.
hashItem->idAlias = idAlias;
hashItem->generation = context->generation + 1; hashItem->generation = context->generation + 1;
hashItem->layoutElement = layoutElement; hashItem->layoutElement = layoutElement;
hashItem->debugData->collision = false; hashItem->debugData->collision = false;
@ -3706,10 +3811,10 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(currentElement->id); // TODO think of a way around this, maybe the fact that it's essentially a binary tree limits the cost, but the worst case is not great Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(currentElement->id); // TODO think of a way around this, maybe the fact that it's essentially a binary tree limits the cost, but the worst case is not great
int32_t clipElementId = Clay__int32_tArray_GetValue(&context->layoutElementClipElementIds, (int32_t)(currentElement - context->layoutElements.internalArray)); int32_t clipElementId = Clay__int32_tArray_GetValue(&context->layoutElementClipElementIds, (int32_t)(currentElement - context->layoutElements.internalArray));
Clay_LayoutElementHashMapItem *clipItem = Clay__GetHashMapItem(clipElementId); Clay_LayoutElementHashMapItem *clipItem = Clay__GetHashMapItem(clipElementId);
Clay_BoundingBox elementBox = mapItem->boundingBox;
elementBox.x -= root->pointerOffset.x;
elementBox.y -= root->pointerOffset.y;
if (mapItem) { if (mapItem) {
Clay_BoundingBox elementBox = mapItem->boundingBox;
elementBox.x -= root->pointerOffset.x;
elementBox.y -= root->pointerOffset.y;
if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)))) { if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)))) {
if (mapItem->onHoverFunction) { if (mapItem->onHoverFunction) {
mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData); mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData);