diff --git a/bindings/jai/.gitignore b/bindings/jai/.gitignore new file mode 100644 index 0000000..329f3e5 --- /dev/null +++ b/bindings/jai/.gitignore @@ -0,0 +1 @@ +.build/ \ No newline at end of file diff --git a/bindings/jai/clay-jai/windows/clay.lib b/bindings/jai/clay-jai/windows/clay.lib new file mode 100644 index 0000000..35da4f4 Binary files /dev/null and b/bindings/jai/clay-jai/windows/clay.lib differ diff --git a/bindings/jai/generate.jai b/bindings/jai/generate.jai new file mode 100644 index 0000000..e78776b --- /dev/null +++ b/bindings/jai/generate.jai @@ -0,0 +1,464 @@ +AT_COMPILE_TIME :: true; + +SOURCE_PATH :: "source"; + +#if AT_COMPILE_TIME { + #run,stallable { + Compiler.set_build_options_dc(.{do_output=false}); + options := Compiler.get_build_options(); + args := options.compile_time_command_line; + if !generate_bindings(args, options.minimum_os_version) { + Compiler.compiler_set_workspace_status(.FAILED); + } + } +} else { + #import "System"; + + main :: () { + set_working_directory(path_strip_filename(get_path_of_running_executable())); + if !generate_bindings(get_command_line_arguments(), #run get_build_options().minimum_os_version) { + exit(1); + } + } +} + + +Build_Type :: enum { + STATIC_LIBRARY; + DYNAMIC_LIBRARY; + EXECUTABLE; + OBJ_FILE; +} + +build_cpp_static_lib :: #bake_arguments build_cpp(type = .STATIC_LIBRARY); +build_cpp_dynamic_lib :: #bake_arguments build_cpp(type = .DYNAMIC_LIBRARY); +build_cpp_executable :: #bake_arguments build_cpp(type = .EXECUTABLE); + +// This is a modified version of the procedure from BuildCpp. It will assume a clang-like compiler if you add something to compiler_executable_path. +build_cpp :: ( + output_basename: string, + files: ..string, + type: Build_Type, + debug := false, + extra: [] string = .[], + library_files: [] string = .[], + target := OS, + compiler_executable_path := "", + ar_executable_path := "", + working_directory := "", + loc := #caller_location +) -> bool { + Basic.auto_release_temp(); + Basic.push_allocator(Basic.temp); + + arguments: [..] string; + + output_filename: string; + if target == .WINDOWS && compiler_executable_path == "" { + if #complete type == { + case .STATIC_LIBRARY; + output_filename = Basic.tprint("%.lib", output_basename); + case .DYNAMIC_LIBRARY; + output_filename = Basic.tprint("%.dll", output_basename); + case .EXECUTABLE; + output_filename = Basic.tprint("%.exe", output_basename); + case .OBJ_FILE; + output_filename = Basic.tprint("%.obj", output_basename); + } + + #if OS == .WINDOWS { + String.path_overwrite_separators(output_filename, #char "\\"); + + vc_path, linker_path := WindowsResources.find_visual_studio_in_a_ridiculous_garbage_way(); + + kit_root := WindowsResources.find_windows_kit_root(); + if !kit_root { + Compiler.compiler_report("Unable to find Windows Kit root; can't compile.\n", loc); + return false; + } + } else { + Compiler.compiler_report("Unable to find Visual Studio; can't compile.\n", loc); + vc_path, linker_path: string; + kit_root: string; + return false; // Visual studio is not available in non-windows OS. + } + + linker := String.join(linker_path, "\\", "cl.exe"); + Basic.array_add(*arguments, linker); + + Basic.array_add(*arguments, "/nologo"); + + // Include directories: + vc_include_path := String.join(vc_path, "\\..\\..\\include"); + kit_root_include := String.replace(kit_root, "Lib", "Include"); + Basic.array_add(*arguments, + Basic.tprint("/I%", vc_include_path), + Basic.tprint("/I%\\um", kit_root_include), + Basic.tprint("/I%\\ucrt", kit_root_include), + Basic.tprint("/I%\\shared", kit_root_include), + ); + + // Definitions: + Basic.array_add(*arguments, "/DWIN32"); + if debug { + Basic.array_add(*arguments, "/DDEBUG"); + } + + // Compiler options: + if debug { + Basic.array_add(*arguments, "/Od"); // Disable optimizations. + } else { + Basic.array_add(*arguments, + "/O2", // Maximize speed. + "/Oi", // Enable intrinsics. + ); + } + Basic.array_add(*arguments, "/W3"); + + if debug { + Basic.array_add(*arguments, + "/DEBUG", // Generate debug info. + "/Zi", // Generate pdb file. + Basic.tprint("/Fd%.pdb", output_basename), // Sets name of pdb file. + ); + } + + Basic.array_add(*arguments, + "-diagnostics:caret", + "-diagnostics:column" + ); + + Basic.array_add(*arguments, .. extra); + + // Add files: + objs: [..] string; + Basic.array_reserve(*objs, files.count); + for files { + src := String.copy_temporary_string(it); + String.path_overwrite_separators(src); + Basic.array_add(*arguments, src); + + Basic.array_add(*objs, Basic.tprint("%.obj", String.path_strip_extension(String.path_filename(it)))); + } + + // Make sure to cleanup the resulting obj files. + defer { + if type != .OBJ_FILE { + for objs File.file_delete(it); + } + + if type == .DYNAMIC_LIBRARY then File.file_delete(Basic.tprint("%.exp", output_basename)); + } + + if type == .STATIC_LIBRARY || type == .OBJ_FILE { + Basic.array_add(*arguments, "/c"); // Compile without linking. + } else { + Basic.array_add(*arguments, "/link"); + + // Linker options: + if type == .DYNAMIC_LIBRARY { + Basic.array_add(*arguments, "/DLL"); + } + Basic.array_add(*arguments, + "/MACHINE:AMD64", + Basic.tprint("/OUT:%", output_filename), + Basic.tprint("/libpath:%", vc_path), + Basic.tprint("/libpath:%\\um\\x64", kit_root), + Basic.tprint("/libpath:%\\ucrt\\x64", kit_root), + ); + } + + Basic.array_add(*arguments, .. library_files); + + Basic.log("%", Process.get_quoted_command_string(arguments)); + result, output_string, error_string := Process.run_command(..arguments, capture_and_return_output = true, print_captured_output = true, working_directory = working_directory); + + if result.exit_code { + Compiler.compiler_report(Basic.tprint("Compiler failed with exit code '%'.\n", result.exit_code), loc); + return false; + } + + if type == .STATIC_LIBRARY { + // Create library: + Basic.array_reset_keeping_memory(*arguments); + + librarian := String.join(linker_path, "\\lib.exe"); + + Basic.array_add(*arguments, librarian, "/nologo"); + Basic.array_add(*arguments, ..objs); + Basic.array_add(*arguments, Basic.tprint("/OUT:%", output_filename)); + + Basic.log("%", Process.get_quoted_command_string(arguments)); + result, output_string, error_string := Process.run_command(..arguments, capture_and_return_output = true, print_captured_output = true, working_directory = working_directory); + + if result.exit_code { + Compiler.compiler_report(Basic.tprint("Librarian failed with exit code '%'.\n", result.exit_code), loc); + return false; + } + } + } else { + if #complete type == { + case .STATIC_LIBRARY; + #if OS == .WINDOWS { + output_filename = Basic.tprint("%.lib", output_basename); + } else { + output_filename = Basic.tprint("%.a", output_basename); + } + + case .OBJ_FILE; + output_filename = Basic.tprint("%.o", output_basename); + case .DYNAMIC_LIBRARY; + if target == { + case .WINDOWS; output_filename = Basic.tprint("%.dll", output_basename); + case .MACOS; output_filename = Basic.tprint("%.dylib", output_basename); + case .LINUX; #through; + case .ANDROID; output_filename = Basic.tprint("%.so", output_basename); + case .NONE; #if OS == .WINDOWS then output_filename = Basic.tprint("%.dll", output_basename); else assert(false); + case; assert(false); + } + case .EXECUTABLE; + output_filename = Basic.copy_temporary_string(output_basename); + } + + #if OS == .WINDOWS { + String.path_overwrite_separators(output_filename, #char "\\"); + } + + compiler := compiler_executable_path; + ar := ar_executable_path; + if !compiler || (type == .STATIC_LIBRARY && !ar) { + is_cpp_project := false; + for files { + if String.ends_with(it, ".cpp") { + is_cpp_project = true; // Use c++ compiler, so we link the required c++ runtime libraries by default. + break; + } + } + + if !compiler { + if is_cpp_project { + // @Cleanup: Could be simplified to the following, but that currently triggers a compiler bug. -rluba, 2024-01-23 + // compiler = ifx to_string(getenv("CXX")) else "clang++"; + compiler = to_string(getenv("CXX")); + if !compiler compiler ="clang++"; + } else { + compiler = to_string(getenv("CC")); + if !compiler compiler ="clang"; + } + } + + if !ar ar = "ar"; + + } + + Basic.array_add(*arguments, compiler); + + if debug { + Basic.array_add(*arguments, "-g", "-Og"); + } else { + Basic.array_add(*arguments, "-O3"); + } + + Basic.array_add(*arguments, ..extra); + + if type == .STATIC_LIBRARY || type == .OBJ_FILE { + array_add(*arguments, "-c"); + } else { + if type == .DYNAMIC_LIBRARY { + array_add(*arguments, "-shared", "-fpic"); + } + + if target == .MACOS { + if type == { + case .DYNAMIC_LIBRARY; + array_add(*arguments, "-install_name", tprint("@rpath/%", output_filename)); + case .EXECUTABLE; + array_add(*arguments, "-rpath", "@loader_path"); + } + } + + array_add(*arguments, "-o", output_filename); + } + + // Add files: + objs: [..] string; + array_reserve(*objs, files.count); + for files { + src := copy_temporary_string(it); + String.path_overwrite_separators(src); + array_add(*arguments, src); + + array_add(*objs, tprint("%.o", String.path_basename(it))); + } + + // Make sure to cleanup the resulting obj files. + defer { + if type != .OBJ_FILE { + for objs File.file_delete(it); + } + } + + array_add(*arguments, .. library_files); + + log("%", Process.get_quoted_command_string(arguments)); + result, output_string, error_string := Process.run_command(..arguments, capture_and_return_output = true, print_captured_output = true, working_directory = working_directory); + + if result.exit_code { + Compiler.compiler_report(tprint("Compiler failed with exit code '%'.\n", result.exit_code), loc); + return false; + } + + if type == .STATIC_LIBRARY { + File.file_delete(output_filename); // ar only adds/updates the archive, but does not delete files from it. + + // Create library: + array_reset_keeping_memory(*arguments); + array_add(*arguments, + ar, + "-rc", // replace or insert files into the archive, do not warn if archive needs to be created. + output_filename, + ); + + array_add(*arguments, ..objs); + + // Run archiver command: + log("%", Process.get_quoted_command_string(arguments)); + result, output_string, error_string := Process.run_command(..arguments, capture_and_return_output = true, print_captured_output = true, working_directory = working_directory); + + if result.exit_code { + Compiler.compiler_report(tprint("Archive command failed with exit code '%'.\n", result.exit_code), loc); + return false; + } + } + } + + return true; +} + +enum_cpp_files :: (path: string, recursive:=false) -> [..] string { + files: [..] string; + + visitor :: (info: *FileUtils.File_Visit_Info, files: *[..] string) { + extension := String.path_extension(info.full_name); + if extension == "cpp" || extension == "c" { + Basic.array_add(files, String.copy_string(info.full_name)); + } + } + + FileUtils.visit_files(path, recursive=recursive, *files, visitor); + + return files; +} + +free_cpp_files :: (files: [] string) { + for files Basic.free(it); + Basic.array_free(files); +} + + +generate_bindings :: (args: [] string, minimum_os_version: type_of(Compiler.Build_Options.minimum_os_version)) -> bool { + compile := Basic.array_find(args, "-compile"); + compile_debug := Basic.array_find(args, "-debug"); + + if compile { + could_copy := FileUtils.copy_file("../../clay.h", "source/clay.h"); + if !could_copy then return false; + + source_file := Basic.tprint("%/clay.c", SOURCE_PATH); + + success := true; + #if OS == .WINDOWS { + File.make_directory_if_it_does_not_exist("clay-jai/windows", true); + + // Can't use this because clay doesn't support MSVC + success &&= build_cpp_static_lib( + "clay-jai/windows/clay", + source_file, + debug = compile_debug, + target=.NONE, + compiler_executable_path="clang", + ar_executable_path="llvm-ar", + ); + + // { + // command := Process.break_command_into_strings("clang -c -o clay-jai/windows/clay.lib -static source/clay.c"); + // result, out, error := Process.run_command(..command, capture_and_return_output = true); + + // write_string(out); + // if result.exit_code != 0 + // { + // write_string("Failed to build clay. Do you have clang installed ?\n"); + // write_string(error); + // success = false; + // } + // } + + // { + // command := Process.break_command_into_strings("clang -c -o clay-jai/windows/clay.dll -dynamic source/clay.c"); + // result, out, error := Process.run_command(..command, capture_and_return_output = true); + + // write_string(out); + // if result.exit_code != 0 + // { + // write_string("Failed to build clay. Do you have clang installed ?\n"); + // write_string(error); + // success = false; + // } + // } + } else { + // TODO MacOS + // TODO Linux + assert(false); + } + + if !success then return false; + } + + output_filename: string; + options: Generator.Generate_Bindings_Options; + { + using options; + + #if OS == .WINDOWS { + Basic.array_add(*libpaths, "clay-jai/windows"); + output_filename = "windows.jai"; + } else { + assert(false); + } + + Basic.array_add(*libnames, "clay"); + Basic.array_add(*include_paths, SOURCE_PATH); + Basic.array_add(*source_files, Basic.tprint("%/clay.h", SOURCE_PATH)); + Basic.array_add(*strip_prefixes, "Clay_"); + + auto_detect_enum_prefixes = true; + log_stripped_declarations = true; + generate_compile_time_struct_checks = false; + } + + could_generate := Generator.generate_bindings(options, output_filename); + + File.file_delete("source/clay.h"); + + return could_generate; +} + +#scope_file + +using Basic :: #import "Basic"; +Generator :: #import "Bindings_Generator"; +Compiler :: #import "Compiler"; +File :: #import "File"; +FileUtils :: #import "File_Utilities"; +BuildCpp :: #import "BuildCpp"; +Process :: #import "Process"; +String :: #import "String"; +WindowsResources :: #import "Windows_Resources"; + +#if OS == .WINDOWS { + Windows :: #import "Windows"; + getenv :: Windows.getenv; +} else { + Posix :: #import "POSIX"; + getenv :: Posix.getenv; +} diff --git a/bindings/jai/module.jai b/bindings/jai/module.jai new file mode 100644 index 0000000..c284510 --- /dev/null +++ b/bindings/jai/module.jai @@ -0,0 +1,5 @@ +#if OS == .WINDOWS { + #load "windows.jai"; +} else { + assert(false) +} \ No newline at end of file diff --git a/bindings/jai/source/clay.c b/bindings/jai/source/clay.c new file mode 100644 index 0000000..22259af --- /dev/null +++ b/bindings/jai/source/clay.c @@ -0,0 +1,2 @@ +#define CLAY_IMPLEMENTATION +#include "clay.h" \ No newline at end of file diff --git a/bindings/jai/windows.jai b/bindings/jai/windows.jai new file mode 100644 index 0000000..de200b1 --- /dev/null +++ b/bindings/jai/windows.jai @@ -0,0 +1,392 @@ +// +// This file was auto-generated using the following command: +// +// jai ./generate.jai - -compile +// + + + +// Utility Structs ------------------------- +// 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. +String :: struct { + length: s32; + chars: *u8; +} + +StringArray :: struct { + capacity: u32; + length: u32; + internalArray: *String; +} + +Arena :: struct { + label: String; + nextAllocation: u64; + capacity: u64; + memory: *u8; +} + +Dimensions :: struct { + width: float; + height: float; +} + +Vector2 :: struct { + x: float; + y: float; +} + +Color :: struct { + r: float; + g: float; + b: float; + a: float; +} + +BoundingBox :: struct { + x: float; + y: float; + width: float; + height: float; +} + +// baseId + offset = id +ElementId :: struct { + id: u32; + offset: u32; + baseId: u32; + stringId: String; +} + +CornerRadius :: struct { + topLeft: float; + topRight: float; + bottomLeft: float; + bottomRight: float; +} + +ElementConfigType :: enum s32 { + RECTANGLE :: 1; + BORDER_CONTAINER :: 2; + FLOATING_CONTAINER :: 4; + SCROLL_CONTAINER :: 8; + IMAGE :: 16; + TEXT :: 32; + CUSTOM :: 64; + + CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE :: RECTANGLE; + CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER :: BORDER_CONTAINER; + CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER :: FLOATING_CONTAINER; + CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER :: SCROLL_CONTAINER; + CLAY__ELEMENT_CONFIG_TYPE_IMAGE :: IMAGE; + CLAY__ELEMENT_CONFIG_TYPE_TEXT :: TEXT; + CLAY__ELEMENT_CONFIG_TYPE_CUSTOM :: CUSTOM; +} + +// Element Configs --------------------------- +// Layout +LayoutDirection :: enum s32 { + LEFT_TO_RIGHT :: 0; + TOP_TO_BOTTOM :: 1; + + CLAY_LEFT_TO_RIGHT :: LEFT_TO_RIGHT; + CLAY_TOP_TO_BOTTOM :: TOP_TO_BOTTOM; +} + +LayoutAlignmentX :: enum s32 { + LEFT :: 0; + RIGHT :: 1; + CENTER :: 2; + + CLAY_ALIGN_X_LEFT :: LEFT; + CLAY_ALIGN_X_RIGHT :: RIGHT; + CLAY_ALIGN_X_CENTER :: CENTER; +} + +LayoutAlignmentY :: enum s32 { + TOP :: 0; + BOTTOM :: 1; + CENTER :: 2; + + CLAY_ALIGN_Y_TOP :: TOP; + CLAY_ALIGN_Y_BOTTOM :: BOTTOM; + CLAY_ALIGN_Y_CENTER :: CENTER; +} + +SizingType :: enum s32 { + FIT :: 0; + GROW :: 1; + PERCENT :: 2; + FIXED :: 3; + + CLAY__SIZING_TYPE_FIT :: FIT; + CLAY__SIZING_TYPE_GROW :: GROW; + CLAY__SIZING_TYPE_PERCENT :: PERCENT; + CLAY__SIZING_TYPE_FIXED :: FIXED; +} + +ChildAlignment :: struct { + x: LayoutAlignmentX; + y: LayoutAlignmentY; +} + +SizingMinMax :: struct { + min: float; + max: float; +} + +SizingAxis :: struct { + union { + sizeMinMax: SizingMinMax; + sizePercent: float; + } + + type: SizingType; +} + +Sizing :: struct { + width: SizingAxis; + height: SizingAxis; +} + +Padding :: struct { + x: u16; + y: u16; +} + +LayoutConfig :: struct { + sizing: Sizing; + padding: Padding; + childGap: u16; + childAlignment: ChildAlignment; + layoutDirection: LayoutDirection; +} + +CLAY_LAYOUT_DEFAULT: LayoutConfig #elsewhere clay; + +// Rectangle +RectangleElementConfig :: struct { + color: Color; + cornerRadius: CornerRadius; +} + +// Text +TextElementConfigWrapMode :: enum s32 { + WORDS :: 0; + NEWLINES :: 1; + NONE :: 2; + + CLAY_TEXT_WRAP_WORDS :: WORDS; + CLAY_TEXT_WRAP_NEWLINES :: NEWLINES; + CLAY_TEXT_WRAP_NONE :: NONE; +} + +TextElementConfig :: struct { + textColor: Color; + fontId: u16; + fontSize: u16; + letterSpacing: u16; + lineHeight: u16; + wrapMode: TextElementConfigWrapMode; +} + +// Image +ImageElementConfig :: struct { + imageData: *void; + sourceDimensions: Dimensions; +} + +// Floating +FloatingAttachPointType :: enum s32 { + LEFT_TOP :: 0; + LEFT_CENTER :: 1; + LEFT_BOTTOM :: 2; + CENTER_TOP :: 3; + CENTER_CENTER :: 4; + CENTER_BOTTOM :: 5; + RIGHT_TOP :: 6; + RIGHT_CENTER :: 7; + RIGHT_BOTTOM :: 8; + + CLAY_ATTACH_POINT_LEFT_TOP :: LEFT_TOP; + CLAY_ATTACH_POINT_LEFT_CENTER :: LEFT_CENTER; + CLAY_ATTACH_POINT_LEFT_BOTTOM :: LEFT_BOTTOM; + CLAY_ATTACH_POINT_CENTER_TOP :: CENTER_TOP; + CLAY_ATTACH_POINT_CENTER_CENTER :: CENTER_CENTER; + CLAY_ATTACH_POINT_CENTER_BOTTOM :: CENTER_BOTTOM; + CLAY_ATTACH_POINT_RIGHT_TOP :: RIGHT_TOP; + CLAY_ATTACH_POINT_RIGHT_CENTER :: RIGHT_CENTER; + CLAY_ATTACH_POINT_RIGHT_BOTTOM :: RIGHT_BOTTOM; +} + +FloatingAttachPoints :: struct { + element: FloatingAttachPointType; + parent: FloatingAttachPointType; +} + +PointerCaptureMode :: enum s32 { + CAPTURE :: 0; + + PASSTHROUGH :: 1; + + CLAY_POINTER_CAPTURE_MODE_CAPTURE :: CAPTURE; + + CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH :: PASSTHROUGH; +} + +FloatingElementConfig :: struct { + offset: Vector2; + expand: Dimensions; + zIndex: u16; + parentId: u32; + attachment: FloatingAttachPoints; + pointerCaptureMode: PointerCaptureMode; +} + +// Custom +CustomElementConfig :: struct { + customData: *void; +} + +// Scroll +ScrollElementConfig :: struct { + horizontal: bool; + vertical: bool; +} + +// Border +Border :: struct { + width: u32; + color: Color; +} + +BorderElementConfig :: struct { + left: Border; + right: Border; + top: Border; + bottom: Border; + betweenChildren: Border; + cornerRadius: CornerRadius; +} + +ElementConfigUnion :: union { + rectangleElementConfig: *RectangleElementConfig; + textElementConfig: *TextElementConfig; + imageElementConfig: *ImageElementConfig; + floatingElementConfig: *FloatingElementConfig; + customElementConfig: *CustomElementConfig; + scrollElementConfig: *ScrollElementConfig; + borderElementConfig: *BorderElementConfig; +} + +ElementConfig :: struct { + type: ElementConfigType; + config: ElementConfigUnion; +} + +// Miscellaneous Structs & Enums --------------------------------- +ScrollContainerData :: struct { + // 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. + scrollPosition: *Vector2; + scrollContainerDimensions: Dimensions; + contentDimensions: Dimensions; + config: ScrollElementConfig; + + // Indicates whether an actual scroll container matched the provided ID or if the default struct was returned. + found: bool; +} + +RenderCommandType :: enum s32 { + NONE :: 0; + RECTANGLE :: 1; + BORDER :: 2; + TEXT :: 3; + IMAGE :: 4; + SCISSOR_START :: 5; + SCISSOR_END :: 6; + CUSTOM :: 7; + + CLAY_RENDER_COMMAND_TYPE_NONE :: NONE; + CLAY_RENDER_COMMAND_TYPE_RECTANGLE :: RECTANGLE; + CLAY_RENDER_COMMAND_TYPE_BORDER :: BORDER; + CLAY_RENDER_COMMAND_TYPE_TEXT :: TEXT; + CLAY_RENDER_COMMAND_TYPE_IMAGE :: IMAGE; + CLAY_RENDER_COMMAND_TYPE_SCISSOR_START :: SCISSOR_START; + CLAY_RENDER_COMMAND_TYPE_SCISSOR_END :: SCISSOR_END; + CLAY_RENDER_COMMAND_TYPE_CUSTOM :: CUSTOM; +} + +RenderCommand :: struct { + boundingBox: BoundingBox; + config: ElementConfigUnion; + text: String; // TODO I wish there was a way to avoid having to have this on every render command + id: u32; + commandType: RenderCommandType; +} + +RenderCommandArray :: struct { + capacity: u32; + length: u32; + internalArray: *RenderCommand; +} + +PointerDataInteractionState :: enum s32 { + PRESSED_THIS_FRAME :: 0; + PRESSED :: 1; + RELEASED_THIS_FRAME :: 2; + RELEASED :: 3; + + CLAY_POINTER_DATA_PRESSED_THIS_FRAME :: PRESSED_THIS_FRAME; + CLAY_POINTER_DATA_PRESSED :: PRESSED; + CLAY_POINTER_DATA_RELEASED_THIS_FRAME :: RELEASED_THIS_FRAME; + CLAY_POINTER_DATA_RELEASED :: RELEASED; +} + +PointerData :: struct { + position: Vector2; + state: PointerDataInteractionState; +} + +// Function Forward Declarations --------------------------------- +// Public API functions --- +MinMemorySize :: (__args: ..Any) -> u32 #foreign clay "Clay_MinMemorySize"; +CreateArenaWithCapacityAndMemory :: (capacity: u32, offset: *void) -> Arena #foreign clay "Clay_CreateArenaWithCapacityAndMemory"; +SetPointerState :: (position: Vector2, pointerDown: bool) -> void #foreign clay "Clay_SetPointerState"; +Initialize :: (arena: Arena, layoutDimensions: Dimensions) -> void #foreign clay "Clay_Initialize"; +UpdateScrollContainers :: (enableDragScrolling: bool, scrollDelta: Vector2, deltaTime: float) -> void #foreign clay "Clay_UpdateScrollContainers"; +SetLayoutDimensions :: (dimensions: Dimensions) -> void #foreign clay "Clay_SetLayoutDimensions"; +BeginLayout :: (__args: ..Any) -> void #foreign clay "Clay_BeginLayout"; +EndLayout :: (__args: ..Any) -> RenderCommandArray #foreign clay "Clay_EndLayout"; +GetElementId :: (idString: String) -> ElementId #foreign clay "Clay_GetElementId"; +GetElementIdWithIndex :: (idString: String, index: u32) -> ElementId #foreign clay "Clay_GetElementIdWithIndex"; +Hovered :: (__args: ..Any) -> bool #foreign clay "Clay_Hovered"; +OnHover :: (onHoverFunction: #type (elementId: ElementId, pointerData: PointerData, userData: s64) -> void #c_call, userData: s64) -> void #foreign clay "Clay_OnHover"; +GetScrollContainerData :: (id: ElementId) -> ScrollContainerData #foreign clay "Clay_GetScrollContainerData"; +SetMeasureTextFunction :: (measureTextFunction: #type (text: *String, config: *TextElementConfig) -> Dimensions #c_call) -> void #foreign clay "Clay_SetMeasureTextFunction"; +SetQueryScrollOffsetFunction :: (queryScrollOffsetFunction: #type (elementId: u32) -> Vector2 #c_call) -> void #foreign clay "Clay_SetQueryScrollOffsetFunction"; +RenderCommandArray_Get :: (array: *RenderCommandArray, index: s32) -> *RenderCommand #foreign clay "Clay_RenderCommandArray_Get"; +SetDebugModeEnabled :: (enabled: bool) -> void #foreign clay "Clay_SetDebugModeEnabled"; +SetCullingEnabled :: (enabled: bool) -> void #foreign clay "Clay_SetCullingEnabled"; + +// Internal API functions required by macros +OpenElement :: (__args: ..Any) -> void #foreign clay "Clay__OpenElement"; +CloseElement :: (__args: ..Any) -> void #foreign clay "Clay__CloseElement"; + +ElementPostConfiguration :: (__args: ..Any) -> void #foreign clay "Clay__ElementPostConfiguration"; +AttachId :: (id: ElementId) -> void #foreign clay "Clay__AttachId"; +AttachLayoutConfig :: (config: *LayoutConfig) -> void #foreign clay "Clay__AttachLayoutConfig"; +AttachElementConfig :: (config: ElementConfigUnion, type: ElementConfigType) -> void #foreign clay "Clay__AttachElementConfig"; + +HashString :: (key: String, offset: u32, seed: u32) -> ElementId #foreign clay "Clay__HashString"; +Noop :: (__args: ..Any) -> void #foreign clay "Clay__Noop"; +OpenTextElement :: (text: String, textConfig: *TextElementConfig) -> void #foreign clay "Clay__OpenTextElement"; + +Clay__debugViewHighlightColor: Color #elsewhere clay; +Clay__debugViewWidth: u32 #elsewhere clay; +Clay__debugMaxElementsLatch: bool #elsewhere clay; + +#scope_file + +clay :: #library,no_dll "clay-jai/windows/clay";