Added C3 Bindings

This commit is contained in:
Jefferey Schlueter 2025-01-28 23:49:19 -05:00
parent e9f2e6c4f1
commit f48ee0b9fd
7 changed files with 5858 additions and 0 deletions

73
bindings/c3/README.md Normal file
View File

@ -0,0 +1,73 @@
# Clay-C3-Bindings
C3 Bindings for [Clay](https://github.com/nicbarker/clay.git), a UI layout library written in C.
This directory contains the clay.c3 bindings file as well as a recreation of the clay-raylibs binding and the video-example raylib project.
Special thanks to:
- [Christoffer L](https://github.com/lerno) C3's core developer (as I understand it)
- Book-reader in the [C3-lang Discord](https://discord.gg/qN76R87)
## TODO:
- Find out how to build a static-lib with additional C sources
## - C3 macros
Traditional Clay C Macro System
```cpp
/* FILTER BUTTON */
CLAY(
CLAY_ID("FilterButton"),
Clay_Hovered() ? CLAY_RECTANGLE({
.color = Clay_Hovered() ? FIRE_ORANGE : (Clay_Color){80, 25, 200, 255},
.cornerRadius = 8,
}) : 0,
CLAY_LAYOUT({
.sizing = {
.width = CLAY_SIZING_FIT(),
.height = CLAY_SIZING_GROW()
},
.padding = 10
})
) {
// define children...
}
```
Clay C3 Macro System
```cpp
/* FILTER BUTTON */
clay::clay(
clay::id("FilterButton"),
clay::@bodyIf(clay::hovered(), clay::rectangle({
.color = clay::hovered() ? FIRE_ORANGE : {80, 25, 200, 255},
.cornerRadius = clay::cornerRadiusUni(8)
})
),
clay::layout({
.sizing = {
.width = clay::sizingFit(),
.height = clay::sizingGrow()
},
.padding = clay::paddingUni(8)
})
){
// define children...
};
```
## To Get Started:
- Download c3c [here](https://c3-lang.org/getting-started/prebuilt-binaries/)
- If you wish to compile the website-example, I've already provided a target to build in the [project.json](project.json)
[Photo of project.json goes here]
- - set your `cd` to this project dir
- - The use the `c3c vendor-fetch raylib55` command to download a c3 compressed archive of raylib
- - - *once you have raylib55.c3l in the [lib](lib) folder you've got it right*
- - - (*note: for the current configuration you'll need to modify the default raylib module name in th raylib.c3i file in [build](build) directory from `raylib55::li` to `module raylib`*)
- - then simple use the command `c3c run video-example` to compile and run that video example
- - - (*note: to use the `c3c build <target>` command with video-example, you'll need to copy the resource folder into the [build](build) directory with the execute to run it
- - - `run` executes the build result from the project directory, somehow. This means that `run` will look for the resource folder in [c3](../c3), while `build` will look for it in [build](build))
## RESOURCES:
### - [C3](https://github.com/c3lang/c3c.git) (A C-a-like, that aims to bring modern language QA features and a revamped Macro system to C)
### - [Raylib](https://github.com/raysan5/raylib.git) (C Videogame and Graphical API)
### - [Lexend](https://github.com/googlefonts/lexend.git) (Accessible/ Dyslexic Friendly Font)

File diff suppressed because it is too large Load Diff

33
bindings/c3/project.json Normal file
View File

@ -0,0 +1,33 @@
{
"langrev": "1",
"authors": [ "Jefferey Schlueter <jefferey.l.schlueter@gmail.com>" ],
"version": "0.1.0",
"targets": {
// TODO: found out how to stop this from outputting a .lib and .pdb in addition to the .exe (they don't do anything)
"video-example": {
"output": "build/video-example/",
"c-sources": [ "c-lang/source/clay.c" ],
"cflags": "-DCLAY_IMPLEMENTATION", // makes the clay source actually define things
"type": "executable",
"dependency-search-paths": [ "lib" ],
"dependencies": [ "raylib55" ],
"sources": [ "source/clay.c3", "source/clay-raylib-renderer.c3", "examples/video-example.c3" ],
// "link-libc": false, // TODO; leads to duplicate definitions (eg math_nolibc)
// "use-stdlib": false, // TODO: leads to ZString being undefined -> then mising main @main_to_void_main
// "features": ["NO_STDLIB"]
},
// TODO: figure out why creating static/dynamic libraries with C sources doesn't work (emits no errors just crashes out and dumps an empty clay-win.h into the project dir)
// "clay-win": {
// "output": "build/clay.c3l/windows-x64",
// "c-sources": [ "c-lang/source/clay.c" ],
// "sources": [ "source/clay.c3" ],
// "type": "static-lib"
// },
// build args with no C references
//../c3c.exe --link-libc=no --use-stdlib=no -o clay --template static-lib --output-dir build/clay.c3l/windows-x64 --print-linking --print-output -vvv static-lib source/clay-slim.c3
},
"cc": "gcc",
"cpu": "generic",
}

Binary file not shown.

View File

@ -0,0 +1,700 @@
// TODO: including additional structures required for Clay_Context led to bloat
// module clay;
// // import std::core::cinterop ;
// import clay::carray;
// // =======================
// // ===== USER MACROS =====
// // =======================
// macro @clay(...; @body()) @builtin
// {
// clay::openElement();
// $for (var $i = 0; $i < $vacount; $i++)
// $vaexpr[$i]; // If you get an error here consisder the @body[...]() macros
// $endfor
// clay::elementPostConfiguration();
// @body();
// clay::closeElement();
// }
// macro text(String text, TextElementConfig *config) { clay::openTextElement({text.len, text}, config); }
// <*Provides you conditional calls (eg #booleanCondition ? #doA : 0) within the condifuration of @clay(...)*>
// macro @bodyIf(#condition, #ifRes) { if (#condition) { #ifRes; } }
// <*Provides you conditional calls (eg #booleanCondition ? #doA : #doB) within the condifuration of @clay(...)*>
// macro @bodyIfElse(#condition, #ifRes, #elseRes) { if (#condition) { #ifRes; } else { #elseRes; } }
// // <*Facilitates non-method calls (eg { #doWhatever }, { #booleanExpression ? #doA : #doB}, etc.) within the parameters of @clay(...)*>
// // macro @inline(; @body()) { @body(); }
// <*attaches a RectangleElementConfig to the clay element when called within @clay(...)*>
// macro rectangle(RectangleElementConfig config) { clay::attachElementConfig({ .rectangleElementConfig = clay::storeRectangleElementConfig(config) }, clay::ELEMENT_CONFIG_TYPE_RECTANGLE ); }
// <*attaches a LayoutConfig to the clay element when called within @clay(...)*>
// macro layout(LayoutConfig config) { clay::attachLayoutConfig( clay::storeLayoutConfig(config) ); }
// <*attaches a LayoutConfig to the clay element when called within @clay(...)*>
// macro scroll(ScrollElementConfig config) { clay::attachElementConfig({ .scrollElementConfig = clay::storeScrollElementConfig(config) }, clay::ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER ); }
// <*attaches a FloatingElementConfig to the clay element when called within @clay(...)*>
// macro floating(FloatingElementConfig config) { clay::attachElementConfig({ .floatingElementConfig = clay::storeFloatingElementConfig(config) }, clay::ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER ); }
// <*attaches a BorderElementConfig to the clay element when called within @clay(...)*>
// macro @borderRadiusUni(uint #width, ClayColor #color, float #cornerRadius = 0) { clay::attachElementConfig({ .borderElementConfig = clay::storeBorderElementConfig({ .left = { #width, #color }, .right = { #width, #color }, .top = { #width, #color }, .bottom = { #width, #color }, .#cornerRadius = {#cornerRadius, #cornerRadius, #cornerRadius, #cornerRadius}})}, clay::ELEMENT_CONFIG_TYPE_BORDER_CONTAINER); }
// macro id(String idString) { clay::attachId(clay::hashString({idString.len, idString}, 0, 0)); }
// macro TextElementConfig* textConfig(TextElementConfig config) { return clay::storeTextElementConfig(config); }
// macro SizingAxis sizingFit(float min = 0, float max = float.max) { return { .size.minMax = {min, max}, .type = SizingType.FIT }; }
// macro SizingAxis sizingGrow() { return { .size.minMax = {0, 0}, .type = SizingType.GROW }; }
// macro SizingAxis sizingFixed(float pixels) { return { .size.minMax = {pixels, pixels}, .type = SizingType.FIXED }; }
// macro SizingAxis sizingPercent(float percent) { return { .size.percent = percent, .type = SizingType.PERCENT }; }
// macro Padding paddingUni(ushort uniform) { return {uniform, uniform, uniform, uniform}; }
// macro Padding padding(ushort horizontal, ushort vertical) { return {horizontal, horizontal, vertical, vertical}; }
// macro CornerRadius cornerRadiusUni(float uniform) { return {uniform, uniform, uniform, uniform}; }
// macro SizingAxis sizingFitCT(float $min = 0, float $max = float.max) { return { .size.minMax = {$min, $max}, .type = SizingType.FIT }; }
// macro SizingAxis sizingFixedCT(float $pixels) { return { .size.minMax = {$pixels, $pixels}, .type = SizingType.FIXED }; }
// macro SizingAxis sizingPercentCT(float $percent) { return { .size.percent = $percent, .type = SizingType.PERCENT }; }
// macro Padding paddingCT(ushort $a, ushort $b, ushort $c, ushort $d) { return { $a, $b, $c, $d }; }
// macro CornerRadius @cornerRadiusUniCT(float #uniform) { return {#uniform, #uniform, #uniform, #uniform}; }
// // ===================
// // ===== STRUCTS =====
// // ===================
// struct ClayString
// {
// int length;
// char *chars;
// }
// def ClayStringArray = carray::Array(<ClayString>) @private;
// struct Arena
// {
// uint128 nextAllocation;
// uint128 capacity;
// char *memory;
// }
// struct Dimensions
// {
// float width, height;
// }
// struct ClayVector2
// {
// float x, y;
// }
// struct ClayColor
// {
// float r, g, b, a;
// }
// struct ClayBoundingBox
// {
// float x, y, width, height;
// }
// struct ElementId
// {
// uint id;
// uint offset;
// uint baseId;
// ClayString stringId;
// }
// struct CornerRadius
// {
// float topLeft;
// float topRight;
// float bottomLeft;
// float bottomRight;
// }
// // ===== Element Configs =====
// distinct ElementConfigType @private = char;
// const ElementConfigType ELEMENT_CONFIG_TYPE_NONE @private = 0;
// const ElementConfigType ELEMENT_CONFIG_TYPE_RECTANGLE @private = 1;
// const ElementConfigType ELEMENT_CONFIG_TYPE_BORDER_CONTAINER @private = 2;
// const ElementConfigType ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER @private = 4;
// const ElementConfigType ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER @private = 8;
// const ElementConfigType ELEMENT_CONFIG_TYPE_IMAGE @private = 16;
// const ElementConfigType ELEMENT_CONFIG_TYPE_TEXT @private = 32;
// const ElementConfigType ELEMENT_CONFIG_TYPE_CUSTOM @private = 64;
// enum LayoutDirection : char @export
// {
// LEFT_TO_RIGHT,
// TOP_TO_BOTTOM,
// }
// enum AlignX : char @export
// {
// LEFT,
// RIGHT,
// CENTER,
// }
// enum AlignY : char @export
// {
// TOP,
// BOTTOM,
// CENTER,
// }
// enum SizingType : char @export
// {
// FIT,
// GROW,
// PERCENT,
// FIXED,
// }
// struct ChildAlignment
// {
// AlignX x;
// AlignY y;
// }
// struct SizingMinMax
// {
// float min;
// float max;
// }
// struct SizingAxis
// {
// union size
// {
// SizingMinMax minMax;
// float percent;
// }
// SizingType type;
// }
// struct Sizing
// {
// SizingAxis width;
// SizingAxis height;
// }
// struct Padding
// {
// ushort left;
// ushort right;
// ushort top;
// ushort bottom;
// }
// struct LayoutConfig
// {
// Sizing sizing;
// Padding padding;
// ushort childGap;
// ChildAlignment childAlignment;
// LayoutDirection layoutDirection;
// }
// struct RectangleElementConfig
// {
// ClayColor color;
// CornerRadius cornerRadius;
// // #ifdef CLAY_EXTEND_CONFIG_RECTANGLE
// // CLAY_EXTEND_CONFIG_RECTANGLE
// // #endif
// }
// enum WrapMode @export
// {
// WORDS,
// NEWLINES,
// NONE,
// }
// struct TextElementConfig
// {
// ClayColor textColor;
// ushort fontId;
// ushort fontSize;
// ushort letterSpacing;
// ushort lineHeight;
// WrapMode wrapMode;
// // #ifdef CLAY_EXTEND_CONFIG_TEXT
// // CLAY_EXTEND_CONFIG_TEXT
// // #endif
// }
// struct ImageElementConfig
// {
// void *imageData;
// Dimensions sourceDimensions;
// // #ifdef CLAY_EXTEND_CONFIG_IMAGE
// // CLAY_EXTEND_CONFIG_IMAGE
// // #endif
// }
// enum AttachPoint : char @export
// {
// LEFT_TOP,
// LEFT_CENTER,
// LEFT_BOTTOM,
// CENTER_TOP,
// CENTER_CENTER,
// CENTER_BOTTOM,
// RIGHT_TOP,
// RIGHT_CENTER,
// RIGHT_BOTTOM,
// }
// struct FloatingAttachPoints
// {
// AttachPoint element;
// AttachPoint parent;
// }
// enum PointerCaptureMode @export
// {
// CAPTURE,
// // MODE_PASSTHROUGH,
// PARENT,
// }
// struct FloatingElementConfig
// {
// ClayVector2 offset;
// Dimensions expand;
// ushort zIndex;
// uint parentId;
// FloatingAttachPoints attachment;
// PointerCaptureMode pointerCaptureMode;
// }
// struct CustomElementConfig
// {
// // #ifndef CLAY_EXTEND_CONFIG_CUSTOM
// void *customData;
// // #else
// // CLAY_EXTEND_CONFIG_CUSTOM
// // #endif
// }
// struct ScrollElementConfig
// {
// bool horizontal;
// bool vertical;
// }
// // Border
// struct Border
// {
// uint width;
// ClayColor color;
// }
// struct BorderElementConfig
// {
// Border left;
// Border right;
// Border top;
// Border bottom;
// Border betweenChildren;
// CornerRadius cornerRadius;
// // #ifdef CLAY_EXTEND_CONFIG_BORDER
// // CLAY_EXTEND_CONFIG_BORDER
// // #endif
// }
// union ElementConfigUnion
// {
// RectangleElementConfig *rectangleElementConfig;
// TextElementConfig *textElementConfig;
// ImageElementConfig *imageElementConfig;
// FloatingElementConfig *floatingElementConfig;
// CustomElementConfig *customElementConfig;
// ScrollElementConfig *scrollElementConfig;
// BorderElementConfig *borderElementConfig;
// }
// struct ElementConfig
// {
// ElementConfigType type;
// ElementConfigUnion config;
// }
// // Miscellaneous Structs & Enums ---------------------------------
// struct ScrollContainerData
// {
// // 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.
// ClayVector2 *scrollPosition;
// Dimensions scrollContainerDimensions;
// Dimensions contentDimensions;
// ScrollElementConfig config;
// // Indicates whether an actual scroll container matched the provided ID or if the default struct was returned.
// bool found;
// }
// <*
// @
// *>
// struct ElementData
// {
// ClayBoundingBox boundingBox;
// // Indicates whether an actual Element matched the provided ID or if the default struct was returned.
// bool found;
// }
// enum RenderCommandType : char @export
// {
// NONE,
// RECTANGLE,
// BORDER,
// TEXT,
// IMAGE,
// SCISSOR_START,
// SCISSOR_END,
// CUSTOM,
// }
// struct RenderCommand
// {
// ClayBoundingBox boundingBox;
// ElementConfigUnion config;
// ClayString text;
// uint id;
// RenderCommandType commandType;
// }
// def RenderCommandArray = carray::Array(<RenderCommand>);
// enum PointerState @export
// {
// PRESSED_THIS_FRAME,
// PRESSED,
// RELEASED_THIS_FRAME,
// RELEASED,
// }
// struct PointerData
// {
// ClayVector2 position;
// PointerState state;
// }
// enum ErrorType @export
// {
// TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED,
// ARENA_CAPACITY_EXCEEDED,
// ELEMENTS_CAPACITY_EXCEEDED,
// TEXT_MEASUREMENT_CAPACITY_EXCEEDED,
// DUPLICATE_ID,
// FLOATING_CONTAINER_PARENT_NOT_FOUND,
// INTERNAL_ERROR,
// }
// struct ErrorData
// {
// ErrorType errorType;
// ClayString errorText;
// uint128 userData;
// }
// def ErrorHandleFunc = fn void(ErrorData errorText);
// struct ErrorHandler
// {
// ErrorHandleFunc errorHandler;
// uint128 userData;
// }
// struct BooleanWarnings
// {
// bool maxElementsExceeded;
// bool maxRenderCommandsExceeded;
// bool maxTextMeasureCacheExceeded;
// }
// struct Warning
// {
// ClayString baseMessage;
// ClayString dynamicMessage;
// }
// def WarningArray = carray::Array(<Warning>);
// struct LayoutElementChildren
// {
// int *elements;
// ushort length;
// }
// struct LayoutElement
// {
// union childrenOrTextContent {
// LayoutElementChildren children;
// TextElementData *textElementData;
// }
// Dimensions dimensions;
// Dimensions minDimensions;
// LayoutConfig *layoutConfig;
// ElementConfigArraySlice elementConfigs;
// uint configsEnabled;
// uint id;
// }
// struct WrappedTextLine
// {
// Dimensions dimensions;
// ClayString line;
// }
// struct WrappedTextLineArraySlice
// {
// int length;
// WrappedTextLine *internalArray;
// }
// struct TextElementData
// {
// ClayString text;
// Dimensions preferredDimensions;
// int elementIndex;
// WrappedTextLineArraySlice wrappedLines;
// }
// struct ElementConfigArraySlice
// {
// int length;
// ElementConfig *internalArray;
// }
// def DebugElementData = bool[<2>];
// struct LayoutElementHashMapItem
// {
// ClayBoundingBox boundingBox;
// ElementId elementId;
// LayoutElement* layoutElement;
// OnHoverEvent onHoverFunction;
// int128 hoverFunctionUserData;
// int nextIndex;
// uint128 generation;
// DebugElementData *debugData;
// }
// struct LayoutElementTreeRoot @private
// {
// int layoutElementIndex;
// uint parentId; // This can be zero in the case of the root layout tree
// uint clipElementId; // This can be zero if there is no clip element
// int zIndex;
// ClayVector2 pointerOffset; // Only used when scroll containers are managed externally
// }
// struct LayoutElementTreeNode @private
// {
// LayoutElement *layoutElement;
// ClayVector2 position;
// ClayVector2 nextChildOffset;
// }
// struct MeasuredWord @private
// {
// int startOffset;
// int length;
// float width;
// int next;
// }
// struct MeasureTextCacheItem @private
// {
// Dimensions unwrappedDimensions;
// int measuredWordsStartIndex;
// bool containsNewlines;
// // Hash map data
// uint id;
// int nextIndex;
// uint generation;
// }
// def LayoutElementArray = carray::Array(<LayoutElement>);
// def CIntArray = carray::Array(<int>);
// def TextElementDataArray = carray::Array(<TextElementData>);
// def RectangleElementConfigArray = carray::Array(<RectangleElementConfig>);
// def TextElementConfigArray = carray::Array(<TextElementConfig>);
// def ImageElementConfigArray = carray::Array(<ImageElementConfig>);
// def FloatingElementConfigArray = carray::Array(<FloatingElementConfig>);
// def ScrollElementConfigArray = carray::Array(<ScrollElementConfig>);
// def CustomElementConfigArray = carray::Array(<CustomElementConfig>);
// def BorderElementConfigArray = carray::Array(<BorderElementConfig>);
// def LayoutElementPointerArray = carray::Array(<LayoutElement*>);
// def LayoutConfigArray = carray::Array(<LayoutConfig>);
// def ElementConfigArray = carray::Array(<ElementConfig>);
// def WrappedTextLineArray = carray::Array(<WrappedTextLine>);
// def LayoutElementTreeNodeArray = carray::Array(<LayoutElementTreeNode>);
// def LayoutElementTreeRootArray = carray::Array(<LayoutElementTreeRoot>);
// def LayoutElementHashMapItemArray = carray::Array(<LayoutElementHashMapItem>);
// def MeasureTextCacheItemArray = carray::Array(<MeasureTextCacheItem>);
// def MeasuredWordArray = carray::Array(<MeasuredWord>);
// def ElementIdArray = carray::Array(<ElementId>);
// def ScrollContainerDataInternalArray = carray::Array(<ScrollContainerData>);
// def BoolArray = carray::Array(<bool>);
// def CharArray = carray::Array(<char>);
// def DebugElementDataArray = carray::Array(<DebugElementData>);
// struct Context @extern ("Clay_Context")
// {
// int maxElementCount;
// int maxMeasureTextCacheWordCount;
// bool warningsEnabled;
// ErrorHandler errorHandler;
// BooleanWarnings booleanWarnings;
// WarningArray warnings;
// PointerData pointerInfo;
// Dimensions layoutDimensions;
// ElementId dynamicElementIndexBaseHash;
// uint dynamicElementIndex;
// bool debugModeEnabled;
// bool disableCulling;
// bool externalScrollHandlingEnabled;
// uint debugSelectedElementId;
// uint generation;
// uint128 arenaResetOffset;
// Arena internalArena;
// // Layout Elements / Render Commands
// LayoutElementArray layoutElements;
// RenderCommandArray renderCommands;
// CIntArray openLayoutElementStack;
// CIntArray layoutElementChildren;
// CIntArray layoutElementChildrenBuffer;
// TextElementDataArray textElementData;
// LayoutElementPointerArray imageElementPointers;
// CIntArray reusableElementIndexBuffer;
// CIntArray layoutElementClipElementIds;
// // Configs
// LayoutConfigArray layoutConfigs;
// ElementConfigArray elementConfigBuffer;
// ElementConfigArray elementConfigs;
// RectangleElementConfigArray rectangleElementConfigs;
// TextElementConfigArray textElementConfigs;
// ImageElementConfigArray imageElementConfigs;
// FloatingElementConfigArray floatingElementConfigs;
// ScrollElementConfigArray scrollElementConfigs;
// CustomElementConfigArray customElementConfigs;
// BorderElementConfigArray borderElementConfigs;
// // Misc Data Structures
// ClayStringArray layoutElementIdStrings;
// WrappedTextLineArray wrappedTextLines;
// LayoutElementTreeNodeArray layoutElementTreeNodeArray1;
// LayoutElementTreeRootArray layoutElementTreeRoots;
// LayoutElementHashMapItemArray layoutElementsHashMapInternal;
// CIntArray layoutElementsHashMap;
// MeasureTextCacheItemArray measureTextHashMapInternal;
// CIntArray measureTextHashMapInternalFreeList;
// CIntArray measureTextHashMap;
// MeasuredWordArray measuredWords;
// CIntArray measuredWordsFreeList;
// CIntArray openClipElementStack;
// ElementIdArray pointerOverIds;
// ScrollContainerDataInternalArray scrollContainerDatas;
// BoolArray treeNodeVisited;
// CharArray dynamicStringData;
// DebugElementDataArray debugElementData;
// }
// def OnHoverEvent = fn void(ElementId elementId, PointerData pointerData, iptr userData);
// def MeasureTextFunc = fn Dimensions(ClayString *text, TextElementConfig *config);
// def QueryScrollOffsetFunc = fn ClayVector2(uint elementId);
// // =====================
// // ===== FUNCTIONS =====
// // =====================
// // ===== Public Clay API C3 Functions (String replacement) =====
// fn ElementId getElementIdWithIndex(String idString, uint index) @export @inline
// { return __getElementIdWithIndex({idString.len, idString}, (uint)index); }
// fn ElementId getElementId(String idString) @export @inline
// { return __getElementId({idString.len, idString}); }
// // ===== Public Clay API Functions =====
// extern fn uint minMemorySize() @extern("Clay_MinMemorySize") @wasm @export;
// extern fn Arena createArena(uint capacity, void* offset) @extern("Clay_CreateArenaWithCapacityAndMemory") @wasm @export;
// extern fn void setPointerState(ClayVector2 position, bool pointerDown) @extern("Clay_SetPointerState") @export;
// extern fn Context* initialize(Arena arena, Dimensions layoutDimensions, ErrorHandler errorHandler) @extern("Clay_Initialize") @wasm @export;
// extern fn Context* getCurrentContext() @extern("Clay_GetCurrentContext") @export;
// extern fn void setCurrentContext(Context* context) @extern("Clay_SetCurrentContext") @export;
// extern fn void updateScrollContainer(bool enableDragScrolling, ClayVector2 scrollDelta, float deltaTime) @extern("Clay_UpdateScrollContainers") @export;
// extern fn void setLayoutDimensions (Dimensions dimensions) @extern("Clay_SetLayoutDimensions") @export;
// extern fn ElementData getElementData(ElementId id) @extern("Clay_GetElementData") @export;
// extern fn bool hovered() @extern("Clay_Hovered") @export;
// extern fn void onHover(OnHoverEvent onHover, iptr userData) @extern("Clay_OnHover") @export;
// extern fn bool pointerOver(ElementId elementId) @extern("Clay_PointerOver") @wasm @export;
// extern fn ScrollContainerData getScrollContainerData(ElementId id) @extern("Clay_GetScrollContainerData") @export;
// extern fn void setMeasureTextFunction(MeasureTextFunc measureText) @extern("Clay_SetMeasureTextFunction") @export;
// extern fn void setQueryScrollOffsetFunction(QueryScrollOffsetFunc queryScrollOffset) @extern("Clay_SetQueryScrollOffsetFunction") @export;
// extern fn RenderCommand * RenderCommandArray.get(RenderCommandArray* array, int index) @extern("Clay_RenderCommandArray_Get") @export;
// extern fn void setDebugModeEnabled(bool enabled) @extern("Clay_SetDebugModeEnabled") @export;
// extern fn bool isDebugModeEnabled() @extern("Clay_IsDebugModeEnabled") @export;
// extern fn void setCullingEnabled(bool enabled) @extern("Clay_SetCullingEnabled") @export;
// extern fn int getMaxMeasuredTextCachedWordCount() @extern("Clay_GetMaxElementCount") @export;
// extern fn void setMaxElementCount(int maxElementCount) @extern("Clay_SetMaxElementCount") @export;
// extern fn int getMaxElementCount() @extern("Clay_GetMaxMeasureTextCacheWordCount") @export;
// extern fn void setMaxMeasureTextCacheWordCount(int maxMeasureTextCacheWordCount) @extern("Clay_SetMaxMeasureTextCacheWordCount") @export;
// extern fn void resetMeasureTextCache() @extern("Clay_ResetMeasureTextCache") @export;
// extern fn void beginLayout() @extern("Clay_BeginLayout") @export;
// extern fn RenderCommandArray endLayout() @extern("Clay_EndLayout") @export;
// // ===== (NEW) Internal Clay API Functions (String replacement) =====
// extern fn ElementId __getElementIdWithIndex(ClayString idString, uint index) @extern("Clay_GetElementIdWithIndex") @export @private;
// extern fn ElementId __getElementId(ClayString idString) @extern("Clay_GetElementId") @export @private;
// // ===== Internal Clay API Functions =====
// extern fn void openElement() @extern ("Clay__OpenElement") @export @private;
// extern fn void closeElement() @extern("Clay__CloseElement") @export @private;
// extern fn void openTextElement(ClayString text, TextElementConfig *textConfig) @extern("Clay__OpenTextElement") @export @private;
// extern fn void elementPostConfiguration() @extern("Clay__ElementPostConfiguration") @export @private;
// extern fn LayoutConfig * storeLayoutConfig(LayoutConfig config) @extern("Clay__StoreLayoutConfig") @export @private;
// extern fn void attachId(ElementId id) @extern("Clay__AttachId") @export @private;
// extern fn void attachLayoutConfig(LayoutConfig *config) @extern("Clay__AttachLayoutConfig") @export @private;
// extern fn void attachElementConfig(ElementConfigUnion config, ElementConfigType type) @extern("Clay__AttachElementConfig") @export @private;
// extern fn RectangleElementConfig * storeRectangleElementConfig(RectangleElementConfig config) @extern("Clay__StoreRectangleElementConfig") @export @private;
// extern fn TextElementConfig * storeTextElementConfig(TextElementConfig config) @extern("Clay__StoreTextElementConfig") @export @private;
// extern fn ImageElementConfig * storeImageElementConfig(ImageElementConfig config) @extern("Clay__StoreImageElementConfig") @export @private;
// extern fn FloatingElementConfig * storeFloatingElementConfig(FloatingElementConfig config) @extern("Clay__StoreFloatingElementConfig") @export @private;
// extern fn CustomElementConfig * storeCustomElementConfig(CustomElementConfig config) @extern("Clay__StoreCustomElementConfig") @export @private;
// extern fn ScrollElementConfig * storeScrollElementConfig(ScrollElementConfig config) @extern("Clay__StoreScrollElementConfig") @export @private;
// extern fn BorderElementConfig * storeBorderElementConfig(BorderElementConfig config) @extern("Clay__StoreBorderElementConfig") @export @private;
// extern fn ElementId hashString(ClayString key, uint offset, uint seed) @extern("Clay__HashString") @export @private;
// extern fn uint getParentElementId() @extern("Clay__GetParentElementId") @export @private;
// // ==========================================================================
// // ===== An internal module for wrapping Struct Array's defined in Clay =====
// // ==========================================================================
// module clay::carray(<ElementType>);
// struct Array {
// int capacity;
// int length;
// ElementType *data;
// }

View File

@ -0,0 +1,448 @@
module raylib @if($feature(NO_STDLIB));
distinct ZString = inline char*;
module clay::renderer;
import raylib;
// TODO: this entire file was very rushed so it can probably be cleaned up a LOT
fn double calculate_sine(double x) {
double term = x;
double sum = term;
double n = 1;
for (int i = 1; i <= 10; i++) {
term *= (-1) * x * x / ((2 * n) * (2 * n + 1));
sum += term;
n++;
}
return sum;
}
fn double calculate_cosine(double x) {
double term = 1;
double sum = term;
double n = 1;
for (int i = 1; i <= 10; i++) {
term *= (-1) * x * x / ((2 * n - 1) * (2 * n));
sum += term;
n++;
}
return sum;
}
macro double calculate_tangent(double x) {
double sine = calculate_sine(x);
double cosine = calculate_cosine(x);
// Check for cases where cosine is zero (tangent is undefined)
if (cosine == 0.0) {
return 0.0;
}
return sine / cosine;
}
fn Color clayToRaylibColor(ClayColor color) @inline
{
return { (char)$$round(color.r), (char)$$round(color.g), (char)$$round(color.b), (char)$$round(color.a)};
}
struct RaylibFont
{
int fontId;
raylib::Font font;
}
RaylibFont[10] raylibFonts;
raylib::Camera raylibCamera;
const Matrix MATRIX_IDENTITY = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
enum CustomLayoutElementType
{
MODEL_3D
}
struct Model3DLayoutElement
{
raylib::Model model;
float scale;
raylib::Vector3 position;
raylib::Matrix rotation;
}
struct CustomLayoutElement
{
CustomLayoutElementType type;
union element
{
Model3DLayoutElement model;
}
}
fn Matrix matrixPerspective(double fovY, double aspect, double nearPlane, double farPlane)
{
Matrix result = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0 };
double top = nearPlane * calculate_tangent(fovY*0.5*raylib::RAD2DEG);
double bottom = -top;
double right = top*aspect;
double left = -right;
// MatrixFrustum(-right, right, -top, top, near, far);
float rl = (float)(right - left);
float tb = (float)(top - bottom);
float far_near = (float)(farPlane - nearPlane);
result.m0 = ((float)nearPlane*2.0f)/rl;
result.m5 = ((float)nearPlane*2.0f)/tb;
result.m8 = ((float)right + (float)left)/rl;
result.m9 = ((float)top + (float)bottom)/tb;
result.m10 = -((float)farPlane + (float)nearPlane)/far_near;
result.m11 = -1.0f;
result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/far_near;
return result;
}
fn Vector3 vector3Unproject(Vector3 source, Matrix projection, Matrix view)
{
Vector3 result = { 0, 0, 0 };
// Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it
Matrix matViewProj = { // MatrixMultiply(view, projection);
view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12,
view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13,
view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14,
view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15,
view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12,
view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13,
view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14,
view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15,
view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12,
view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13,
view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14,
view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15,
view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12,
view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13,
view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14,
view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 };
// Calculate inverted matrix . MatrixInvert(matViewProj);
// Cache the matrix values (speed optimization)
float a00 = matViewProj.m0;
float a01 = matViewProj.m1;
float a02 = matViewProj.m2;
float a03 = matViewProj.m3;
float a10 = matViewProj.m4;
float a11 = matViewProj.m5;
float a12 = matViewProj.m6;
float a13 = matViewProj.m7;
float a20 = matViewProj.m8;
float a21 = matViewProj.m9;
float a22 = matViewProj.m10;
float a23 = matViewProj.m11;
float a30 = matViewProj.m12;
float a31 = matViewProj.m13;
float a32 = matViewProj.m14;
float a33 = matViewProj.m15;
float b00 = a00*a11 - a01*a10;
float b01 = a00*a12 - a02*a10;
float b02 = a00*a13 - a03*a10;
float b03 = a01*a12 - a02*a11;
float b04 = a01*a13 - a03*a11;
float b05 = a02*a13 - a03*a12;
float b06 = a20*a31 - a21*a30;
float b07 = a20*a32 - a22*a30;
float b08 = a20*a33 - a23*a30;
float b09 = a21*a32 - a22*a31;
float b10 = a21*a33 - a23*a31;
float b11 = a22*a33 - a23*a32;
// Calculate the invert determinant (inlined to avoid double-caching)
float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
Matrix matViewProjInv = {
(a11*b11 - a12*b10 + a13*b09)*invDet,
(-a01*b11 + a02*b10 - a03*b09)*invDet,
(a31*b05 - a32*b04 + a33*b03)*invDet,
(-a21*b05 + a22*b04 - a23*b03)*invDet,
(-a10*b11 + a12*b08 - a13*b07)*invDet,
(a00*b11 - a02*b08 + a03*b07)*invDet,
(-a30*b05 + a32*b02 - a33*b01)*invDet,
(a20*b05 - a22*b02 + a23*b01)*invDet,
(a10*b10 - a11*b08 + a13*b06)*invDet,
(-a00*b10 + a01*b08 - a03*b06)*invDet,
(a30*b04 - a31*b02 + a33*b00)*invDet,
(-a20*b04 + a21*b02 - a23*b00)*invDet,
(-a10*b09 + a11*b07 - a12*b06)*invDet,
(a00*b09 - a01*b07 + a02*b06)*invDet,
(-a30*b03 + a31*b01 - a32*b00)*invDet,
(a20*b03 - a21*b01 + a22*b00)*invDet };
// Create quaternion from source point
raylib::Quaternion quat = { source.x, source.y, source.z, 1.0f };
// Multiply quat point by unprojecte matrix
raylib::Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv)
matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,
matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w,
matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w };
// Normalized world points in vectors
result.x = qtransformed.x/qtransformed.w;
result.y = qtransformed.y/qtransformed.w;
result.z = qtransformed.z/qtransformed.w;
return result;
}
fn Matrix matrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane)
{
Matrix result = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0 };
float rl = (float)(right - left);
float tb = (float)(top - bottom);
float far_near = (float)(farPlane - nearPlane);
result.m0 = 2.0f/rl;
result.m1 = 0.0f;
result.m2 = 0.0f;
result.m3 = 0.0f;
result.m4 = 0.0f;
result.m5 = 2.0f/tb;
result.m6 = 0.0f;
result.m7 = 0.0f;
result.m8 = 0.0f;
result.m9 = 0.0f;
result.m10 = -2.0f/far_near;
result.m11 = 0.0f;
result.m12 = -((float)left + (float)right)/rl;
result.m13 = -((float)top + (float)bottom)/tb;
result.m14 = -((float)farPlane + (float)nearPlane)/far_near;
result.m15 = 1.0f;
return result;
}
fn Vector3 vector3Normalize(Vector3 v)
{
Vector3 result = v;
float length = $$sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
if (length != 0.0f)
{
float ilength = 1.0f/length;
result.x *= ilength;
result.y *= ilength;
result.z *= ilength;
}
return result;
}
fn Vector3 vector3Subtract(Vector3 v1, Vector3 v2)
{
Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
return result;
}
fn Ray getScreenToWorldPointWithZDistance(Vector2 position, Camera camera, int screenWidth, int screenHeight, float zDistance)
{
Ray ray = { {0,0,0}, {0,0,0} };
float x = (2.0f*position.x)/(float)screenWidth - 1.0f;
float y = 1.0f - (2.0f*position.y)/(float)screenHeight;
float z = 1.0f;
// Store values in a vector
Vector3 deviceCoords = { x, y, z };
// Calculate view matrix from camera look at
Matrix matView = raylib::getCameraMatrix(camera);
Matrix matProj = MATRIX_IDENTITY;
if (camera.projection == CameraProjection.PERSPECTIVE)
{
// Calculate projection matrix from perspective
matProj = matrixPerspective((double)(camera.fovy*raylib::DEG2RAD), ((double)screenWidth/(double)screenHeight), 0.01f, zDistance);
}
else if (camera.projection == CameraProjection.ORTHOGRAPHIC)
{
double aspect = (double)screenWidth/(double)screenHeight;
double top = camera.fovy/2.0;
double right = top*aspect;
// Calculate projection matrix from orthographic
matProj = matrixOrtho(-right, right, -top, top, 0.01, 1000.0);
}
// Unproject far/near points
Vector3 nearPoint = vector3Unproject({ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView);
Vector3 farPoint = vector3Unproject({ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
// Calculate normalized direction vector
Vector3 direction = vector3Normalize(vector3Subtract(farPoint, nearPoint));
ray.position = farPoint;
// Apply calculated vectors to ray
ray.direction = direction;
return ray;
}
fn Dimensions raylibMeasureText(ClayString *text, TextElementConfig *config)
{
// Measure string size for Font
Dimensions textSize = { 0, 0 };
float maxTextWidth = 0.0f;
float lineTextWidth = 0;
float textHeight = config.fontSize;
Font fontToUse = raylibFonts[config.fontId].font;
float scaleFactor = config.fontSize/(float)fontToUse.baseSize;
for (int i = 0; i < text.length; ++i)
{
if (text.chars[i] == '\n') {
maxTextWidth = $$max(maxTextWidth, lineTextWidth);
lineTextWidth = 0;
continue;
}
int index = text.chars[i] - 32;
if (fontToUse.glyphs[index].advanceX != 0) {lineTextWidth += fontToUse.glyphs[index].advanceX;}
else {lineTextWidth += (fontToUse.recs[index].width + fontToUse.glyphs[index].offsetX);}
}
maxTextWidth = $$max(maxTextWidth, lineTextWidth);
textSize.width = maxTextWidth * scaleFactor;
textSize.height = textHeight;
return textSize;
}
fn void raylibRender(RenderCommandArray renderCommands)
{
for (int j = 0; j < renderCommands.length; j++)
{
RenderCommand *renderCommand = renderCommands.get(j);
ClayBoundingBox boundingBox = renderCommand.boundingBox;
switch (renderCommand.commandType)
{
case RenderCommandType.TEXT: {
// Raylib uses standard C strings so isn't compatible with cheap slices, we need to clone the string to append null terminator
ClayString text = renderCommand.text;
ZString cloned = (ZString)malloc((ulong)text.length + 1);
$$memcpy(cloned, text.chars, (isz)text.length, false, (isz)0, (isz)0);
cloned[text.length] = '\0';
Font fontToUse = raylibFonts[renderCommand.config.textElementConfig.fontId].font;
raylib::drawTextEx(fontToUse, cloned, {boundingBox.x, boundingBox.y}, (float)renderCommand.config.textElementConfig.fontSize, (float)renderCommand.config.textElementConfig.letterSpacing, clayToRaylibColor(renderCommand.config.textElementConfig.textColor));
free(cloned);
break;
}
case RenderCommandType.IMAGE: {
Texture2D imageTexture = *(Texture2D *)renderCommand.config.imageElementConfig.imageData;
raylib::drawTextureEx(
imageTexture,
{boundingBox.x, boundingBox.y},
0,
boundingBox.width / (float)imageTexture.width,
raylib::WHITE);
break;
}
case RenderCommandType.SCISSOR_START: {
raylib::beginScissorMode((int)$$round(boundingBox.x), (int)$$round(boundingBox.y), (int)$$round(boundingBox.width), (int)$$round(boundingBox.height));
break;
}
case RenderCommandType.SCISSOR_END: {
raylib::endScissorMode();
break;
}
case RenderCommandType.RECTANGLE: {
RectangleElementConfig *config = renderCommand.config.rectangleElementConfig;
if (config.cornerRadius.topLeft > 0) {
float radius = (config.cornerRadius.topLeft * 2) / (float)(boundingBox.width > boundingBox.height ? boundingBox.height : boundingBox.width);
raylib::drawRectangleRounded({ boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height }, radius, 8, clayToRaylibColor(config.color));
} else {
raylib::drawRectangle((int)$$round(boundingBox.x), (int)$$round(boundingBox.y), (int)$$round(boundingBox.width), (int)$$round(boundingBox.height), clayToRaylibColor(config.color));
}
break;
}
case RenderCommandType.BORDER: {
BorderElementConfig *config = renderCommand.config.borderElementConfig;
// Left border
if (config.left.width > 0) {
raylib::drawRectangle((int)$$round(boundingBox.x), (int)$$round(boundingBox.y + config.cornerRadius.topLeft), (int)config.left.width, (int)$$round(boundingBox.height - config.cornerRadius.topLeft - config.cornerRadius.bottomLeft), clayToRaylibColor(config.left.color));
}
// Right border
if (config.right.width > 0) {
raylib::drawRectangle((int)$$round(boundingBox.x + boundingBox.width - config.right.width), (int)$$round(boundingBox.y + config.cornerRadius.topRight), (int)config.right.width, (int)$$round(boundingBox.height - config.cornerRadius.topRight - config.cornerRadius.bottomRight), clayToRaylibColor(config.right.color));
}
// Top border
if (config.top.width > 0) {
raylib::drawRectangle((int)$$round(boundingBox.x + config.cornerRadius.topLeft), (int)$$round(boundingBox.y), (int)$$round(boundingBox.width - config.cornerRadius.topLeft - config.cornerRadius.topRight), (int)config.top.width, clayToRaylibColor(config.top.color));
}
// Bottom border
if (config.bottom.width > 0) {
raylib::drawRectangle((int)$$round(boundingBox.x + config.cornerRadius.bottomLeft), (int)$$round(boundingBox.y + boundingBox.height - config.bottom.width), (int)$$round(boundingBox.width - config.cornerRadius.bottomLeft - config.cornerRadius.bottomRight), (int)config.bottom.width, clayToRaylibColor(config.bottom.color));
}
if (config.cornerRadius.topLeft > 0) {
raylib::drawRing({ $$round(boundingBox.x + config.cornerRadius.topLeft), $$round(boundingBox.y + config.cornerRadius.topLeft) }, $$round(config.cornerRadius.topLeft - config.top.width), config.cornerRadius.topLeft, 180, 270, 10, clayToRaylibColor(config.top.color));
}
if (config.cornerRadius.topRight > 0) {
raylib::drawRing({ $$round(boundingBox.x + boundingBox.width - config.cornerRadius.topRight), $$round(boundingBox.y + config.cornerRadius.topRight) }, $$round(config.cornerRadius.topRight - config.top.width), config.cornerRadius.topRight, 270, 360, 10, clayToRaylibColor(config.top.color));
}
if (config.cornerRadius.bottomLeft > 0) {
raylib::drawRing({ $$round(boundingBox.x + config.cornerRadius.bottomLeft), $$round(boundingBox.y + boundingBox.height - config.cornerRadius.bottomLeft) }, $$round(config.cornerRadius.bottomLeft - config.top.width), config.cornerRadius.bottomLeft, 90, 180, 10, clayToRaylibColor(config.bottom.color));
}
if (config.cornerRadius.bottomRight > 0) {
raylib::drawRing({ $$round(boundingBox.x + boundingBox.width - config.cornerRadius.bottomRight), $$round(boundingBox.y + boundingBox.height - config.cornerRadius.bottomRight) }, $$round(config.cornerRadius.bottomRight - config.bottom.width), config.cornerRadius.bottomRight, 0.1, 90, 10, clayToRaylibColor(config.bottom.color));
}
break;
}
case RenderCommandType.CUSTOM: {
CustomLayoutElement *customElement = (CustomLayoutElement *)renderCommand.config.customElementConfig.customData;
if (!customElement) continue;
switch (customElement.type) {
case CustomLayoutElementType.MODEL_3D: {
ClayBoundingBox rootBox = renderCommands.data[0].boundingBox;
float scaleValue = $$min($$min(1f, 768f / rootBox.height) * $$max(1f, rootBox.width / 1024f), 1.5f);
Ray positionRay = getScreenToWorldPointWithZDistance({ renderCommand.boundingBox.x + renderCommand.boundingBox.width / 2, renderCommand.boundingBox.y + (renderCommand.boundingBox.height / 2) + 20 }, raylibCamera, (int)$$round(rootBox.width), (int)$$round(rootBox.height), 140);
raylib::beginMode3D(raylibCamera);
raylib::drawModel(customElement.element.model.model, positionRay.position, customElement.element.model.scale * scaleValue, raylib::WHITE); // Draw 3d model with texture
raylib::endMode3D();
break;
}
default: break;
}
break;
}
default: {
// std::io::printfn("ERROR: unhandled render command."); TODO: maybe make a workout for this
}
}
}
}

478
bindings/c3/source/clay.c3 Normal file
View File

@ -0,0 +1,478 @@
module clay;
import clay::carray;
macro @clay(...; @body()) @builtin
{
clay::openElement();
$for (var $i = 0; $i < $vacount; $i++)
$vaexpr[$i]; // If you get an error here consisder the @body[...]() macros
$endfor
clay::elementPostConfiguration();
@body();
clay::closeElement();
}
macro text(String text, TextElementConfig *config) { clay::openTextElement({text.len, text}, config); }
<*Provides you conditional calls (eg #booleanCondition ? #doA : 0) within the condifuration of @clay(...)*>
macro @bodyIf(#condition, #ifRes) { if (#condition) { #ifRes; } }
<*Provides you conditional calls (eg #booleanCondition ? #doA : #doB) within the condifuration of @clay(...)*>
macro @bodyIfElse(#condition, #ifRes, #elseRes) { if (#condition) { #ifRes; } else { #elseRes; } }
<*attaches a RectangleElementConfig to the clay element when called within @clay(...)*>
macro rectangle(RectangleElementConfig config) { clay::attachElementConfig({ .rectangleElementConfig = clay::storeRectangleElementConfig(config) }, clay::ELEMENT_CONFIG_TYPE_RECTANGLE ); }
<*attaches a LayoutConfig to the clay element when called within @clay(...)*>
macro layout(LayoutConfig config) { clay::attachLayoutConfig( clay::storeLayoutConfig(config) ); }
<*attaches a LayoutConfig to the clay element when called within @clay(...)*>
macro scroll(ScrollElementConfig config) { clay::attachElementConfig({ .scrollElementConfig = clay::storeScrollElementConfig(config) }, clay::ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER ); }
<*attaches a FloatingElementConfig to the clay element when called within @clay(...)*>
macro floating(FloatingElementConfig config) { clay::attachElementConfig({ .floatingElementConfig = clay::storeFloatingElementConfig(config) }, clay::ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER ); }
<*attaches a BorderElementConfig to the clay element when called within @clay(...)*>
macro @borderRadiusUni(uint #width, ClayColor #color, float #cornerRadius = 0) { clay::attachElementConfig({ .borderElementConfig = clay::storeBorderElementConfig({ .left = { #width, #color }, .right = { #width, #color }, .top = { #width, #color }, .bottom = { #width, #color }, .#cornerRadius = {#cornerRadius, #cornerRadius, #cornerRadius, #cornerRadius}})}, clay::ELEMENT_CONFIG_TYPE_BORDER_CONTAINER); }
macro id(String idString) { clay::attachId(clay::hashString({idString.len, idString}, 0, 0)); }
macro TextElementConfig* textConfig(TextElementConfig config) { return clay::storeTextElementConfig(config); }
macro SizingAxis sizingFit(float min = 0, float max = float.max) { return { .size.minMax = {min, max}, .type = SizingType.FIT }; }
macro SizingAxis sizingGrow() { return { .size.minMax = {0, 0}, .type = SizingType.GROW }; }
macro SizingAxis sizingFixed(float pixels) { return { .size.minMax = {pixels, pixels}, .type = SizingType.FIXED }; }
macro SizingAxis sizingPercent(float percent) { return { .size.percent = percent, .type = SizingType.PERCENT }; }
macro Padding paddingUni(ushort uniform) { return {uniform, uniform, uniform, uniform}; }
macro Padding padding(ushort horizontal, ushort vertical) { return {horizontal, horizontal, vertical, vertical}; }
macro CornerRadius cornerRadiusUni(float uniform) { return {uniform, uniform, uniform, uniform}; }
macro SizingAxis sizingFitCT(float $min = 0, float $max = float.max) { return { .size.minMax = {$min, $max}, .type = SizingType.FIT }; }
macro SizingAxis sizingFixedCT(float $pixels) { return { .size.minMax = {$pixels, $pixels}, .type = SizingType.FIXED }; }
macro SizingAxis sizingPercentCT(float $percent) { return { .size.percent = $percent, .type = SizingType.PERCENT }; }
macro Padding paddingCT(ushort $a, ushort $b, ushort $c, ushort $d) { return { $a, $b, $c, $d }; }
macro CornerRadius @cornerRadiusUniCT(float #uniform) { return {#uniform, #uniform, #uniform, #uniform}; }
struct ClayString
{
int length;
char *chars;
}
def ClayStringArray = carray::Array(<ClayString>) @private;
struct Arena
{
uint128 nextAllocation;
uint128 capacity;
char *memory;
}
struct Dimensions
{
float width, height;
}
struct ClayVector2
{
float x, y;
}
struct ClayColor
{
float r, g, b, a;
}
struct ElementId
{
uint id;
uint offset;
uint baseId;
ClayString stringId;
}
struct CornerRadius
{
float topLeft;
float topRight;
float bottomLeft;
float bottomRight;
}
distinct ElementConfigType @private = char;
const ElementConfigType ELEMENT_CONFIG_TYPE_NONE @private = 0;
const ElementConfigType ELEMENT_CONFIG_TYPE_RECTANGLE @private = 1;
const ElementConfigType ELEMENT_CONFIG_TYPE_BORDER_CONTAINER @private = 2;
const ElementConfigType ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER @private = 4;
const ElementConfigType ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER @private = 8;
const ElementConfigType ELEMENT_CONFIG_TYPE_IMAGE @private = 16;
const ElementConfigType ELEMENT_CONFIG_TYPE_TEXT @private = 32;
const ElementConfigType ELEMENT_CONFIG_TYPE_CUSTOM @private = 64;
enum LayoutDirection : char @export
{
LEFT_TO_RIGHT,
TOP_TO_BOTTOM,
}
enum AlignX : char @export
{
LEFT,
RIGHT,
CENTER,
}
enum AlignY : char @export
{
TOP,
BOTTOM,
CENTER,
}
enum SizingType : char @export
{
FIT,
GROW,
PERCENT,
FIXED,
}
struct ChildAlignment
{
AlignX x;
AlignY y;
}
struct SizingMinMax
{
float min;
float max;
}
struct SizingAxis
{
union size
{
SizingMinMax minMax;
float percent;
}
SizingType type;
}
struct Sizing
{
SizingAxis width;
SizingAxis height;
}
struct Padding
{
ushort left;
ushort right;
ushort top;
ushort bottom;
}
struct LayoutConfig
{
Sizing sizing;
Padding padding;
ushort childGap;
ChildAlignment childAlignment;
LayoutDirection layoutDirection;
}
struct RectangleElementConfig
{
ClayColor color;
CornerRadius cornerRadius;
// #ifdef CLAY_EXTEND_CONFIG_RECTANGLE
// CLAY_EXTEND_CONFIG_RECTANGLE
// #endif
}
enum WrapMode @export
{
WORDS,
NEWLINES,
NONE,
}
struct TextElementConfig
{
ClayColor textColor;
ushort fontId;
ushort fontSize;
ushort letterSpacing;
ushort lineHeight;
WrapMode wrapMode;
// #ifdef CLAY_EXTEND_CONFIG_TEXT
// CLAY_EXTEND_CONFIG_TEXT
// #endif
}
struct ImageElementConfig
{
void *imageData;
Dimensions sourceDimensions;
// #ifdef CLAY_EXTEND_CONFIG_IMAGE
// CLAY_EXTEND_CONFIG_IMAGE
// #endif
}
enum AttachPoint : char @export
{
LEFT_TOP,
LEFT_CENTER,
LEFT_BOTTOM,
CENTER_TOP,
CENTER_CENTER,
CENTER_BOTTOM,
RIGHT_TOP,
RIGHT_CENTER,
RIGHT_BOTTOM,
}
struct FloatingAttachPoints
{
AttachPoint element;
AttachPoint parent;
}
enum PointerCaptureMode @export
{
CAPTURE,
// MODE_PASSTHROUGH,
PARENT,
}
struct FloatingElementConfig
{
ClayVector2 offset;
Dimensions expand;
ushort zIndex;
uint parentId;
FloatingAttachPoints attachment;
PointerCaptureMode pointerCaptureMode;
}
struct CustomElementConfig
{
void *customData;
}
struct ScrollElementConfig
{
bool horizontal;
bool vertical;
}
// Border
struct Border
{
uint width;
ClayColor color;
}
struct BorderElementConfig
{
Border left;
Border right;
Border top;
Border bottom;
Border betweenChildren;
CornerRadius cornerRadius;
}
union ElementConfigUnion
{
RectangleElementConfig *rectangleElementConfig;
TextElementConfig *textElementConfig;
ImageElementConfig *imageElementConfig;
FloatingElementConfig *floatingElementConfig;
CustomElementConfig *customElementConfig;
ScrollElementConfig *scrollElementConfig;
BorderElementConfig *borderElementConfig;
}
struct ElementConfig
{
ElementConfigType type;
ElementConfigUnion config;
}
struct ClayBoundingBox
{
float x, y, width, height;
}
enum RenderCommandType : char @export
{
NONE,
RECTANGLE,
BORDER,
TEXT,
IMAGE,
SCISSOR_START,
SCISSOR_END,
CUSTOM,
}
struct RenderCommand
{
ClayBoundingBox boundingBox;
ElementConfigUnion config;
ClayString text;
uint id;
RenderCommandType commandType;
}
def RenderCommandArray = carray::Array(<RenderCommand>);
struct ScrollContainerData
{
// 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.
ClayVector2 *scrollPosition;
Dimensions scrollContainerDimensions;
Dimensions contentDimensions;
ScrollElementConfig config;
// Indicates whether an actual scroll container matched the provided ID or if the default struct was returned.
bool found;
}
struct ElementData
{
ClayBoundingBox boundingBox;
// Indicates whether an actual Element matched the provided ID or if the default struct was returned.
bool found;
}
enum PointerState @export
{
PRESSED_THIS_FRAME,
PRESSED,
RELEASED_THIS_FRAME,
RELEASED,
}
struct PointerData
{
ClayVector2 position;
PointerState state;
}
def OnHoverEvent = fn void(ElementId elementId, PointerData pointerData, iptr userData);
def MeasureTextFunc = fn Dimensions(ClayString *text, TextElementConfig *config);
def QueryScrollOffsetFunc = fn ClayVector2(uint elementId);
enum ErrorType @export
{
TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED,
ARENA_CAPACITY_EXCEEDED,
ELEMENTS_CAPACITY_EXCEEDED,
TEXT_MEASUREMENT_CAPACITY_EXCEEDED,
DUPLICATE_ID,
FLOATING_CONTAINER_PARENT_NOT_FOUND,
INTERNAL_ERROR,
}
struct ErrorData
{
ErrorType errorType;
ClayString errorText;
uint128 userData;
}
def ErrorHandleFunc = fn void(ErrorData errorText);
struct ErrorHandler
{
ErrorHandleFunc errorHandler;
uint128 userData;
}
distinct Context = void; // I'm not doing all that again
// =====================
// ===== FUNCTIONS =====
// =====================
// ===== Public Clay API C3 Functions (String replacement) ===== // TODO @export and @wasm can be ignored rn
// I haven't been able to get c3c and c compilations to work together for wasm32 or a c3 library
fn ElementId getElementIdWithIndex(String idString, uint index) @export @inline
{ return __getElementIdWithIndex({idString.len, idString}, (uint)index); }
fn ElementId getElementId(String idString) @export @inline
{ return __getElementId({idString.len, idString}); }
// ===== Public Clay API Functions =====
extern fn uint minMemorySize() @extern("Clay_MinMemorySize") @wasm @export;
extern fn Arena createArena(uint capacity, void* offset) @extern("Clay_CreateArenaWithCapacityAndMemory") @wasm @export;
extern fn void setPointerState(ClayVector2 position, bool pointerDown) @extern("Clay_SetPointerState") @export;
extern fn Context* initialize(Arena arena, Dimensions layoutDimensions, ErrorHandler errorHandler) @extern("Clay_Initialize") @wasm @export;
extern fn Context* getCurrentContext() @extern("Clay_GetCurrentContext") @export;
extern fn void setCurrentContext(Context* context) @extern("Clay_SetCurrentContext") @export;
extern fn void updateScrollContainer(bool enableDragScrolling, ClayVector2 scrollDelta, float deltaTime) @extern("Clay_UpdateScrollContainers") @export;
extern fn void setLayoutDimensions (Dimensions dimensions) @extern("Clay_SetLayoutDimensions") @export;
extern fn ElementData getElementData(ElementId id) @extern("Clay_GetElementData") @export;
extern fn bool hovered() @extern("Clay_Hovered") @export;
extern fn void onHover(OnHoverEvent onHover, iptr userData) @extern("Clay_OnHover") @export;
extern fn bool pointerOver(ElementId elementId) @extern("Clay_PointerOver") @wasm @export;
extern fn ScrollContainerData getScrollContainerData(ElementId id) @extern("Clay_GetScrollContainerData") @export;
extern fn void setMeasureTextFunction(MeasureTextFunc measureText) @extern("Clay_SetMeasureTextFunction") @export;
extern fn void setQueryScrollOffsetFunction(QueryScrollOffsetFunc queryScrollOffset) @extern("Clay_SetQueryScrollOffsetFunction") @export;
extern fn RenderCommand * RenderCommandArray.get(RenderCommandArray* array, int index) @extern("Clay_RenderCommandArray_Get") @export;
extern fn void setDebugModeEnabled(bool enabled) @extern("Clay_SetDebugModeEnabled") @export;
extern fn bool isDebugModeEnabled() @extern("Clay_IsDebugModeEnabled") @export;
extern fn void setCullingEnabled(bool enabled) @extern("Clay_SetCullingEnabled") @export;
extern fn int getMaxMeasuredTextCachedWordCount() @extern("Clay_GetMaxElementCount") @export;
extern fn void setMaxElementCount(int maxElementCount) @extern("Clay_SetMaxElementCount") @export;
extern fn int getMaxElementCount() @extern("Clay_GetMaxMeasureTextCacheWordCount") @export;
extern fn void setMaxMeasureTextCacheWordCount(int maxMeasureTextCacheWordCount) @extern("Clay_SetMaxMeasureTextCacheWordCount") @export;
extern fn void resetMeasureTextCache() @extern("Clay_ResetMeasureTextCache") @export;
extern fn void beginLayout() @extern("Clay_BeginLayout") @export;
extern fn RenderCommandArray endLayout() @extern("Clay_EndLayout") @export;
// ===== (NEW) Internal Clay API Functions (String replacement) =====
extern fn ElementId __getElementIdWithIndex(ClayString idString, uint index) @extern("Clay_GetElementIdWithIndex") @export @private;
extern fn ElementId __getElementId(ClayString idString) @extern("Clay_GetElementId") @export @private;
// ===== Internal Clay API Functions =====
extern fn void openElement() @extern ("Clay__OpenElement") @export @private;
extern fn void closeElement() @extern("Clay__CloseElement") @export @private;
extern fn void openTextElement(ClayString text, TextElementConfig *textConfig) @extern("Clay__OpenTextElement") @export @private;
extern fn void elementPostConfiguration() @extern("Clay__ElementPostConfiguration") @export @private;
extern fn LayoutConfig * storeLayoutConfig(LayoutConfig config) @extern("Clay__StoreLayoutConfig") @export @private;
extern fn void attachId(ElementId id) @extern("Clay__AttachId") @export @private;
extern fn void attachLayoutConfig(LayoutConfig *config) @extern("Clay__AttachLayoutConfig") @export @private;
extern fn void attachElementConfig(ElementConfigUnion config, ElementConfigType type) @extern("Clay__AttachElementConfig") @export @private;
extern fn RectangleElementConfig * storeRectangleElementConfig(RectangleElementConfig config) @extern("Clay__StoreRectangleElementConfig") @export @private;
extern fn TextElementConfig * storeTextElementConfig(TextElementConfig config) @extern("Clay__StoreTextElementConfig") @export @private;
extern fn ImageElementConfig * storeImageElementConfig(ImageElementConfig config) @extern("Clay__StoreImageElementConfig") @export @private;
extern fn FloatingElementConfig * storeFloatingElementConfig(FloatingElementConfig config) @extern("Clay__StoreFloatingElementConfig") @export @private;
extern fn CustomElementConfig * storeCustomElementConfig(CustomElementConfig config) @extern("Clay__StoreCustomElementConfig") @export @private;
extern fn ScrollElementConfig * storeScrollElementConfig(ScrollElementConfig config) @extern("Clay__StoreScrollElementConfig") @export @private;
extern fn BorderElementConfig * storeBorderElementConfig(BorderElementConfig config) @extern("Clay__StoreBorderElementConfig") @export @private;
extern fn ElementId hashString(ClayString key, uint offset, uint seed) @extern("Clay__HashString") @export @private;
extern fn uint getParentElementId() @extern("Clay__GetParentElementId") @export @private;
// ==========================================================================
// ===== An internal module for wrapping Struct Array's defined in Clay =====
// ==========================================================================
module clay::carray(<ElementType>);
struct Array {
int capacity;
int length;
ElementType *data;
}