diff --git a/.build/autosample.exp b/.build/autosample.exp new file mode 100644 index 0000000..82cd7ac Binary files /dev/null and b/.build/autosample.exp differ diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..875e626 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Read(//c/opt/jai/**)", + "Bash(cd:*)" + ] + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 16de434..8e6e10c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,40 +1,36 @@ { "version": "2.0.0", "tasks": [ - { - "label": "bootstrap nob", - "type": "shell", - "command": "cl", - "args": ["/nologo", "nob.c"], - "group": "build", - "problemMatcher": "$msCompile", - "detail": "One-time bootstrap: compile nob.c with cl.exe" - }, { "label": "build", "type": "shell", - "command": "${workspaceFolder}/nob.exe", - "group": "build", - "problemMatcher": "$msCompile", - "detail": "Build autosample via nob" + "command": "jai", + "args": ["build.jai"], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "detail": "Build autosample via jai" }, { "label": "rebuild", "type": "shell", - "command": "${workspaceFolder}/nob.exe", + "command": "jai", + "args": ["build.jai"], "group": "build", - "problemMatcher": "$msCompile", + "problemMatcher": [], "detail": "Clean and rebuild", "dependsOn": "clean" }, { "label": "clean", "type": "shell", - "command": "if (Test-Path build) { Remove-Item -Recurse -Force build }", + "command": "if (Test-Path build) { Remove-Item -Recurse -Force build }; if (Test-Path .build) { Remove-Item -Recurse -Force .build }", "args": [], "group": "build", "problemMatcher": [], - "detail": "Remove build directory" + "detail": "Remove build and .build directories" } ] } diff --git a/build.jai b/build.jai new file mode 100644 index 0000000..8b0dd49 --- /dev/null +++ b/build.jai @@ -0,0 +1,71 @@ +#import "Basic"; +#import "Compiler"; +#import "File"; +#import "File_Utilities"; + +IMGUI_PATH :: "modules/ImGui/src"; +IMGUI_LIB :: "modules/ImGui/windows/ImGui.lib"; + +build :: () { + set_build_options_dc(.{do_output=false}); + + // Build ImGui from source if the static lib doesn't exist + if !file_exists(IMGUI_LIB) { + print("ImGui.lib not found — building from source...\n"); + make_directory_if_it_does_not_exist("modules/ImGui/windows"); + + success := build_cpp_static_lib("modules/ImGui/windows/ImGui", + tprint("%/imgui.cpp", IMGUI_PATH), + tprint("%/imgui_widgets.cpp", IMGUI_PATH), + tprint("%/imgui_draw.cpp", IMGUI_PATH), + tprint("%/imgui_tables.cpp", IMGUI_PATH), + tprint("%/imgui_demo.cpp", IMGUI_PATH), + tprint("%/backends/imgui_impl_win32.cpp", IMGUI_PATH), + tprint("%/backends/imgui_impl_dx12.cpp", IMGUI_PATH), + tprint("%/imgui_backend_c.cpp", IMGUI_PATH), + extra = .[ + "/DIMGUI_API=__declspec(dllexport)", + "/DIMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS", + tprint("/I%", IMGUI_PATH), + tprint("/I%/backends", IMGUI_PATH), + ], + ); + + if !success { + compiler_set_workspace_status(.FAILED); + return; + } + print("ImGui.lib built successfully.\n"); + } + + w := compiler_create_workspace("autosample"); + if !w { + print("Workspace creation failed.\n"); + return; + } + + options := get_build_options(w); + options.output_executable_name = "autosample"; + options.output_path = "build/"; + + import_path: [..] string; + array_add(*import_path, "modules"); // Our local modules (ImGui) + for options.import_path array_add(*import_path, it); + options.import_path = import_path; + + set_build_options(options, w); + compiler_begin_intercept(w); + add_build_file("src/main.jai", w); + + while true { + message := compiler_wait_for_message(); + if !message break; + if message.kind == .COMPLETE break; + } + + compiler_end_intercept(w); +} + +#run build(); + +#import "BuildCpp"; diff --git a/modules/ImGui/.build/.added_strings_w2.jai b/modules/ImGui/.build/.added_strings_w2.jai new file mode 100644 index 0000000..294d3e2 --- /dev/null +++ b/modules/ImGui/.build/.added_strings_w2.jai @@ -0,0 +1,56 @@ +// Workspace: Target Program + +// +// String added via add_build_string() from c:/Users/mta/.vscode-oss/extensions/apparentlystudio.jails-0.2.0-universal/out/metaprogram/jails_diagnostics.jai:19. +// +JAILS_DIAGNOSTICS_BUILD :: true; + +// +// #insert text. Generated from C:/opt/jai/modules/Bindings_Generator/module.jai:369. +// + ([2] string).[ + .["FLT_MIN", "FLOAT32_MIN"], + .["FLT_MAX", "FLOAT32_MAX"], + .["DBL_MIN", "FLOAT64_MIN"], + .["DBL_MAX", "FLOAT64_MAX"], + + .["SCHAR_MIN", "S8_MIN"], + .["SCHAR_MAX", "S8_MAX"], + .["UCHAR_MIN", "0"], + .["UCHAR_MAX", "U8_MAX"], + + .["SHRT_MIN", "S16_MIN"], + .["SHRT_MAX", "S16_MAX"], + .["USHRT_MIN", "0"], + .["USHRT_MAX", "U16_MAX"], + + .["INT_MIN", "S32_MIN"], + .["INT_MAX", "S32_MAX"], + .["UINT_MIN", "0"], + .["UINT_MAX", "U32_MAX"], + + .["LLONG_MIN", "S64_MIN"], + .["LLONG_MAX", "S64_MAX"], + .["ULLONG_MIN", "0"], + .["ULLONG_MAX", "U64_MAX"], + + .["INT8_MIN", "S8_MIN"], + .["INT8_MAX", "S8_MAX"], + .["UINT8_MAX", "U8_MAX"], + + .["INT16_MIN", "S16_MIN"], + .["INT16_MAX", "S16_MAX"], + .["UINT16_MAX", "U16_MAX"], + + .["INT32_MIN", "S32_MIN"], + .["INT32_MAX", "S32_MAX"], + .["UINT32_MAX", "U32_MAX"], + + .["INT64_MIN", "S64_MIN"], + .["INT64_MAX", "S64_MAX"], + .["UINT64_MAX", "U64_MAX"], + .["LONG_MIN", "S32_MIN"], + .["LONG_MAX", "S32_MAX"], + .["ULONG_MIN", "0"], + .["ULONG_MAX", "U32_MAX"], +]; diff --git a/modules/ImGui/backend.jai b/modules/ImGui/backend.jai new file mode 100644 index 0000000..9d806b6 --- /dev/null +++ b/modules/ImGui/backend.jai @@ -0,0 +1,47 @@ +// Backend and DockBuilder declarations. +// These call into extern "C" wrappers in imgui_backend_c.cpp, compiled into ImGui.lib. + +#scope_export + +d3d12 :: #import "d3d12"; +dxgi :: #import "dxgi"; +Windows :: #import "Windows"; + +// ImGui_ImplDX12_InitInfo — mirrors the C++ struct layout. +ImplDX12_InitInfo :: struct { + Device: *d3d12.ID3D12Device; + CommandQueue: *d3d12.ID3D12CommandQueue; + NumFramesInFlight: s32; + RTVFormat: dxgi.DXGI_FORMAT; + DSVFormat: dxgi.DXGI_FORMAT; + UserData: *void; + SrvDescriptorHeap: *d3d12.ID3D12DescriptorHeap; + SrvDescriptorAllocFn: #type (info: *ImplDX12_InitInfo, out_cpu: *d3d12.D3D12_CPU_DESCRIPTOR_HANDLE, out_gpu: *d3d12.D3D12_GPU_DESCRIPTOR_HANDLE) #c_call; + SrvDescriptorFreeFn: #type (info: *ImplDX12_InitInfo, cpu: d3d12.D3D12_CPU_DESCRIPTOR_HANDLE, gpu: d3d12.D3D12_GPU_DESCRIPTOR_HANDLE) #c_call; + // Legacy single-descriptor fields (IMGUI_DISABLE_OBSOLETE_FUNCTIONS not set) + LegacySingleSrvCpuDescriptor: d3d12.D3D12_CPU_DESCRIPTOR_HANDLE; + LegacySingleSrvGpuDescriptor: d3d12.D3D12_GPU_DESCRIPTOR_HANDLE; +} + +// Win32 backend +ImplWin32_Init :: (hwnd: *void) -> bool #foreign imgui "jai_ImGui_ImplWin32_Init"; +ImplWin32_Shutdown :: () #foreign imgui "jai_ImGui_ImplWin32_Shutdown"; +ImplWin32_NewFrame :: () #foreign imgui "jai_ImGui_ImplWin32_NewFrame"; +ImplWin32_WndProcHandler :: (hWnd: Windows.HWND, msg: u32, wParam: Windows.WPARAM, lParam: Windows.LPARAM) -> Windows.LRESULT #foreign imgui "jai_ImGui_ImplWin32_WndProcHandler"; + +// DX12 backend +ImplDX12_Init :: (info: *ImplDX12_InitInfo) -> bool #foreign imgui "jai_ImGui_ImplDX12_Init"; +ImplDX12_Shutdown :: () #foreign imgui "jai_ImGui_ImplDX12_Shutdown"; +ImplDX12_NewFrame :: () #foreign imgui "jai_ImGui_ImplDX12_NewFrame"; +ImplDX12_RenderDrawData :: (draw_data: *ImDrawData, cmd_list: *d3d12.ID3D12GraphicsCommandList) #foreign imgui "jai_ImGui_ImplDX12_RenderDrawData"; + +// DockBuilder (from imgui_internal.h) +DockBuilderRemoveNode :: (node_id: ID) #foreign imgui "jai_DockBuilderRemoveNode"; +DockBuilderAddNode :: (node_id: ID, flags: s32) #foreign imgui "jai_DockBuilderAddNode"; +DockBuilderSetNodeSize :: (node_id: ID, size: ImVec2) #foreign imgui "jai_DockBuilderSetNodeSize"; +DockBuilderSplitNode :: (node_id: ID, split_dir: s32, size_ratio: float32, out_id_at_dir: *ID, out_id_at_opposite_dir: *ID) -> ID #foreign imgui "jai_DockBuilderSplitNode"; +DockBuilderDockWindow :: (window_name: *u8, node_id: ID) #foreign imgui "jai_DockBuilderDockWindow"; +DockBuilderFinish :: (node_id: ID) #foreign imgui "jai_DockBuilderFinish"; + +// Font loading +AddFontFromFileTTF :: (filename: *u8, size_pixels: float32) -> *void #foreign imgui "jai_AddFontFromFileTTF"; diff --git a/modules/ImGui/generate.jai b/modules/ImGui/generate.jai new file mode 100644 index 0000000..0d8fe96 --- /dev/null +++ b/modules/ImGui/generate.jai @@ -0,0 +1,239 @@ +AT_COMPILE_TIME :: true; + +IMGUI_PATH :: "src"; + +DECLARATIONS_TO_OMIT :: string.[ + "ImVec2", + "ImVec4", + "ImColor", + "ImVector", + "ImDrawCallback", + "ImGuiTextBuffer", + "ImDrawCallback_ResetRenderState", +]; + +#if AT_COMPILE_TIME { + #run,stallable { + set_build_options_dc(.{do_output=false}); + root_options := get_build_options(); + args := root_options.compile_time_command_line; + if !generate_bindings(args) { + compiler_set_workspace_status(.FAILED); + } + } +} else { + #import "System"; + + main :: () { + set_working_directory(path_strip_filename(get_path_of_running_executable())); + args := get_command_line_arguments(); + if !generate_bindings(args) { + exit(1); + } + } +} + +generate_bindings :: (args: [] string) -> bool { + compile := array_find(args, "-compile"); + compile_debug := array_find(args, "-debug"); + + if compile { + imgui_src_files: [..] string; + array_add(*imgui_src_files, tprint("%/imgui.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/imgui_widgets.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/imgui_draw.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/imgui_tables.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/imgui_demo.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/backends/imgui_impl_win32.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/backends/imgui_impl_dx12.cpp", IMGUI_PATH)); + array_add(*imgui_src_files, tprint("%/imgui_backend_c.cpp", IMGUI_PATH)); + + success := true; + #if OS == .WINDOWS { + make_directory_if_it_does_not_exist("windows"); + success &&= build_cpp_static_lib("windows/ImGui", ..imgui_src_files, + extra = .[ + "/DIMGUI_API=__declspec(dllexport)", + "/DIMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS", + tprint("/I%", IMGUI_PATH), + tprint("/I%/backends", IMGUI_PATH), + ], + debug=compile_debug); + } else { + assert(false, "Only Windows is supported for this project."); + } + + if !success return false; + } + + defer array_reset(*begin_end_string_args); + + output_filename: string; + opts: Generate_Bindings_Options; + { + using opts; + + #if OS == .WINDOWS { + array_add(*library_search_paths, "windows"); + output_filename = "windows.jai"; + } else { + assert(false); + } + + array_add(*libraries, .{filename="ImGui"}); + array_add(*include_paths, IMGUI_PATH); + array_add(*source_files, tprint("%/imgui.h", IMGUI_PATH)); + array_add(*extra_clang_arguments, "-x", "c++", "-DWIN32_LEAN_AND_MEAN"); + array_add(*flatten_namespaces, "ImGui"); + array_add(*strip_prefixes, "ImGui"); + auto_detect_enum_prefixes = false; + log_stripped_declarations = false; + generate_compile_time_struct_checks = false; + strip_flags |= .INLINED_FUNCTIONS; + + visitor = imgui_visitor; + get_func_args_for_printing = imgui_get_function_arg_for_printing; + } + + return generate_bindings(opts, output_filename); +} + +begin_end_string_args: [..]*Declaration; + +enums_for_typedefs: Table(string, *Enum); + +imgui_visitor :: (decl: *Declaration, parent_decl: *Declaration) -> Declaration_Visit_Result { + get_associated_enum_name :: (name: string) -> string { + if name.count > 1 && name[name.count - 1] != #char "_" { + return tprint("%_", name); + } + return name; + } + + if !parent_decl { + if array_find(DECLARATIONS_TO_OMIT, decl.name) { + decl.decl_flags |= .OMIT_FROM_OUTPUT; + return .STOP; + } + if decl.name == "ImGuiContext" { + decl.output_name = decl.name; + } + + if decl.kind == .TYPEDEF { + old_name := decl.name; + if old_name { + new_name := get_associated_enum_name(old_name); + for context.generator.global_scope.members { + if it.kind != .ENUM || it.name != new_name continue; + + en := cast(*Enum)it; + decl.decl_flags |= .OMIT_FROM_OUTPUT; + + if en.output_name.count > 2 && en.output_name[en.output_name.count - 1] == #char "_" { + en.output_name.count -= 1; + } + + if decl.comment.text && !en.comment.text { + en.comment = decl.comment; + } + + table_add(*enums_for_typedefs, old_name, en); + break; + } + } + } + } + + if parent_decl && + (parent_decl.kind == .FUNCTION || parent_decl.kind == .STRUCT) && + decl.kind == .DECLARATION && decl.type.type_of_typedef != null + { + old_name := decl.type.type_of_typedef.name; + if old_name { + found, en := table_find(*enums_for_typedefs, old_name); + if found { + change_type_to_enum(decl, en); + } + } + } + + if decl.kind == .ENUM { + if ends_with(decl.name, "Flags_") { + en := cast(*Enum)decl; + en.flags |= .IS_ENUM_FLAGS; + en.flags |= .VALUES_IN_HEX; + } + } + + if decl.kind == .FUNCTION { + func := cast(*Function)decl; + type := func.type.type_of_function; + for type.arguments { + if it_index == 0 || !ends_with(it.name, "_end") continue; + arg_type := find_underlying_type(it.type); + if !arg_type.pointer_to || !(arg_type.pointer_to.number_flags & ._8BIT) continue; + + name_part := slice(it.name, 0, it.name.count - "_end".count); + if !name_part continue; + + name_part_with_begin := tprint("%_begin", name_part); + prev_arg := type.arguments[it_index - 1]; + if prev_arg.name == name_part || prev_arg.name == name_part_with_begin { + array_add(*begin_end_string_args, prev_arg); + func.decl_flags |= .NEEDS_ARGUMENT_WRAPPER; + } + } + } + + return .RECURSE; +} + +imgui_get_function_arg_for_printing :: (func: *Function, type: *Function_Type, mode: Arg_Print_Mode) -> []*Declaration { + args: [..]*Declaration; + for type.arguments { + if array_find(begin_end_string_args, it) { + if mode == { + case .OUTER_WRAPPER; + arg_copy := New(Declaration); + (arg_copy.*) = it.*; + arg_copy.type = context.generator.type_def_jai_string; + if ends_with(it.name, "_begin") { + arg_copy.output_name = slice(it.name, 0, it.name.count - "_begin".count); + } + array_add(*args, arg_copy); + it_index += 1; + continue; + case .INNER_WRAPPER_CALL; + base_arg_name := it.name; + if ends_with(it.name, "_begin") { + base_arg_name = slice(it.name, 0, it.name.count - "_begin".count); + } + + arg_copy := New(Declaration); + (arg_copy.*) = it.*; + arg_copy.output_name = tprint("%.data", base_arg_name); + array_add(*args, arg_copy); + + arg_copy_2 := New(Declaration); + (arg_copy_2.*) = it.*; + arg_copy_2.output_name = tprint("%.data + %.count", base_arg_name, base_arg_name); + array_add(*args, arg_copy_2); + + it_index += 1; + continue; + } + } + + array_add(*args, it); + } + + return args; +} + +#import "Basic"; +#import "Bindings_Generator"; +#import "BuildCpp"; +#import "Compiler"; +#import "File"; +#import "Hash_Table"; +#import "String"; diff --git a/modules/ImGui/module.jai b/modules/ImGui/module.jai new file mode 100644 index 0000000..47e8120 --- /dev/null +++ b/modules/ImGui/module.jai @@ -0,0 +1,30 @@ +// ImGui module for autosample — docking branch 1.92.7 +// Core bindings are auto-generated in windows.jai via generate.jai. +// Backend and DockBuilder wrappers use C-linkage via imgui_backend_c.cpp. + +ImVec2 :: Vector2; +ImVec4 :: Vector4; +ImColor :: Vector4; + +ImVector :: struct (T: Type) { + Size: s32; + Capacity: s32; + Data: *T; +} + +ImDrawCallback :: #type (parent_list: *ImDrawList, cmd: *ImDrawCmd) #c_call; + +#scope_module + +#import "Basic"; +#import "Math"; + +#if OS == .WINDOWS { + imgui :: #library,no_dll "windows/ImGui"; + #load "windows.jai"; + #load "backend.jai"; + #library,system,link_always "user32"; + #library,system,link_always "gdi32"; + #library,system,link_always "dwmapi"; + #library,system,link_always "d3dcompiler"; +} diff --git a/vendor/imgui/backends/imgui_impl_dx12.cpp b/modules/ImGui/src/backends/imgui_impl_dx12.cpp similarity index 100% rename from vendor/imgui/backends/imgui_impl_dx12.cpp rename to modules/ImGui/src/backends/imgui_impl_dx12.cpp diff --git a/vendor/imgui/backends/imgui_impl_dx12.h b/modules/ImGui/src/backends/imgui_impl_dx12.h similarity index 100% rename from vendor/imgui/backends/imgui_impl_dx12.h rename to modules/ImGui/src/backends/imgui_impl_dx12.h diff --git a/vendor/imgui/backends/imgui_impl_win32.cpp b/modules/ImGui/src/backends/imgui_impl_win32.cpp similarity index 100% rename from vendor/imgui/backends/imgui_impl_win32.cpp rename to modules/ImGui/src/backends/imgui_impl_win32.cpp diff --git a/vendor/imgui/backends/imgui_impl_win32.h b/modules/ImGui/src/backends/imgui_impl_win32.h similarity index 100% rename from vendor/imgui/backends/imgui_impl_win32.h rename to modules/ImGui/src/backends/imgui_impl_win32.h diff --git a/vendor/imgui/imconfig.h b/modules/ImGui/src/imconfig.h similarity index 100% rename from vendor/imgui/imconfig.h rename to modules/ImGui/src/imconfig.h diff --git a/vendor/imgui/imgui.cpp b/modules/ImGui/src/imgui.cpp similarity index 100% rename from vendor/imgui/imgui.cpp rename to modules/ImGui/src/imgui.cpp diff --git a/vendor/imgui/imgui.h b/modules/ImGui/src/imgui.h similarity index 100% rename from vendor/imgui/imgui.h rename to modules/ImGui/src/imgui.h diff --git a/modules/ImGui/src/imgui_backend_c.cpp b/modules/ImGui/src/imgui_backend_c.cpp new file mode 100644 index 0000000..d1537e4 --- /dev/null +++ b/modules/ImGui/src/imgui_backend_c.cpp @@ -0,0 +1,77 @@ +// Thin extern "C" wrapper for ImGui backend functions. +// This avoids C++ name mangling so Jai can call them with simple #foreign declarations. + +#include "imgui.h" +#include "imgui_internal.h" +#include "imgui_impl_win32.h" +#include "imgui_impl_dx12.h" +#include + +// Forward declare — intentionally behind #if 0 in imgui_impl_win32.h +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +extern "C" { + +bool jai_ImGui_ImplWin32_Init(void* hwnd) { + return ImGui_ImplWin32_Init(hwnd); +} + +void jai_ImGui_ImplWin32_Shutdown() { + ImGui_ImplWin32_Shutdown(); +} + +void jai_ImGui_ImplWin32_NewFrame() { + ImGui_ImplWin32_NewFrame(); +} + +LRESULT jai_ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + return ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam); +} + +bool jai_ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* info) { + return ImGui_ImplDX12_Init(info); +} + +void jai_ImGui_ImplDX12_Shutdown() { + ImGui_ImplDX12_Shutdown(); +} + +void jai_ImGui_ImplDX12_NewFrame() { + ImGui_ImplDX12_NewFrame(); +} + +void jai_ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* cmd_list) { + ImGui_ImplDX12_RenderDrawData(draw_data, cmd_list); +} + +// DockBuilder functions (from imgui_internal.h) +void jai_DockBuilderRemoveNode(ImGuiID node_id) { + ImGui::DockBuilderRemoveNode(node_id); +} + +void jai_DockBuilderAddNode(ImGuiID node_id, int flags) { + ImGui::DockBuilderAddNode(node_id, (ImGuiDockNodeFlags)flags); +} + +void jai_DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size) { + ImGui::DockBuilderSetNodeSize(node_id, size); +} + +ImGuiID jai_DockBuilderSplitNode(ImGuiID node_id, int split_dir, float size_ratio, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir) { + return ImGui::DockBuilderSplitNode(node_id, (ImGuiDir)split_dir, size_ratio, out_id_at_dir, out_id_at_opposite_dir); +} + +void jai_DockBuilderDockWindow(const char* window_name, ImGuiID node_id) { + ImGui::DockBuilderDockWindow(window_name, node_id); +} + +void jai_DockBuilderFinish(ImGuiID node_id) { + ImGui::DockBuilderFinish(node_id); +} + +// Font loading (convenience wrapper) +void* jai_AddFontFromFileTTF(const char* filename, float size_pixels) { + return ImGui::GetIO().Fonts->AddFontFromFileTTF(filename, size_pixels); +} + +} // extern "C" diff --git a/vendor/imgui/imgui_demo.cpp b/modules/ImGui/src/imgui_demo.cpp similarity index 100% rename from vendor/imgui/imgui_demo.cpp rename to modules/ImGui/src/imgui_demo.cpp diff --git a/vendor/imgui/imgui_draw.cpp b/modules/ImGui/src/imgui_draw.cpp similarity index 100% rename from vendor/imgui/imgui_draw.cpp rename to modules/ImGui/src/imgui_draw.cpp diff --git a/vendor/imgui/imgui_internal.h b/modules/ImGui/src/imgui_internal.h similarity index 100% rename from vendor/imgui/imgui_internal.h rename to modules/ImGui/src/imgui_internal.h diff --git a/vendor/imgui/imgui_tables.cpp b/modules/ImGui/src/imgui_tables.cpp similarity index 100% rename from vendor/imgui/imgui_tables.cpp rename to modules/ImGui/src/imgui_tables.cpp diff --git a/vendor/imgui/imgui_widgets.cpp b/modules/ImGui/src/imgui_widgets.cpp similarity index 100% rename from vendor/imgui/imgui_widgets.cpp rename to modules/ImGui/src/imgui_widgets.cpp diff --git a/vendor/imgui/imstb_rectpack.h b/modules/ImGui/src/imstb_rectpack.h similarity index 100% rename from vendor/imgui/imstb_rectpack.h rename to modules/ImGui/src/imstb_rectpack.h diff --git a/vendor/imgui/imstb_textedit.h b/modules/ImGui/src/imstb_textedit.h similarity index 100% rename from vendor/imgui/imstb_textedit.h rename to modules/ImGui/src/imstb_textedit.h diff --git a/vendor/imgui/imstb_truetype.h b/modules/ImGui/src/imstb_truetype.h similarity index 100% rename from vendor/imgui/imstb_truetype.h rename to modules/ImGui/src/imstb_truetype.h diff --git a/modules/ImGui/windows.jai b/modules/ImGui/windows.jai new file mode 100644 index 0000000..37ce92d --- /dev/null +++ b/modules/ImGui/windows.jai @@ -0,0 +1,4490 @@ +// +// This file was auto-generated using the following command: +// +// jai c:/Users/mta/projects/autosample//modules/ImGui/generate.jai modules +jails_diagnostics import_dir c:/Users/mta/.vscode-oss/extensions/apparentlystudio.jails-0.2.0-universal/out/metaprogram +// + + + +IMGUI_VERSION :: "1.92.7 WIP"; +IMGUI_VERSION_NUM :: 19262; + +ImTextureID_Invalid :: cast(ImTextureID) 0; + +IMGUI_PAYLOAD_TYPE_COLOR_3F :: "_COL3F"; +IMGUI_PAYLOAD_TYPE_COLOR_4F :: "_COL4F"; + +IM_UNICODE_CODEPOINT_INVALID :: 0xFFFD; + +IM_UNICODE_CODEPOINT_MAX :: 0xFFFF; + +IM_COL32_R_SHIFT :: 0; +IM_COL32_G_SHIFT :: 8; +IM_COL32_B_SHIFT :: 16; +IM_COL32_A_SHIFT :: 24; +IM_COL32_A_MASK :: 0xFF000000; + +IM_DRAWLIST_TEX_LINES_WIDTH_MAX :: 32; + +ImFontAtlasRectId_Invalid :: -1; + +// Scalar data types +ID :: u32; +ImS8 :: s8; +ImU8 :: u8; +ImS16 :: s16; +ImU16 :: u16; +ImS32 :: s32; +ImU32 :: u32; +ImS64 :: s64; +ImU64 :: u64; + +ImDrawListSharedData :: struct {} + +ImFontAtlasBuilder :: struct {} + +ImFontLoader :: struct {} + +// Forward declarations: ImGui layer +ImGuiContext :: struct {} + +// Enumerations +// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// - In Visual Studio: Ctrl+Comma ("Edit.GoToAll") can follow symbols inside comments, whereas Ctrl+F12 ("Edit.GoToImplementation") cannot. +// - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +// - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments. +Dir :: enum s32 { + None :: -1; + Left :: 0; + Right :: 1; + Up :: 2; + Down :: 3; + COUNT :: 4; + + ImGuiDir_None :: None; + ImGuiDir_Left :: Left; + ImGuiDir_Right :: Right; + ImGuiDir_Up :: Up; + ImGuiDir_Down :: Down; + ImGuiDir_COUNT :: COUNT; +} + +// A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. +// All our named keys are >= 512. Keys value 0 to 511 are left unused and were legacy native/opaque key values (< 1.87). +// Support for legacy keys was completely removed in 1.91.5. +// Read details about the 1.87+ transition : https://github.com/ocornut/imgui/issues/4921 +// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the latter are submitted via io.AddInputCharacter(). +// The keyboard key enum values are named after the keys on a standard US keyboard, and on other keyboard types the keys reported may not match the keycaps. +Key :: enum s32 { + None :: 0; + NamedKey_BEGIN :: 512; + + Tab :: 512; + LeftArrow :: 513; + RightArrow :: 514; + UpArrow :: 515; + DownArrow :: 516; + PageUp :: 517; + PageDown :: 518; + Home :: 519; + End :: 520; + Insert :: 521; + Delete :: 522; + Backspace :: 523; + Space :: 524; + Enter :: 525; + Escape :: 526; + LeftCtrl :: 527; + LeftShift :: 528; + LeftAlt :: 529; + LeftSuper :: 530; + RightCtrl :: 531; + RightShift :: 532; + RightAlt :: 533; + RightSuper :: 534; + Menu :: 535; + _0 :: 536; + _1 :: 537; + _2 :: 538; + _3 :: 539; + _4 :: 540; + _5 :: 541; + _6 :: 542; + _7 :: 543; + _8 :: 544; + _9 :: 545; + A :: 546; + B :: 547; + C :: 548; + D :: 549; + E :: 550; + F :: 551; + G :: 552; + H :: 553; + I :: 554; + J :: 555; + K :: 556; + L :: 557; + M :: 558; + N :: 559; + O :: 560; + P :: 561; + Q :: 562; + R :: 563; + S :: 564; + T :: 565; + U :: 566; + V :: 567; + W :: 568; + X :: 569; + Y :: 570; + Z :: 571; + F1 :: 572; + F2 :: 573; + F3 :: 574; + F4 :: 575; + F5 :: 576; + F6 :: 577; + F7 :: 578; + F8 :: 579; + F9 :: 580; + F10 :: 581; + F11 :: 582; + F12 :: 583; + F13 :: 584; + F14 :: 585; + F15 :: 586; + F16 :: 587; + F17 :: 588; + F18 :: 589; + F19 :: 590; + F20 :: 591; + F21 :: 592; + F22 :: 593; + F23 :: 594; + F24 :: 595; + Apostrophe :: 596; + Comma :: 597; + Minus :: 598; + Period :: 599; + Slash :: 600; + Semicolon :: 601; + Equal :: 602; + LeftBracket :: 603; + Backslash :: 604; + RightBracket :: 605; + GraveAccent :: 606; + CapsLock :: 607; + ScrollLock :: 608; + NumLock :: 609; + PrintScreen :: 610; + Pause :: 611; + Keypad0 :: 612; + Keypad1 :: 613; + Keypad2 :: 614; + Keypad3 :: 615; + Keypad4 :: 616; + Keypad5 :: 617; + Keypad6 :: 618; + Keypad7 :: 619; + Keypad8 :: 620; + Keypad9 :: 621; + KeypadDecimal :: 622; + KeypadDivide :: 623; + KeypadMultiply :: 624; + KeypadSubtract :: 625; + KeypadAdd :: 626; + KeypadEnter :: 627; + KeypadEqual :: 628; + AppBack :: 629; + AppForward :: 630; + Oem102 :: 631; + + GamepadStart :: 632; + GamepadBack :: 633; + GamepadFaceLeft :: 634; + GamepadFaceRight :: 635; + GamepadFaceUp :: 636; + GamepadFaceDown :: 637; + GamepadDpadLeft :: 638; + GamepadDpadRight :: 639; + GamepadDpadUp :: 640; + GamepadDpadDown :: 641; + GamepadL1 :: 642; + GamepadR1 :: 643; + GamepadL2 :: 644; + GamepadR2 :: 645; + GamepadL3 :: 646; + GamepadR3 :: 647; + GamepadLStickLeft :: 648; + GamepadLStickRight :: 649; + GamepadLStickUp :: 650; + GamepadLStickDown :: 651; + GamepadRStickLeft :: 652; + GamepadRStickRight :: 653; + GamepadRStickUp :: 654; + GamepadRStickDown :: 655; + + MouseLeft :: 656; + MouseRight :: 657; + MouseMiddle :: 658; + MouseX1 :: 659; + MouseX2 :: 660; + MouseWheelX :: 661; + MouseWheelY :: 662; + + ReservedForModCtrl :: 663; + ReservedForModShift :: 664; + ReservedForModAlt :: 665; + ReservedForModSuper :: 666; + + NamedKey_END :: 667; + NamedKey_COUNT :: 155; + + Mod_None :: 0; + Mod_Ctrl :: 4096; + Mod_Shift :: 8192; + Mod_Alt :: 16384; + Mod_Super :: 32768; + Mod_Mask_ :: 61440; + + COUNT :: 667; + Mod_Shortcut :: 4096; + + ImGuiKey_None :: None; + ImGuiKey_NamedKey_BEGIN :: NamedKey_BEGIN; + + ImGuiKey_Tab :: Tab; + ImGuiKey_LeftArrow :: LeftArrow; + ImGuiKey_RightArrow :: RightArrow; + ImGuiKey_UpArrow :: UpArrow; + ImGuiKey_DownArrow :: DownArrow; + ImGuiKey_PageUp :: PageUp; + ImGuiKey_PageDown :: PageDown; + ImGuiKey_Home :: Home; + ImGuiKey_End :: End; + ImGuiKey_Insert :: Insert; + ImGuiKey_Delete :: Delete; + ImGuiKey_Backspace :: Backspace; + ImGuiKey_Space :: Space; + ImGuiKey_Enter :: Enter; + ImGuiKey_Escape :: Escape; + ImGuiKey_LeftCtrl :: LeftCtrl; + ImGuiKey_LeftShift :: LeftShift; + ImGuiKey_LeftAlt :: LeftAlt; + ImGuiKey_LeftSuper :: LeftSuper; + ImGuiKey_RightCtrl :: RightCtrl; + ImGuiKey_RightShift :: RightShift; + ImGuiKey_RightAlt :: RightAlt; + ImGuiKey_RightSuper :: RightSuper; + ImGuiKey_Menu :: Menu; + ImGuiKey_0 :: _0; + ImGuiKey_1 :: _1; + ImGuiKey_2 :: _2; + ImGuiKey_3 :: _3; + ImGuiKey_4 :: _4; + ImGuiKey_5 :: _5; + ImGuiKey_6 :: _6; + ImGuiKey_7 :: _7; + ImGuiKey_8 :: _8; + ImGuiKey_9 :: _9; + ImGuiKey_A :: A; + ImGuiKey_B :: B; + ImGuiKey_C :: C; + ImGuiKey_D :: D; + ImGuiKey_E :: E; + ImGuiKey_F :: F; + ImGuiKey_G :: G; + ImGuiKey_H :: H; + ImGuiKey_I :: I; + ImGuiKey_J :: J; + ImGuiKey_K :: K; + ImGuiKey_L :: L; + ImGuiKey_M :: M; + ImGuiKey_N :: N; + ImGuiKey_O :: O; + ImGuiKey_P :: P; + ImGuiKey_Q :: Q; + ImGuiKey_R :: R; + ImGuiKey_S :: S; + ImGuiKey_T :: T; + ImGuiKey_U :: U; + ImGuiKey_V :: V; + ImGuiKey_W :: W; + ImGuiKey_X :: X; + ImGuiKey_Y :: Y; + ImGuiKey_Z :: Z; + ImGuiKey_F1 :: F1; + ImGuiKey_F2 :: F2; + ImGuiKey_F3 :: F3; + ImGuiKey_F4 :: F4; + ImGuiKey_F5 :: F5; + ImGuiKey_F6 :: F6; + ImGuiKey_F7 :: F7; + ImGuiKey_F8 :: F8; + ImGuiKey_F9 :: F9; + ImGuiKey_F10 :: F10; + ImGuiKey_F11 :: F11; + ImGuiKey_F12 :: F12; + ImGuiKey_F13 :: F13; + ImGuiKey_F14 :: F14; + ImGuiKey_F15 :: F15; + ImGuiKey_F16 :: F16; + ImGuiKey_F17 :: F17; + ImGuiKey_F18 :: F18; + ImGuiKey_F19 :: F19; + ImGuiKey_F20 :: F20; + ImGuiKey_F21 :: F21; + ImGuiKey_F22 :: F22; + ImGuiKey_F23 :: F23; + ImGuiKey_F24 :: F24; + ImGuiKey_Apostrophe :: Apostrophe; + ImGuiKey_Comma :: Comma; + ImGuiKey_Minus :: Minus; + ImGuiKey_Period :: Period; + ImGuiKey_Slash :: Slash; + ImGuiKey_Semicolon :: Semicolon; + ImGuiKey_Equal :: Equal; + ImGuiKey_LeftBracket :: LeftBracket; + ImGuiKey_Backslash :: Backslash; + ImGuiKey_RightBracket :: RightBracket; + ImGuiKey_GraveAccent :: GraveAccent; + ImGuiKey_CapsLock :: CapsLock; + ImGuiKey_ScrollLock :: ScrollLock; + ImGuiKey_NumLock :: NumLock; + ImGuiKey_PrintScreen :: PrintScreen; + ImGuiKey_Pause :: Pause; + ImGuiKey_Keypad0 :: Keypad0; + ImGuiKey_Keypad1 :: Keypad1; + ImGuiKey_Keypad2 :: Keypad2; + ImGuiKey_Keypad3 :: Keypad3; + ImGuiKey_Keypad4 :: Keypad4; + ImGuiKey_Keypad5 :: Keypad5; + ImGuiKey_Keypad6 :: Keypad6; + ImGuiKey_Keypad7 :: Keypad7; + ImGuiKey_Keypad8 :: Keypad8; + ImGuiKey_Keypad9 :: Keypad9; + ImGuiKey_KeypadDecimal :: KeypadDecimal; + ImGuiKey_KeypadDivide :: KeypadDivide; + ImGuiKey_KeypadMultiply :: KeypadMultiply; + ImGuiKey_KeypadSubtract :: KeypadSubtract; + ImGuiKey_KeypadAdd :: KeypadAdd; + ImGuiKey_KeypadEnter :: KeypadEnter; + ImGuiKey_KeypadEqual :: KeypadEqual; + ImGuiKey_AppBack :: AppBack; + ImGuiKey_AppForward :: AppForward; + ImGuiKey_Oem102 :: Oem102; + + ImGuiKey_GamepadStart :: GamepadStart; + ImGuiKey_GamepadBack :: GamepadBack; + ImGuiKey_GamepadFaceLeft :: GamepadFaceLeft; + ImGuiKey_GamepadFaceRight :: GamepadFaceRight; + ImGuiKey_GamepadFaceUp :: GamepadFaceUp; + ImGuiKey_GamepadFaceDown :: GamepadFaceDown; + ImGuiKey_GamepadDpadLeft :: GamepadDpadLeft; + ImGuiKey_GamepadDpadRight :: GamepadDpadRight; + ImGuiKey_GamepadDpadUp :: GamepadDpadUp; + ImGuiKey_GamepadDpadDown :: GamepadDpadDown; + ImGuiKey_GamepadL1 :: GamepadL1; + ImGuiKey_GamepadR1 :: GamepadR1; + ImGuiKey_GamepadL2 :: GamepadL2; + ImGuiKey_GamepadR2 :: GamepadR2; + ImGuiKey_GamepadL3 :: GamepadL3; + ImGuiKey_GamepadR3 :: GamepadR3; + ImGuiKey_GamepadLStickLeft :: GamepadLStickLeft; + ImGuiKey_GamepadLStickRight :: GamepadLStickRight; + ImGuiKey_GamepadLStickUp :: GamepadLStickUp; + ImGuiKey_GamepadLStickDown :: GamepadLStickDown; + ImGuiKey_GamepadRStickLeft :: GamepadRStickLeft; + ImGuiKey_GamepadRStickRight :: GamepadRStickRight; + ImGuiKey_GamepadRStickUp :: GamepadRStickUp; + ImGuiKey_GamepadRStickDown :: GamepadRStickDown; + + ImGuiKey_MouseLeft :: MouseLeft; + ImGuiKey_MouseRight :: MouseRight; + ImGuiKey_MouseMiddle :: MouseMiddle; + ImGuiKey_MouseX1 :: MouseX1; + ImGuiKey_MouseX2 :: MouseX2; + ImGuiKey_MouseWheelX :: MouseWheelX; + ImGuiKey_MouseWheelY :: MouseWheelY; + + ImGuiKey_ReservedForModCtrl :: ReservedForModCtrl; + ImGuiKey_ReservedForModShift :: ReservedForModShift; + ImGuiKey_ReservedForModAlt :: ReservedForModAlt; + ImGuiKey_ReservedForModSuper :: ReservedForModSuper; + + ImGuiKey_NamedKey_END :: NamedKey_END; + ImGuiKey_NamedKey_COUNT :: NamedKey_COUNT; + + ImGuiMod_None :: Mod_None; + ImGuiMod_Ctrl :: Mod_Ctrl; + ImGuiMod_Shift :: Mod_Shift; + ImGuiMod_Alt :: Mod_Alt; + ImGuiMod_Super :: Mod_Super; + ImGuiMod_Mask_ :: Mod_Mask_; + + ImGuiKey_COUNT :: COUNT; + ImGuiMod_Shortcut :: Mod_Shortcut; +} + +// Enumeration for AddMouseSourceEvent() actual source of Mouse Input data. +// Historically we use "Mouse" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), io.AddMousePosEvent() +// But that "Mouse" data can come from different source which occasionally may be useful for application to know about. +// You can submit a change of pointer type using io.AddMouseSourceEvent(). +MouseSource :: enum s32 { + Mouse :: 0; + TouchScreen :: 1; + Pen :: 2; + COUNT :: 3; + + ImGuiMouseSource_Mouse :: Mouse; + ImGuiMouseSource_TouchScreen :: TouchScreen; + ImGuiMouseSource_Pen :: Pen; + ImGuiMouseSource_COUNT :: COUNT; +} + +// A sorting direction +SortDirection :: enum ImU8 { + None :: 0; + Ascending :: 1; + Descending :: 2; + + ImGuiSortDirection_None :: None; + ImGuiSortDirection_Ascending :: Ascending; + ImGuiSortDirection_Descending :: Descending; +} + +ImDrawTextFlags :: s32; + +KeyChord :: s32; + +// Character types +// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) +ImWchar32 :: u32; +ImWchar16 :: u16; + +ImWchar :: ImWchar16; + +// Multi-Selection item index or identifier when using BeginMultiSelect() +// - Used by SetNextItemSelectionUserData() + and inside ImGuiMultiSelectIO structure. +// - Most users are likely to use this store an item INDEX but this may be used to store a POINTER/ID as well. Read comments near ImGuiMultiSelectIO for details. +SelectionUserData :: ImS64; + +// Callback and functions types +InputTextCallback :: #type (data: *InputTextCallbackData) -> s32 #c_call; +SizeCallback :: #type (data: *SizeCallbackData) -> void #c_call; +MemAllocFunc :: #type (sz: u64, user_data: *void) -> *void #c_call; +MemFreeFunc :: #type (ptr: *void, user_data: *void) -> void #c_call; + +ImTextureID :: ImU64; + +// ImTextureRef = higher-level identifier for a texture. Store a ImTextureID _or_ a ImTextureData*. +// The identifier is valid even before the texture has been uploaded to the GPU/graphics system. +// This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. +// This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. +// - When a texture is created by user code (e.g. custom images), we directly store the low-level ImTextureID. +// Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. +// - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection +// to extract the ImTextureID value during rendering, after texture upload has happened. +// - To create a ImTextureRef from a ImTextureData you can use ImTextureData::GetTexRef(). +// We intentionally do not provide an ImTextureRef constructor for this: we don't expect this +// to be frequently useful to the end-user, and it would be erroneously called by many legacy code. +// - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. +// - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. +// inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } +// In 1.92 we changed most drawing functions using ImTextureID to use ImTextureRef. +// We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. +ImTextureRef :: struct { + _TexData: *ImTextureData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded. + _TexID: ImTextureID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui::Image() calls. +} +//----------------------------------------------------------------------------- +// [SECTION] Dear ImGui end-user API functions +// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) +//----------------------------------------------------------------------------- + +// Context creation and access +// - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts. +// - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for details. +CreateContext :: (shared_font_atlas: *ImFontAtlas = null) -> *ImGuiContext #foreign imgui "?CreateContext@ImGui@@YAPEAUImGuiContext@@PEAUImFontAtlas@@@Z"; +DestroyContext :: (ctx: *ImGuiContext = null) -> void #foreign imgui "?DestroyContext@ImGui@@YAXPEAUImGuiContext@@@Z"; +GetCurrentContext :: () -> *ImGuiContext #foreign imgui "?GetCurrentContext@ImGui@@YAPEAUImGuiContext@@XZ"; +SetCurrentContext :: (ctx: *ImGuiContext) -> void #foreign imgui "?SetCurrentContext@ImGui@@YAXPEAUImGuiContext@@@Z"; + +// Main +GetIO :: () -> *IO #foreign imgui "?GetIO@ImGui@@YAAEAUImGuiIO@@XZ"; +GetPlatformIO :: () -> *PlatformIO #foreign imgui "?GetPlatformIO@ImGui@@YAAEAUImGuiPlatformIO@@XZ"; +GetStyle :: () -> *Style #foreign imgui "?GetStyle@ImGui@@YAAEAUImGuiStyle@@XZ"; +NewFrame :: () -> void #foreign imgui "?NewFrame@ImGui@@YAXXZ"; +EndFrame :: () -> void #foreign imgui "?EndFrame@ImGui@@YAXXZ"; +Render :: () -> void #foreign imgui "?Render@ImGui@@YAXXZ"; +GetDrawData :: () -> *ImDrawData #foreign imgui "?GetDrawData@ImGui@@YAPEAUImDrawData@@XZ"; + +// Demo, Debug, Information +ShowDemoWindow :: (p_open: *bool = null) -> void #foreign imgui "?ShowDemoWindow@ImGui@@YAXPEA_N@Z"; +ShowMetricsWindow :: (p_open: *bool = null) -> void #foreign imgui "?ShowMetricsWindow@ImGui@@YAXPEA_N@Z"; +ShowDebugLogWindow :: (p_open: *bool = null) -> void #foreign imgui "?ShowDebugLogWindow@ImGui@@YAXPEA_N@Z"; +ShowIDStackToolWindow :: (p_open: *bool = null) -> void #foreign imgui "?ShowIDStackToolWindow@ImGui@@YAXPEA_N@Z"; +ShowAboutWindow :: (p_open: *bool = null) -> void #foreign imgui "?ShowAboutWindow@ImGui@@YAXPEA_N@Z"; +ShowStyleEditor :: (ref: *Style = null) -> void #foreign imgui "?ShowStyleEditor@ImGui@@YAXPEAUImGuiStyle@@@Z"; +ShowStyleSelector :: (label: *u8) -> bool #foreign imgui "?ShowStyleSelector@ImGui@@YA_NPEBD@Z"; +ShowFontSelector :: (label: *u8) -> void #foreign imgui "?ShowFontSelector@ImGui@@YAXPEBD@Z"; +ShowUserGuide :: () -> void #foreign imgui "?ShowUserGuide@ImGui@@YAXXZ"; +GetVersion :: () -> *u8 #foreign imgui "?GetVersion@ImGui@@YAPEBDXZ"; + +// Styles +StyleColorsDark :: (dst: *Style = null) -> void #foreign imgui "?StyleColorsDark@ImGui@@YAXPEAUImGuiStyle@@@Z"; +StyleColorsLight :: (dst: *Style = null) -> void #foreign imgui "?StyleColorsLight@ImGui@@YAXPEAUImGuiStyle@@@Z"; +StyleColorsClassic :: (dst: *Style = null) -> void #foreign imgui "?StyleColorsClassic@ImGui@@YAXPEAUImGuiStyle@@@Z"; + +// Windows +// - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. +// - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, +// which clicking will set the boolean to false when clicked. +// - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. +// Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). +// - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting +// anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! +// [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions +// such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding +// BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] +// - Note that the bottom of window stack always contains a window called "Debug". +Begin :: (name: *u8, p_open: *bool = null, flags: WindowFlags = .None) -> bool #foreign imgui "?Begin@ImGui@@YA_NPEBDPEA_NH@Z"; +End :: () -> void #foreign imgui "?End@ImGui@@YAXXZ"; + +// Child Windows +// - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. +// - Before 1.90 (November 2023), the "ImGuiChildFlags child_flags = 0" parameter was "bool border = false". +// This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Borders == true. +// Consider updating your old code: +// BeginChild("Name", size, false) -> Begin("Name", size, 0); or Begin("Name", size, ImGuiChildFlags_None); +// BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Borders); +// - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)): +// == 0.0f: use remaining parent window size for this axis. +// > 0.0f: use specified size for this axis. +// < 0.0f: right/bottom-align to specified distance from available content boundaries. +// - Specifying ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY makes the sizing automatic based on child contents. +// Combining both ImGuiChildFlags_AutoResizeX _and_ ImGuiChildFlags_AutoResizeY defeats purpose of a scrolling region and is NOT recommended. +// - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting +// anything to the window. Always call a matching EndChild() for each BeginChild() call, regardless of its return value. +// [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions +// such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding +// BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] +BeginChild :: (str_id: *u8, size: *ImVec2, child_flags: ChildFlags = .None, window_flags: WindowFlags = .None) -> bool #foreign imgui "?BeginChild@ImGui@@YA_NPEBDAEBUImVec2@@HH@Z"; +BeginChild :: (str_id: *u8, size: ImVec2 = ImVec2.{0, 0}, child_flags: ChildFlags = .None, window_flags: WindowFlags = .None) -> bool #no_context { + return BeginChild(str_id, *size, child_flags, window_flags); +} +BeginChild :: (id: ID, size: *ImVec2, child_flags: ChildFlags = .None, window_flags: WindowFlags = .None) -> bool #foreign imgui "?BeginChild@ImGui@@YA_NIAEBUImVec2@@HH@Z"; +BeginChild :: (id: ID, size: ImVec2 = ImVec2.{0, 0}, child_flags: ChildFlags = .None, window_flags: WindowFlags = .None) -> bool #no_context { + return BeginChild(id, *size, child_flags, window_flags); +} +EndChild :: () -> void #foreign imgui "?EndChild@ImGui@@YAXXZ"; + +// Windows Utilities +// - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. +IsWindowAppearing :: () -> bool #foreign imgui "?IsWindowAppearing@ImGui@@YA_NXZ"; +IsWindowCollapsed :: () -> bool #foreign imgui "?IsWindowCollapsed@ImGui@@YA_NXZ"; +IsWindowFocused :: (flags: FocusedFlags = .None) -> bool #foreign imgui "?IsWindowFocused@ImGui@@YA_NH@Z"; +IsWindowHovered :: (flags: HoveredFlags = .None) -> bool #foreign imgui "?IsWindowHovered@ImGui@@YA_NH@Z"; +GetWindowDrawList :: () -> *ImDrawList #foreign imgui "?GetWindowDrawList@ImGui@@YAPEAUImDrawList@@XZ"; +GetWindowDpiScale :: () -> float #foreign imgui "?GetWindowDpiScale@ImGui@@YAMXZ"; +GetWindowPos :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetWindowPos@ImGui@@YA?AUImVec2@@XZ"; +GetWindowSize :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetWindowSize@ImGui@@YA?AUImVec2@@XZ"; +GetWindowWidth :: () -> float #foreign imgui "?GetWindowWidth@ImGui@@YAMXZ"; +GetWindowHeight :: () -> float #foreign imgui "?GetWindowHeight@ImGui@@YAMXZ"; +GetWindowViewport :: () -> *Viewport #foreign imgui "?GetWindowViewport@ImGui@@YAPEAUImGuiViewport@@XZ"; + +// Window manipulation +// - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). +SetNextWindowPos :: (pos: *ImVec2, cond: Cond = .None, pivot: *ImVec2) -> void #foreign imgui "?SetNextWindowPos@ImGui@@YAXAEBUImVec2@@H0@Z"; +SetNextWindowPos :: (pos: ImVec2, cond: Cond = .None, pivot: ImVec2 = ImVec2.{0, 0}) #no_context { + SetNextWindowPos(*pos, cond, *pivot); +} +SetNextWindowSize :: (size: *ImVec2, cond: Cond = .None) -> void #foreign imgui "?SetNextWindowSize@ImGui@@YAXAEBUImVec2@@H@Z"; +SetNextWindowSize :: (size: ImVec2, cond: Cond = .None) #no_context { + SetNextWindowSize(*size, cond); +} +SetNextWindowSizeConstraints :: (size_min: *ImVec2, size_max: *ImVec2, custom_callback: SizeCallback = null, custom_callback_data: *void = null) -> void #foreign imgui "?SetNextWindowSizeConstraints@ImGui@@YAXAEBUImVec2@@0P6AXPEAUImGuiSizeCallbackData@@@ZPEAX@Z"; +SetNextWindowSizeConstraints :: (size_min: ImVec2, size_max: ImVec2, custom_callback: SizeCallback = null, custom_callback_data: *void = null) #no_context { + SetNextWindowSizeConstraints(*size_min, *size_max, custom_callback, custom_callback_data); +} +SetNextWindowContentSize :: (size: *ImVec2) -> void #foreign imgui "?SetNextWindowContentSize@ImGui@@YAXAEBUImVec2@@@Z"; +SetNextWindowContentSize :: (size: ImVec2) #no_context { + SetNextWindowContentSize(*size); +} +SetNextWindowCollapsed :: (collapsed: bool, cond: Cond = .None) -> void #foreign imgui "?SetNextWindowCollapsed@ImGui@@YAX_NH@Z"; +SetNextWindowFocus :: () -> void #foreign imgui "?SetNextWindowFocus@ImGui@@YAXXZ"; +SetNextWindowScroll :: (scroll: *ImVec2) -> void #foreign imgui "?SetNextWindowScroll@ImGui@@YAXAEBUImVec2@@@Z"; +SetNextWindowScroll :: (scroll: ImVec2) #no_context { + SetNextWindowScroll(*scroll); +} +SetNextWindowBgAlpha :: (alpha: float) -> void #foreign imgui "?SetNextWindowBgAlpha@ImGui@@YAXM@Z"; +SetNextWindowViewport :: (viewport_id: ID) -> void #foreign imgui "?SetNextWindowViewport@ImGui@@YAXI@Z"; +SetWindowPos :: (pos: *ImVec2, cond: Cond = .None) -> void #foreign imgui "?SetWindowPos@ImGui@@YAXAEBUImVec2@@H@Z"; +SetWindowPos :: (pos: ImVec2, cond: Cond = .None) #no_context { + SetWindowPos(*pos, cond); +} +SetWindowSize :: (size: *ImVec2, cond: Cond = .None) -> void #foreign imgui "?SetWindowSize@ImGui@@YAXAEBUImVec2@@H@Z"; +SetWindowSize :: (size: ImVec2, cond: Cond = .None) #no_context { + SetWindowSize(*size, cond); +} +SetWindowCollapsed :: (collapsed: bool, cond: Cond = .None) -> void #foreign imgui "?SetWindowCollapsed@ImGui@@YAX_NH@Z"; +SetWindowFocus :: () -> void #foreign imgui "?SetWindowFocus@ImGui@@YAXXZ"; +SetWindowPos :: (name: *u8, pos: *ImVec2, cond: Cond = .None) -> void #foreign imgui "?SetWindowPos@ImGui@@YAXPEBDAEBUImVec2@@H@Z"; +SetWindowPos :: (name: *u8, pos: ImVec2, cond: Cond = .None) #no_context { + SetWindowPos(name, *pos, cond); +} +SetWindowSize :: (name: *u8, size: *ImVec2, cond: Cond = .None) -> void #foreign imgui "?SetWindowSize@ImGui@@YAXPEBDAEBUImVec2@@H@Z"; +SetWindowSize :: (name: *u8, size: ImVec2, cond: Cond = .None) #no_context { + SetWindowSize(name, *size, cond); +} +SetWindowCollapsed :: (name: *u8, collapsed: bool, cond: Cond = .None) -> void #foreign imgui "?SetWindowCollapsed@ImGui@@YAXPEBD_NH@Z"; +SetWindowFocus :: (name: *u8) -> void #foreign imgui "?SetWindowFocus@ImGui@@YAXPEBD@Z"; + +// Windows Scrolling +// - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). +// - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY(). +GetScrollX :: () -> float #foreign imgui "?GetScrollX@ImGui@@YAMXZ"; +GetScrollY :: () -> float #foreign imgui "?GetScrollY@ImGui@@YAMXZ"; +SetScrollX :: (scroll_x: float) -> void #foreign imgui "?SetScrollX@ImGui@@YAXM@Z"; +SetScrollY :: (scroll_y: float) -> void #foreign imgui "?SetScrollY@ImGui@@YAXM@Z"; +GetScrollMaxX :: () -> float #foreign imgui "?GetScrollMaxX@ImGui@@YAMXZ"; +GetScrollMaxY :: () -> float #foreign imgui "?GetScrollMaxY@ImGui@@YAMXZ"; +SetScrollHereX :: (center_x_ratio: float = 0.5) -> void #foreign imgui "?SetScrollHereX@ImGui@@YAXM@Z"; +SetScrollHereY :: (center_y_ratio: float = 0.5) -> void #foreign imgui "?SetScrollHereY@ImGui@@YAXM@Z"; +SetScrollFromPosX :: (local_x: float, center_x_ratio: float = 0.5) -> void #foreign imgui "?SetScrollFromPosX@ImGui@@YAXMM@Z"; +SetScrollFromPosY :: (local_y: float, center_y_ratio: float = 0.5) -> void #foreign imgui "?SetScrollFromPosY@ImGui@@YAXMM@Z"; + +// Parameters stacks (font) +// - PushFont(font, 0.0f) // Change font and keep current size +// - PushFont(NULL, 20.0f) // Keep font and change current size +// - PushFont(font, 20.0f) // Change font and set size to 20.0f +// - PushFont(font, style.FontSizeBase * 2.0f) // Change font and set size to be twice bigger than current size. +// - PushFont(font, font->LegacySize) // Change font and set size to size passed to AddFontXXX() function. Same as pre-1.92 behavior. +// *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. +// - In 1.92 we have REMOVED the single parameter version of PushFont() because it seems like the easiest way to provide an error-proof transition. +// - PushFont(font) before 1.92 = PushFont(font, font->LegacySize) after 1.92 // Use default font size as passed to AddFontXXX() function. +// *IMPORTANT* global scale factors are applied over the provided size. +// - Global scale factors are: 'style.FontScaleMain', 'style.FontScaleDpi' and maybe more. +// - If you want to apply a factor to the _current_ font size: +// - CORRECT: PushFont(NULL, style.FontSizeBase) // use current unscaled size == does nothing +// - CORRECT: PushFont(NULL, style.FontSizeBase * 2.0f) // use current unscaled size x2 == make text twice bigger +// - INCORRECT: PushFont(NULL, GetFontSize()) // INCORRECT! using size after global factors already applied == GLOBAL SCALING FACTORS WILL APPLY TWICE! +// - INCORRECT: PushFont(NULL, GetFontSize() * 2.0f) // INCORRECT! using size after global factors already applied == GLOBAL SCALING FACTORS WILL APPLY TWICE! +PushFont :: (font: *ImFont, font_size_base_unscaled: float) -> void #foreign imgui "?PushFont@ImGui@@YAXPEAUImFont@@M@Z"; +PopFont :: () -> void #foreign imgui "?PopFont@ImGui@@YAXXZ"; +GetFont :: () -> *ImFont #foreign imgui "?GetFont@ImGui@@YAPEAUImFont@@XZ"; +GetFontSize :: () -> float #foreign imgui "?GetFontSize@ImGui@@YAMXZ"; +GetFontBaked :: () -> *ImFontBaked #foreign imgui "?GetFontBaked@ImGui@@YAPEAUImFontBaked@@XZ"; + +// Parameters stacks (shared) +PushStyleColor :: (idx: Col, col: ImU32) -> void #foreign imgui "?PushStyleColor@ImGui@@YAXHI@Z"; +PushStyleColor :: (idx: Col, col: *ImVec4) -> void #foreign imgui "?PushStyleColor@ImGui@@YAXHAEBUImVec4@@@Z"; +PushStyleColor :: (idx: Col, col: ImVec4) #no_context { + PushStyleColor(idx, *col); +} +PopStyleColor :: (count: s32 = 1) -> void #foreign imgui "?PopStyleColor@ImGui@@YAXH@Z"; +PushStyleVar :: (idx: StyleVar, val: float) -> void #foreign imgui "?PushStyleVar@ImGui@@YAXHM@Z"; +PushStyleVar :: (idx: StyleVar, val: *ImVec2) -> void #foreign imgui "?PushStyleVar@ImGui@@YAXHAEBUImVec2@@@Z"; +PushStyleVar :: (idx: StyleVar, val: ImVec2) #no_context { + PushStyleVar(idx, *val); +} +PushStyleVarX :: (idx: StyleVar, val_x: float) -> void #foreign imgui "?PushStyleVarX@ImGui@@YAXHM@Z"; +PushStyleVarY :: (idx: StyleVar, val_y: float) -> void #foreign imgui "?PushStyleVarY@ImGui@@YAXHM@Z"; +PopStyleVar :: (count: s32 = 1) -> void #foreign imgui "?PopStyleVar@ImGui@@YAXH@Z"; +PushItemFlag :: (option: ItemFlags, enabled: bool) -> void #foreign imgui "?PushItemFlag@ImGui@@YAXH_N@Z"; +PopItemFlag :: () -> void #foreign imgui "?PopItemFlag@ImGui@@YAXXZ"; + +// Parameters stacks (current window) +PushItemWidth :: (item_width: float) -> void #foreign imgui "?PushItemWidth@ImGui@@YAXM@Z"; +PopItemWidth :: () -> void #foreign imgui "?PopItemWidth@ImGui@@YAXXZ"; +SetNextItemWidth :: (item_width: float) -> void #foreign imgui "?SetNextItemWidth@ImGui@@YAXM@Z"; +CalcItemWidth :: () -> float #foreign imgui "?CalcItemWidth@ImGui@@YAMXZ"; +PushTextWrapPos :: (wrap_local_pos_x: float = 0.0) -> void #foreign imgui "?PushTextWrapPos@ImGui@@YAXM@Z"; +PopTextWrapPos :: () -> void #foreign imgui "?PopTextWrapPos@ImGui@@YAXXZ"; + +// Style read access +// - Use the ShowStyleEditor() function to interactively see/edit the colors. +GetFontTexUvWhitePixel :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetFontTexUvWhitePixel@ImGui@@YA?AUImVec2@@XZ"; +GetColorU32 :: (idx: Col, alpha_mul: float = 1.0) -> ImU32 #foreign imgui "?GetColorU32@ImGui@@YAIHM@Z"; +GetColorU32 :: (col: *ImVec4) -> ImU32 #foreign imgui "?GetColorU32@ImGui@@YAIAEBUImVec4@@@Z"; +GetColorU32 :: (col: ImVec4) -> ImU32 #no_context { + return GetColorU32(*col); +} +GetColorU32 :: (col: ImU32, alpha_mul: float = 1.0) -> ImU32 #foreign imgui "?GetColorU32@ImGui@@YAIIM@Z"; +GetStyleColorVec4 :: (idx: Col) -> *ImVec4 #foreign imgui "?GetStyleColorVec4@ImGui@@YAAEBUImVec4@@H@Z"; + +// Layout cursor positioning +// - By "cursor" we mean the current output position. +// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. +// - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. +// - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). +// - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: +// - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward. +// - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), PushTextWrapPos() +// - Window-local coordinates: GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax() --> all obsoleted. YOU DON'T NEED THEM. +// - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. Try not to use it. +GetCursorScreenPos :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetCursorScreenPos@ImGui@@YA?AUImVec2@@XZ"; +SetCursorScreenPos :: (pos: *ImVec2) -> void #foreign imgui "?SetCursorScreenPos@ImGui@@YAXAEBUImVec2@@@Z"; +SetCursorScreenPos :: (pos: ImVec2) #no_context { + SetCursorScreenPos(*pos); +} +GetContentRegionAvail :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetContentRegionAvail@ImGui@@YA?AUImVec2@@XZ"; +GetCursorPos :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetCursorPos@ImGui@@YA?AUImVec2@@XZ"; +GetCursorPosX :: () -> float #foreign imgui "?GetCursorPosX@ImGui@@YAMXZ"; +GetCursorPosY :: () -> float #foreign imgui "?GetCursorPosY@ImGui@@YAMXZ"; +SetCursorPos :: (local_pos: *ImVec2) -> void #foreign imgui "?SetCursorPos@ImGui@@YAXAEBUImVec2@@@Z"; +SetCursorPos :: (local_pos: ImVec2) #no_context { + SetCursorPos(*local_pos); +} +SetCursorPosX :: (local_x: float) -> void #foreign imgui "?SetCursorPosX@ImGui@@YAXM@Z"; +SetCursorPosY :: (local_y: float) -> void #foreign imgui "?SetCursorPosY@ImGui@@YAXM@Z"; +GetCursorStartPos :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetCursorStartPos@ImGui@@YA?AUImVec2@@XZ"; + +// Other layout functions +Separator :: () -> void #foreign imgui "?Separator@ImGui@@YAXXZ"; +SameLine :: (offset_from_start_x: float = 0.0, spacing: float = -1.0) -> void #foreign imgui "?SameLine@ImGui@@YAXMM@Z"; +NewLine :: () -> void #foreign imgui "?NewLine@ImGui@@YAXXZ"; +Spacing :: () -> void #foreign imgui "?Spacing@ImGui@@YAXXZ"; +Dummy :: (size: *ImVec2) -> void #foreign imgui "?Dummy@ImGui@@YAXAEBUImVec2@@@Z"; +Dummy :: (size: ImVec2) #no_context { + Dummy(*size); +} +Indent :: (indent_w: float = 0.0) -> void #foreign imgui "?Indent@ImGui@@YAXM@Z"; +Unindent :: (indent_w: float = 0.0) -> void #foreign imgui "?Unindent@ImGui@@YAXM@Z"; +BeginGroup :: () -> void #foreign imgui "?BeginGroup@ImGui@@YAXXZ"; +EndGroup :: () -> void #foreign imgui "?EndGroup@ImGui@@YAXXZ"; +AlignTextToFramePadding :: () -> void #foreign imgui "?AlignTextToFramePadding@ImGui@@YAXXZ"; +GetTextLineHeight :: () -> float #foreign imgui "?GetTextLineHeight@ImGui@@YAMXZ"; +GetTextLineHeightWithSpacing :: () -> float #foreign imgui "?GetTextLineHeightWithSpacing@ImGui@@YAMXZ"; +GetFrameHeight :: () -> float #foreign imgui "?GetFrameHeight@ImGui@@YAMXZ"; +GetFrameHeightWithSpacing :: () -> float #foreign imgui "?GetFrameHeightWithSpacing@ImGui@@YAMXZ"; + +// ID stack/scopes +// Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui. +// - Those questions are answered and impacted by understanding of the ID stack system: +// - "Q: Why is my widget not reacting when I click on it?" +// - "Q: How can I have widgets with an empty label?" +// - "Q: How can I have multiple widgets with the same label?" +// - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely +// want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. +// - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. +// - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID, +// whereas "str_id" denote a string that is only used as an ID and not normally displayed. +PushID :: (str_id: *u8) -> void #foreign imgui "?PushID@ImGui@@YAXPEBD@Z"; +PushID :: (str_id_begin: *u8, str_id_end: *u8) -> void #foreign imgui "?PushID@ImGui@@YAXPEBD0@Z"; +PushID :: (str_id: string) #no_context { + PushID(str_id.data, str_id.data + str_id.count); +} +PushID :: (ptr_id: *void) -> void #foreign imgui "?PushID@ImGui@@YAXPEBX@Z"; +PushID :: (int_id: s32) -> void #foreign imgui "?PushID@ImGui@@YAXH@Z"; +PopID :: () -> void #foreign imgui "?PopID@ImGui@@YAXXZ"; +GetID :: (str_id: *u8) -> ID #foreign imgui "?GetID@ImGui@@YAIPEBD@Z"; +GetID :: (str_id_begin: *u8, str_id_end: *u8) -> ID #foreign imgui "?GetID@ImGui@@YAIPEBD0@Z"; +GetID :: (str_id: string) -> ID #no_context { + return GetID(str_id.data, str_id.data + str_id.count); +} +GetID :: (ptr_id: *void) -> ID #foreign imgui "?GetID@ImGui@@YAIPEBX@Z"; +GetID :: (int_id: s32) -> ID #foreign imgui "?GetID@ImGui@@YAIH@Z"; + +// Widgets: Text +TextUnformatted :: (text: *u8, text_end: *u8 = null) -> void #foreign imgui "?TextUnformatted@ImGui@@YAXPEBD0@Z"; +TextUnformatted :: (text: string) #no_context { + TextUnformatted(text.data, text.data + text.count); +} +Text_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?Text@ImGui@@YAXPEBDZZ"; +Text :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + Text_CFormat("%s", formatted_text.data); +} @PrintLike + +TextColored_CFormat :: (col: *ImVec4, fmt: *u8, __args: ..Any) -> void #foreign imgui "?TextColored@ImGui@@YAXAEBUImVec4@@PEBDZZ"; +TextColored :: (col: ImVec4, fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + TextColored_CFormat(*col, "%s", formatted_text.data); +} @PrintLike + +TextDisabled_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?TextDisabled@ImGui@@YAXPEBDZZ"; +TextDisabled :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + TextDisabled_CFormat("%s", formatted_text.data); +} @PrintLike + +TextWrapped_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?TextWrapped@ImGui@@YAXPEBDZZ"; +TextWrapped :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + TextWrapped_CFormat("%s", formatted_text.data); +} @PrintLike + +LabelText_CFormat :: (label: *u8, fmt: *u8, __args: ..Any) -> void #foreign imgui "?LabelText@ImGui@@YAXPEBD0ZZ"; +LabelText :: (label: *u8, fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + LabelText_CFormat(label, "%s", formatted_text.data); +} @PrintLike + +BulletText_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?BulletText@ImGui@@YAXPEBDZZ"; +BulletText :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + BulletText_CFormat("%s", formatted_text.data); +} @PrintLike + +SeparatorText :: (label: *u8) -> void #foreign imgui "?SeparatorText@ImGui@@YAXPEBD@Z"; + +// Widgets: Main +// - Most widgets return true when the value has been changed or when pressed/selected +// - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. +Button :: (label: *u8, size: *ImVec2) -> bool #foreign imgui "?Button@ImGui@@YA_NPEBDAEBUImVec2@@@Z"; +Button :: (label: *u8, size: ImVec2 = ImVec2.{0, 0}) -> bool #no_context { + return Button(label, *size); +} +SmallButton :: (label: *u8) -> bool #foreign imgui "?SmallButton@ImGui@@YA_NPEBD@Z"; +InvisibleButton :: (str_id: *u8, size: *ImVec2, flags: ButtonFlags = .None) -> bool #foreign imgui "?InvisibleButton@ImGui@@YA_NPEBDAEBUImVec2@@H@Z"; +InvisibleButton :: (str_id: *u8, size: ImVec2, flags: ButtonFlags = .None) -> bool #no_context { + return InvisibleButton(str_id, *size, flags); +} +ArrowButton :: (str_id: *u8, dir: Dir) -> bool #foreign imgui "?ArrowButton@ImGui@@YA_NPEBDW4ImGuiDir@@@Z"; +Checkbox :: (label: *u8, v: *bool) -> bool #foreign imgui "?Checkbox@ImGui@@YA_NPEBDPEA_N@Z"; +CheckboxFlags :: (label: *u8, flags: *s32, flags_value: s32) -> bool #foreign imgui "?CheckboxFlags@ImGui@@YA_NPEBDPEAHH@Z"; +CheckboxFlags :: (label: *u8, flags: *u32, flags_value: u32) -> bool #foreign imgui "?CheckboxFlags@ImGui@@YA_NPEBDPEAII@Z"; +RadioButton :: (label: *u8, active: bool) -> bool #foreign imgui "?RadioButton@ImGui@@YA_NPEBD_N@Z"; +RadioButton :: (label: *u8, v: *s32, v_button: s32) -> bool #foreign imgui "?RadioButton@ImGui@@YA_NPEBDPEAHH@Z"; +ProgressBar :: (fraction: float, size_arg: *ImVec2, overlay: *u8 = null) -> void #foreign imgui "?ProgressBar@ImGui@@YAXMAEBUImVec2@@PEBD@Z"; +ProgressBar :: (fraction: float, size_arg: ImVec2 = ImVec2.{-FLOAT32_MIN, 0}, overlay: *u8 = null) #no_context { + ProgressBar(fraction, *size_arg, overlay); +} +Bullet :: () -> void #foreign imgui "?Bullet@ImGui@@YAXXZ"; +TextLink :: (label: *u8) -> bool #foreign imgui "?TextLink@ImGui@@YA_NPEBD@Z"; +TextLinkOpenURL :: (label: *u8, url: *u8 = null) -> bool #foreign imgui "?TextLinkOpenURL@ImGui@@YA_NPEBD0@Z"; + +// Widgets: Images +// - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples +// - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. +// - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. +// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. +// - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by the ImageWithBg() function. +Image :: (tex_ref: ImTextureRef, image_size: *ImVec2, uv0: *ImVec2, uv1: *ImVec2) -> void #foreign imgui "?Image@ImGui@@YAXUImTextureRef@@AEBUImVec2@@11@Z"; +Image :: (tex_ref: ImTextureRef, image_size: ImVec2, uv0: ImVec2 = ImVec2.{0, 0}, uv1: ImVec2 = ImVec2.{1, 1}) #no_context { + Image(tex_ref, *image_size, *uv0, *uv1); +} +ImageWithBg :: (tex_ref: ImTextureRef, image_size: *ImVec2, uv0: *ImVec2, uv1: *ImVec2, bg_col: *ImVec4, tint_col: *ImVec4) -> void #foreign imgui "?ImageWithBg@ImGui@@YAXUImTextureRef@@AEBUImVec2@@11AEBUImVec4@@2@Z"; +ImageWithBg :: (tex_ref: ImTextureRef, image_size: ImVec2, uv0: ImVec2 = ImVec2.{0, 0}, uv1: ImVec2 = ImVec2.{1, 1}, bg_col: ImVec4 = ImVec4.{0, 0, 0, 0}, tint_col: ImVec4 = ImVec4.{1, 1, 1, 1}) #no_context { + ImageWithBg(tex_ref, *image_size, *uv0, *uv1, *bg_col, *tint_col); +} +ImageButton :: (str_id: *u8, tex_ref: ImTextureRef, image_size: *ImVec2, uv0: *ImVec2, uv1: *ImVec2, bg_col: *ImVec4, tint_col: *ImVec4) -> bool #foreign imgui "?ImageButton@ImGui@@YA_NPEBDUImTextureRef@@AEBUImVec2@@22AEBUImVec4@@3@Z"; +ImageButton :: (str_id: *u8, tex_ref: ImTextureRef, image_size: ImVec2, uv0: ImVec2 = ImVec2.{0, 0}, uv1: ImVec2 = ImVec2.{1, 1}, bg_col: ImVec4 = ImVec4.{0, 0, 0, 0}, tint_col: ImVec4 = ImVec4.{1, 1, 1, 1}) -> bool #no_context { + return ImageButton(str_id, tex_ref, *image_size, *uv0, *uv1, *bg_col, *tint_col); +} + +// Widgets: Combo Box (Dropdown) +// - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. +// - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. +BeginCombo :: (label: *u8, preview_value: *u8, flags: ComboFlags = .None) -> bool #foreign imgui "?BeginCombo@ImGui@@YA_NPEBD0H@Z"; +EndCombo :: () -> void #foreign imgui "?EndCombo@ImGui@@YAXXZ"; +Combo :: (label: *u8, current_item: *s32, items: **u8, items_count: s32, popup_max_height_in_items: s32 = -1) -> bool #foreign imgui "?Combo@ImGui@@YA_NPEBDPEAHQEBQEBDHH@Z"; +Combo :: (label: *u8, current_item: *s32, items_separated_by_zeros: *u8, popup_max_height_in_items: s32 = -1) -> bool #foreign imgui "?Combo@ImGui@@YA_NPEBDPEAH0H@Z"; +Combo :: (label: *u8, current_item: *s32, getter: #type (user_data: *void, idx: s32) -> *u8 #c_call, user_data: *void, items_count: s32, popup_max_height_in_items: s32 = -1) -> bool #foreign imgui "?Combo@ImGui@@YA_NPEBDPEAHP6APEBDPEAXH@Z2HH@Z"; + +// Widgets: Drag Sliders +// - Ctrl+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. +// - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every function, note that a 'float v[X]' function argument is the same as 'float* v', +// the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x +// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. +// - Format string may also be set to NULL or use the default format ("%f" or "%d"). +// - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For keyboard/gamepad navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). +// - Use v_min < v_max to clamp edits to given limits. Note that Ctrl+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. +// - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. +// - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. +// - Legacy: Pre-1.78 there are DragXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. +// If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 +DragFloat :: (label: *u8, v: *float, v_speed: float = 1.0, v_min: float = 0.0, v_max: float = 0.0, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?DragFloat@ImGui@@YA_NPEBDPEAMMMM0H@Z"; +DragFloat2 :: (label: *u8, v: *[2] float, v_speed: float = 1.0, v_min: float = 0.0, v_max: float = 0.0, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?DragFloat2@ImGui@@YA_NPEBDQEAMMMM0H@Z"; +DragFloat3 :: (label: *u8, v: *[3] float, v_speed: float = 1.0, v_min: float = 0.0, v_max: float = 0.0, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?DragFloat3@ImGui@@YA_NPEBDQEAMMMM0H@Z"; +DragFloat4 :: (label: *u8, v: *[4] float, v_speed: float = 1.0, v_min: float = 0.0, v_max: float = 0.0, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?DragFloat4@ImGui@@YA_NPEBDQEAMMMM0H@Z"; +DragFloatRange2 :: (label: *u8, v_current_min: *float, v_current_max: *float, v_speed: float = 1.0, v_min: float = 0.0, v_max: float = 0.0, format: *u8 = "%.3f", format_max: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?DragFloatRange2@ImGui@@YA_NPEBDPEAM1MMM00H@Z"; +DragInt :: (label: *u8, v: *s32, v_speed: float = 1.0, v_min: s32 = 0, v_max: s32 = 0, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?DragInt@ImGui@@YA_NPEBDPEAHMHH0H@Z"; +DragInt2 :: (label: *u8, v: *[2] s32, v_speed: float = 1.0, v_min: s32 = 0, v_max: s32 = 0, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?DragInt2@ImGui@@YA_NPEBDQEAHMHH0H@Z"; +DragInt3 :: (label: *u8, v: *[3] s32, v_speed: float = 1.0, v_min: s32 = 0, v_max: s32 = 0, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?DragInt3@ImGui@@YA_NPEBDQEAHMHH0H@Z"; +DragInt4 :: (label: *u8, v: *[4] s32, v_speed: float = 1.0, v_min: s32 = 0, v_max: s32 = 0, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?DragInt4@ImGui@@YA_NPEBDQEAHMHH0H@Z"; +DragIntRange2 :: (label: *u8, v_current_min: *s32, v_current_max: *s32, v_speed: float = 1.0, v_min: s32 = 0, v_max: s32 = 0, format: *u8 = "%d", format_max: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?DragIntRange2@ImGui@@YA_NPEBDPEAH1MHH00H@Z"; +DragScalar :: (label: *u8, data_type: DataType, p_data: *void, v_speed: float = 1.0, p_min: *void = null, p_max: *void = null, format: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?DragScalar@ImGui@@YA_NPEBDHPEAXMPEBX20H@Z"; +DragScalarN :: (label: *u8, data_type: DataType, p_data: *void, components: s32, v_speed: float = 1.0, p_min: *void = null, p_max: *void = null, format: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?DragScalarN@ImGui@@YA_NPEBDHPEAXHMPEBX20H@Z"; + +// Widgets: Regular Sliders +// - Ctrl+Click on any slider to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. +// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. +// - Format string may also be set to NULL or use the default format ("%f" or "%d"). +// - Legacy: Pre-1.78 there are SliderXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. +// If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 +SliderFloat :: (label: *u8, v: *float, v_min: float, v_max: float, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderFloat@ImGui@@YA_NPEBDPEAMMM0H@Z"; +SliderFloat2 :: (label: *u8, v: *[2] float, v_min: float, v_max: float, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderFloat2@ImGui@@YA_NPEBDQEAMMM0H@Z"; +SliderFloat3 :: (label: *u8, v: *[3] float, v_min: float, v_max: float, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderFloat3@ImGui@@YA_NPEBDQEAMMM0H@Z"; +SliderFloat4 :: (label: *u8, v: *[4] float, v_min: float, v_max: float, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderFloat4@ImGui@@YA_NPEBDQEAMMM0H@Z"; +SliderAngle :: (label: *u8, v_rad: *float, v_degrees_min: float = -360.0, v_degrees_max: float = +360.0, format: *u8 = "%.0f deg", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderAngle@ImGui@@YA_NPEBDPEAMMM0H@Z"; +SliderInt :: (label: *u8, v: *s32, v_min: s32, v_max: s32, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderInt@ImGui@@YA_NPEBDPEAHHH0H@Z"; +SliderInt2 :: (label: *u8, v: *[2] s32, v_min: s32, v_max: s32, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderInt2@ImGui@@YA_NPEBDQEAHHH0H@Z"; +SliderInt3 :: (label: *u8, v: *[3] s32, v_min: s32, v_max: s32, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderInt3@ImGui@@YA_NPEBDQEAHHH0H@Z"; +SliderInt4 :: (label: *u8, v: *[4] s32, v_min: s32, v_max: s32, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?SliderInt4@ImGui@@YA_NPEBDQEAHHH0H@Z"; +SliderScalar :: (label: *u8, data_type: DataType, p_data: *void, p_min: *void, p_max: *void, format: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?SliderScalar@ImGui@@YA_NPEBDHPEAXPEBX20H@Z"; +SliderScalarN :: (label: *u8, data_type: DataType, p_data: *void, components: s32, p_min: *void, p_max: *void, format: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?SliderScalarN@ImGui@@YA_NPEBDHPEAXHPEBX20H@Z"; +VSliderFloat :: (label: *u8, size: *ImVec2, v: *float, v_min: float, v_max: float, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #foreign imgui "?VSliderFloat@ImGui@@YA_NPEBDAEBUImVec2@@PEAMMM0H@Z"; +VSliderFloat :: (label: *u8, size: ImVec2, v: *float, v_min: float, v_max: float, format: *u8 = "%.3f", flags: SliderFlags = .None) -> bool #no_context { + return VSliderFloat(label, *size, v, v_min, v_max, format, flags); +} +VSliderInt :: (label: *u8, size: *ImVec2, v: *s32, v_min: s32, v_max: s32, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #foreign imgui "?VSliderInt@ImGui@@YA_NPEBDAEBUImVec2@@PEAHHH0H@Z"; +VSliderInt :: (label: *u8, size: ImVec2, v: *s32, v_min: s32, v_max: s32, format: *u8 = "%d", flags: SliderFlags = .None) -> bool #no_context { + return VSliderInt(label, *size, v, v_min, v_max, format, flags); +} +VSliderScalar :: (label: *u8, size: *ImVec2, data_type: DataType, p_data: *void, p_min: *void, p_max: *void, format: *u8 = null, flags: SliderFlags = .None) -> bool #foreign imgui "?VSliderScalar@ImGui@@YA_NPEBDAEBUImVec2@@HPEAXPEBX30H@Z"; +VSliderScalar :: (label: *u8, size: ImVec2, data_type: DataType, p_data: *void, p_min: *void, p_max: *void, format: *u8 = null, flags: SliderFlags = .None) -> bool #no_context { + return VSliderScalar(label, *size, data_type, p_data, p_min, p_max, format, flags); +} + +// Widgets: Input with Keyboard +// - If you want to use InputText() with std::string or any custom dynamic string type, use the wrapper in misc/cpp/imgui_stdlib.h/.cpp! +// - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. +InputText :: (label: *u8, buf: *u8, buf_size: u64, flags: InputTextFlags = .None, callback: InputTextCallback = null, user_data: *void = null) -> bool #foreign imgui "?InputText@ImGui@@YA_NPEBDPEAD_KHP6AHPEAUImGuiInputTextCallbackData@@@ZPEAX@Z"; +InputTextMultiline :: (label: *u8, buf: *u8, buf_size: u64, size: *ImVec2, flags: InputTextFlags = .None, callback: InputTextCallback = null, user_data: *void = null) -> bool #foreign imgui "?InputTextMultiline@ImGui@@YA_NPEBDPEAD_KAEBUImVec2@@HP6AHPEAUImGuiInputTextCallbackData@@@ZPEAX@Z"; +InputTextMultiline :: (label: *u8, buf: *u8, buf_size: u64, size: ImVec2 = ImVec2.{0, 0}, flags: InputTextFlags = .None, callback: InputTextCallback = null, user_data: *void = null) -> bool #no_context { + return InputTextMultiline(label, buf, buf_size, *size, flags, callback, user_data); +} +InputTextWithHint :: (label: *u8, hint: *u8, buf: *u8, buf_size: u64, flags: InputTextFlags = .None, callback: InputTextCallback = null, user_data: *void = null) -> bool #foreign imgui "?InputTextWithHint@ImGui@@YA_NPEBD0PEAD_KHP6AHPEAUImGuiInputTextCallbackData@@@ZPEAX@Z"; +InputFloat :: (label: *u8, v: *float, step: float = 0.0, step_fast: float = 0.0, format: *u8 = "%.3f", flags: InputTextFlags = .None) -> bool #foreign imgui "?InputFloat@ImGui@@YA_NPEBDPEAMMM0H@Z"; +InputFloat2 :: (label: *u8, v: *[2] float, format: *u8 = "%.3f", flags: InputTextFlags = .None) -> bool #foreign imgui "?InputFloat2@ImGui@@YA_NPEBDQEAM0H@Z"; +InputFloat3 :: (label: *u8, v: *[3] float, format: *u8 = "%.3f", flags: InputTextFlags = .None) -> bool #foreign imgui "?InputFloat3@ImGui@@YA_NPEBDQEAM0H@Z"; +InputFloat4 :: (label: *u8, v: *[4] float, format: *u8 = "%.3f", flags: InputTextFlags = .None) -> bool #foreign imgui "?InputFloat4@ImGui@@YA_NPEBDQEAM0H@Z"; +InputInt :: (label: *u8, v: *s32, step: s32 = 1, step_fast: s32 = 100, flags: InputTextFlags = .None) -> bool #foreign imgui "?InputInt@ImGui@@YA_NPEBDPEAHHHH@Z"; +InputInt2 :: (label: *u8, v: *[2] s32, flags: InputTextFlags = .None) -> bool #foreign imgui "?InputInt2@ImGui@@YA_NPEBDQEAHH@Z"; +InputInt3 :: (label: *u8, v: *[3] s32, flags: InputTextFlags = .None) -> bool #foreign imgui "?InputInt3@ImGui@@YA_NPEBDQEAHH@Z"; +InputInt4 :: (label: *u8, v: *[4] s32, flags: InputTextFlags = .None) -> bool #foreign imgui "?InputInt4@ImGui@@YA_NPEBDQEAHH@Z"; +InputDouble :: (label: *u8, v: *float64, step: float64 = 0.0, step_fast: float64 = 0.0, format: *u8 = "%.6f", flags: InputTextFlags = .None) -> bool #foreign imgui "?InputDouble@ImGui@@YA_NPEBDPEANNN0H@Z"; +InputScalar :: (label: *u8, data_type: DataType, p_data: *void, p_step: *void = null, p_step_fast: *void = null, format: *u8 = null, flags: InputTextFlags = .None) -> bool #foreign imgui "?InputScalar@ImGui@@YA_NPEBDHPEAXPEBX20H@Z"; +InputScalarN :: (label: *u8, data_type: DataType, p_data: *void, components: s32, p_step: *void = null, p_step_fast: *void = null, format: *u8 = null, flags: InputTextFlags = .None) -> bool #foreign imgui "?InputScalarN@ImGui@@YA_NPEBDHPEAXHPEBX20H@Z"; + +// Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.) +// - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. +// - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x +ColorEdit3 :: (label: *u8, col: *[3] float, flags: ColorEditFlags = .None) -> bool #foreign imgui "?ColorEdit3@ImGui@@YA_NPEBDQEAMH@Z"; +ColorEdit4 :: (label: *u8, col: *[4] float, flags: ColorEditFlags = .None) -> bool #foreign imgui "?ColorEdit4@ImGui@@YA_NPEBDQEAMH@Z"; +ColorPicker3 :: (label: *u8, col: *[3] float, flags: ColorEditFlags = .None) -> bool #foreign imgui "?ColorPicker3@ImGui@@YA_NPEBDQEAMH@Z"; +ColorPicker4 :: (label: *u8, col: *[4] float, flags: ColorEditFlags = .None, ref_col: *float = null) -> bool #foreign imgui "?ColorPicker4@ImGui@@YA_NPEBDQEAMHPEBM@Z"; +ColorButton :: (desc_id: *u8, col: *ImVec4, flags: ColorEditFlags = .None, size: *ImVec2) -> bool #foreign imgui "?ColorButton@ImGui@@YA_NPEBDAEBUImVec4@@HAEBUImVec2@@@Z"; +ColorButton :: (desc_id: *u8, col: ImVec4, flags: ColorEditFlags = .None, size: ImVec2 = ImVec2.{0, 0}) -> bool #no_context { + return ColorButton(desc_id, *col, flags, *size); +} +SetColorEditOptions :: (flags: ColorEditFlags) -> void #foreign imgui "?SetColorEditOptions@ImGui@@YAXH@Z"; + +// Widgets: Trees +// - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. +TreeNode :: (label: *u8) -> bool #foreign imgui "?TreeNode@ImGui@@YA_NPEBD@Z"; +TreeNode_CFormat :: (str_id: *u8, fmt: *u8, __args: ..Any) -> bool #foreign imgui "?TreeNode@ImGui@@YA_NPEBD0ZZ"; +TreeNode :: (str_id: *u8, fmt: string, __args: ..Any) -> bool { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + return TreeNode_CFormat(str_id, "%s", formatted_text.data); +} @PrintLike +TreeNode_CFormat :: (ptr_id: *void, fmt: *u8, __args: ..Any) -> bool #foreign imgui "?TreeNode@ImGui@@YA_NPEBXPEBDZZ"; +TreeNode :: (ptr_id: *void, fmt: string, __args: ..Any) -> bool { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + return TreeNode_CFormat(ptr_id, "%s", formatted_text.data); +} @PrintLike + +TreeNodeEx :: (label: *u8, flags: TreeNodeFlags = .None) -> bool #foreign imgui "?TreeNodeEx@ImGui@@YA_NPEBDH@Z"; +TreeNodeEx_CFormat :: (str_id: *u8, flags: TreeNodeFlags, fmt: *u8, __args: ..Any) -> bool #foreign imgui "?TreeNodeEx@ImGui@@YA_NPEBDH0ZZ"; +TreeNodeEx :: (str_id: *u8, flags: TreeNodeFlags, fmt: string, __args: ..Any) -> bool { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + return TreeNodeEx_CFormat(str_id, flags, "%s", formatted_text.data); +} @PrintLike +TreeNodeEx_CFormat :: (ptr_id: *void, flags: TreeNodeFlags, fmt: *u8, __args: ..Any) -> bool #foreign imgui "?TreeNodeEx@ImGui@@YA_NPEBXHPEBDZZ"; +TreeNodeEx :: (ptr_id: *void, flags: TreeNodeFlags, fmt: string, __args: ..Any) -> bool { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + return TreeNodeEx_CFormat(ptr_id, flags, "%s", formatted_text.data); +} @PrintLike + +TreePush :: (str_id: *u8) -> void #foreign imgui "?TreePush@ImGui@@YAXPEBD@Z"; +TreePush :: (ptr_id: *void) -> void #foreign imgui "?TreePush@ImGui@@YAXPEBX@Z"; +TreePop :: () -> void #foreign imgui "?TreePop@ImGui@@YAXXZ"; +GetTreeNodeToLabelSpacing :: () -> float #foreign imgui "?GetTreeNodeToLabelSpacing@ImGui@@YAMXZ"; +CollapsingHeader :: (label: *u8, flags: TreeNodeFlags = .None) -> bool #foreign imgui "?CollapsingHeader@ImGui@@YA_NPEBDH@Z"; +CollapsingHeader :: (label: *u8, p_visible: *bool, flags: TreeNodeFlags = .None) -> bool #foreign imgui "?CollapsingHeader@ImGui@@YA_NPEBDPEA_NH@Z"; +SetNextItemOpen :: (is_open: bool, cond: Cond = .None) -> void #foreign imgui "?SetNextItemOpen@ImGui@@YAX_NH@Z"; +SetNextItemStorageID :: (storage_id: ID) -> void #foreign imgui "?SetNextItemStorageID@ImGui@@YAXI@Z"; + +// Widgets: Selectables +// - A selectable highlights when hovered, and can display another color when selected. +// - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. +Selectable :: (label: *u8, selected := false, flags: SelectableFlags = .None, size: *ImVec2) -> bool #foreign imgui "?Selectable@ImGui@@YA_NPEBD_NHAEBUImVec2@@@Z"; +Selectable :: (label: *u8, selected := false, flags: SelectableFlags = .None, size: ImVec2 = ImVec2.{0, 0}) -> bool #no_context { + return Selectable(label, selected, flags, *size); +} +Selectable :: (label: *u8, p_selected: *bool, flags: SelectableFlags = .None, size: *ImVec2) -> bool #foreign imgui "?Selectable@ImGui@@YA_NPEBDPEA_NHAEBUImVec2@@@Z"; +Selectable :: (label: *u8, p_selected: *bool, flags: SelectableFlags = .None, size: ImVec2 = ImVec2.{0, 0}) -> bool #no_context { + return Selectable(label, p_selected, flags, *size); +} + +// Multi-selection system for Selectable(), Checkbox(), TreeNode() functions [BETA] +// - This enables standard multi-selection/range-selection idioms (Ctrl+Mouse/Keyboard, Shift+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used. +// - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something else). +// - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo. +// - TreeNode() is technically supported but... using this correctly is more complicated. You need some sort of linear/random access to your tree, +// which is suited to advanced trees setups already implementing filters and clipper. We will work simplifying the current demo. +// - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you to compute, you may avoid them. +BeginMultiSelect :: (flags: MultiSelectFlags, selection_size: s32 = -1, items_count: s32 = -1) -> *MultiSelectIO #foreign imgui "?BeginMultiSelect@ImGui@@YAPEAUImGuiMultiSelectIO@@HHH@Z"; +EndMultiSelect :: () -> *MultiSelectIO #foreign imgui "?EndMultiSelect@ImGui@@YAPEAUImGuiMultiSelectIO@@XZ"; +SetNextItemSelectionUserData :: (selection_user_data: SelectionUserData) -> void #foreign imgui "?SetNextItemSelectionUserData@ImGui@@YAX_J@Z"; +IsItemToggledSelection :: () -> bool #foreign imgui "?IsItemToggledSelection@ImGui@@YA_NXZ"; + +// Widgets: List Boxes +// - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. +// - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the same result. +// - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items. +// - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analogous to how Combos are created. +// - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth +// - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items +BeginListBox :: (label: *u8, size: *ImVec2) -> bool #foreign imgui "?BeginListBox@ImGui@@YA_NPEBDAEBUImVec2@@@Z"; +BeginListBox :: (label: *u8, size: ImVec2 = ImVec2.{0, 0}) -> bool #no_context { + return BeginListBox(label, *size); +} +EndListBox :: () -> void #foreign imgui "?EndListBox@ImGui@@YAXXZ"; +ListBox :: (label: *u8, current_item: *s32, items: **u8, items_count: s32, height_in_items: s32 = -1) -> bool #foreign imgui "?ListBox@ImGui@@YA_NPEBDPEAHQEBQEBDHH@Z"; +ListBox :: (label: *u8, current_item: *s32, getter: #type (user_data: *void, idx: s32) -> *u8 #c_call, user_data: *void, items_count: s32, height_in_items: s32 = -1) -> bool #foreign imgui "?ListBox@ImGui@@YA_NPEBDPEAHP6APEBDPEAXH@Z2HH@Z"; + +// Widgets: Data Plotting +// - Consider using ImPlot (https://github.com/epezent/implot) which is much better! +PlotLines :: (label: *u8, values: *float, values_count: s32, values_offset: s32 = 0, overlay_text: *u8 = null, scale_min: float = FLOAT32_MAX, scale_max: float = FLOAT32_MAX, graph_size: ImVec2 = .{0, 0}, stride: s32 = 4) -> void #foreign imgui "?PlotLines@ImGui@@YAXPEBDPEBMHH0MMUImVec2@@H@Z"; +PlotLines :: (label: *u8, values_getter: #type (data: *void, idx: s32) -> float #c_call, data: *void, values_count: s32, values_offset: s32 = 0, overlay_text: *u8 = null, scale_min: float = FLOAT32_MAX, scale_max: float = FLOAT32_MAX, graph_size: ImVec2 = .{0, 0}) -> void #foreign imgui "?PlotLines@ImGui@@YAXPEBDP6AMPEAXH@Z1HH0MMUImVec2@@@Z"; +PlotHistogram :: (label: *u8, values: *float, values_count: s32, values_offset: s32 = 0, overlay_text: *u8 = null, scale_min: float = FLOAT32_MAX, scale_max: float = FLOAT32_MAX, graph_size: ImVec2 = .{0, 0}, stride: s32 = 4) -> void #foreign imgui "?PlotHistogram@ImGui@@YAXPEBDPEBMHH0MMUImVec2@@H@Z"; +PlotHistogram :: (label: *u8, values_getter: #type (data: *void, idx: s32) -> float #c_call, data: *void, values_count: s32, values_offset: s32 = 0, overlay_text: *u8 = null, scale_min: float = FLOAT32_MAX, scale_max: float = FLOAT32_MAX, graph_size: ImVec2 = .{0, 0}) -> void #foreign imgui "?PlotHistogram@ImGui@@YAXPEBDP6AMPEAXH@Z1HH0MMUImVec2@@@Z"; + +// Widgets: Value() Helpers. +// - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) +Value :: (prefix: *u8, b: bool) -> void #foreign imgui "?Value@ImGui@@YAXPEBD_N@Z"; +Value :: (prefix: *u8, v: s32) -> void #foreign imgui "?Value@ImGui@@YAXPEBDH@Z"; +Value :: (prefix: *u8, v: u32) -> void #foreign imgui "?Value@ImGui@@YAXPEBDI@Z"; +Value :: (prefix: *u8, v: float, float_format: *u8 = null) -> void #foreign imgui "?Value@ImGui@@YAXPEBDM0@Z"; + +// Widgets: Menus +// - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. +// - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. +// - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. +// - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. +BeginMenuBar :: () -> bool #foreign imgui "?BeginMenuBar@ImGui@@YA_NXZ"; +EndMenuBar :: () -> void #foreign imgui "?EndMenuBar@ImGui@@YAXXZ"; +BeginMainMenuBar :: () -> bool #foreign imgui "?BeginMainMenuBar@ImGui@@YA_NXZ"; +EndMainMenuBar :: () -> void #foreign imgui "?EndMainMenuBar@ImGui@@YAXXZ"; +BeginMenu :: (label: *u8, enabled := true) -> bool #foreign imgui "?BeginMenu@ImGui@@YA_NPEBD_N@Z"; +EndMenu :: () -> void #foreign imgui "?EndMenu@ImGui@@YAXXZ"; +MenuItem :: (label: *u8, shortcut: *u8 = null, selected := false, enabled := true) -> bool #foreign imgui "?MenuItem@ImGui@@YA_NPEBD0_N1@Z"; +MenuItem :: (label: *u8, shortcut: *u8, p_selected: *bool, enabled := true) -> bool #foreign imgui "?MenuItem@ImGui@@YA_NPEBD0PEA_N_N@Z"; + +// Tooltips +// - Tooltips are windows following the mouse. They do not take focus away. +// - A tooltip window can contain items of any types. +// - SetTooltip() is more or less a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom (with a subtlety that it discard any previously submitted tooltip) +BeginTooltip :: () -> bool #foreign imgui "?BeginTooltip@ImGui@@YA_NXZ"; +EndTooltip :: () -> void #foreign imgui "?EndTooltip@ImGui@@YAXXZ"; +SetTooltip_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?SetTooltip@ImGui@@YAXPEBDZZ"; +SetTooltip :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + SetTooltip_CFormat("%s", formatted_text.data); +} @PrintLike + +// Tooltips: helpers for showing a tooltip when hovering an item +// - BeginItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_ForTooltip) && BeginTooltip())' idiom. +// - SetItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) { SetTooltip(...); }' idiom. +// - Where 'ImGuiHoveredFlags_ForTooltip' itself is a shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on active input type. For mouse it defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. +BeginItemTooltip :: () -> bool #foreign imgui "?BeginItemTooltip@ImGui@@YA_NXZ"; +SetItemTooltip_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?SetItemTooltip@ImGui@@YAXPEBDZZ"; +SetItemTooltip :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + SetItemTooltip_CFormat("%s", formatted_text.data); +} @PrintLike + +// Popups, Modals +// - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. +// - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. +// - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. +// - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. +// - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). +// - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack. +// This is sometimes leading to confusing mistakes. May rework this in the future. +// - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards if returned true. ImGuiWindowFlags are forwarded to the window. +// - BeginPopupModal(): block every interaction behind the window, cannot be closed by user, add a dimming background, has a title bar. +BeginPopup :: (str_id: *u8, flags: WindowFlags = .None) -> bool #foreign imgui "?BeginPopup@ImGui@@YA_NPEBDH@Z"; +BeginPopupModal :: (name: *u8, p_open: *bool = null, flags: WindowFlags = .None) -> bool #foreign imgui "?BeginPopupModal@ImGui@@YA_NPEBDPEA_NH@Z"; +EndPopup :: () -> void #foreign imgui "?EndPopup@ImGui@@YAXXZ"; + +// Popups: open/close functions +// - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. +// - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. +// - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually. +// - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). +// - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). +// - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. +OpenPopup :: (str_id: *u8, popup_flags: PopupFlags = .None) -> void #foreign imgui "?OpenPopup@ImGui@@YAXPEBDH@Z"; +OpenPopup :: (id: ID, popup_flags: PopupFlags = .None) -> void #foreign imgui "?OpenPopup@ImGui@@YAXIH@Z"; +OpenPopupOnItemClick :: (str_id: *u8 = null, popup_flags: PopupFlags = .None) -> void #foreign imgui "?OpenPopupOnItemClick@ImGui@@YAXPEBDH@Z"; +CloseCurrentPopup :: () -> void #foreign imgui "?CloseCurrentPopup@ImGui@@YAXXZ"; + +// Popups: Open+Begin popup combined functions helpers to create context menus. +// - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. +// - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. +// - IMPORTANT: If you ever used the left mouse button with BeginPopupContextXXX() helpers before 1.92.6: +// - Before this version, OpenPopupOnItemClick(), BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid() had 'a ImGuiPopupFlags popup_flags = 1' default value in their function signature. +// - Before: Explicitly passing a literal 0 meant ImGuiPopupFlags_MouseButtonLeft. The default = 1 meant ImGuiPopupFlags_MouseButtonRight. +// - After: The default = 0 means ImGuiPopupFlags_MouseButtonRight. Explicitly passing a literal 1 also means ImGuiPopupFlags_MouseButtonRight (if legacy behavior are enabled) or will assert (if legacy behavior are disabled). +// - TL;DR: if you don't want to use right mouse button for popups, always specify it explicitly using a named ImGuiPopupFlags_MouseButtonXXXX value. +// - Read "API BREAKING CHANGES" 2026/01/07 (1.92.6) entry in imgui.cpp or GitHub topic #9157 for all details. +BeginPopupContextItem :: (str_id: *u8 = null, popup_flags: PopupFlags = .None) -> bool #foreign imgui "?BeginPopupContextItem@ImGui@@YA_NPEBDH@Z"; +BeginPopupContextWindow :: (str_id: *u8 = null, popup_flags: PopupFlags = .None) -> bool #foreign imgui "?BeginPopupContextWindow@ImGui@@YA_NPEBDH@Z"; +BeginPopupContextVoid :: (str_id: *u8 = null, popup_flags: PopupFlags = .None) -> bool #foreign imgui "?BeginPopupContextVoid@ImGui@@YA_NPEBDH@Z"; + +// Popups: query functions +// - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. +// - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack. +// - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open. +IsPopupOpen :: (str_id: *u8, flags: PopupFlags = .None) -> bool #foreign imgui "?IsPopupOpen@ImGui@@YA_NPEBDH@Z"; + +// Tables +// - Full-featured replacement for old Columns API. +// - See Demo->Tables for demo code. See top of imgui_tables.cpp for general commentary. +// - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags. +// The typical call flow is: +// - 1. Call BeginTable(), early out if returning false. +// - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults. +// - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows. +// - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data. +// - 5. Populate contents: +// - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column. +// - If you are using tables as a sort of grid, where every column is holding the same type of contents, +// you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex(). +// TableNextColumn() will automatically wrap-around into the next row if needed. +// - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column! +// - Summary of possible call flow: +// - TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK +// - TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK +// - TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row! +// - TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! +// - 5. Call EndTable() +BeginTable :: (str_id: *u8, columns: s32, flags: TableFlags = .None, outer_size: *ImVec2, inner_width: float = 0.0) -> bool #foreign imgui "?BeginTable@ImGui@@YA_NPEBDHHAEBUImVec2@@M@Z"; +BeginTable :: (str_id: *u8, columns: s32, flags: TableFlags = .None, outer_size: ImVec2 = ImVec2.{0.0, 0.0}, inner_width: float = 0.0) -> bool #no_context { + return BeginTable(str_id, columns, flags, *outer_size, inner_width); +} +EndTable :: () -> void #foreign imgui "?EndTable@ImGui@@YAXXZ"; +TableNextRow :: (row_flags: TableRowFlags = .None, min_row_height: float = 0.0) -> void #foreign imgui "?TableNextRow@ImGui@@YAXHM@Z"; +TableNextColumn :: () -> bool #foreign imgui "?TableNextColumn@ImGui@@YA_NXZ"; +TableSetColumnIndex :: (column_n: s32) -> bool #foreign imgui "?TableSetColumnIndex@ImGui@@YA_NH@Z"; + +// Tables: Headers & Columns declaration +// - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. +// - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. +// Headers are required to perform: reordering, sorting, and opening the context menu. +// The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. +// - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in +// some advanced use cases (e.g. adding custom widgets in header row). +// - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. +TableSetupColumn :: (label: *u8, flags: TableColumnFlags = .None, init_width_or_weight: float = 0.0, user_id: ID = 0) -> void #foreign imgui "?TableSetupColumn@ImGui@@YAXPEBDHMI@Z"; +TableSetupScrollFreeze :: (cols: s32, rows: s32) -> void #foreign imgui "?TableSetupScrollFreeze@ImGui@@YAXHH@Z"; +TableHeader :: (label: *u8) -> void #foreign imgui "?TableHeader@ImGui@@YAXPEBD@Z"; +TableHeadersRow :: () -> void #foreign imgui "?TableHeadersRow@ImGui@@YAXXZ"; +TableAngledHeadersRow :: () -> void #foreign imgui "?TableAngledHeadersRow@ImGui@@YAXXZ"; + +// Tables: Sorting & Miscellaneous functions +// - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting. +// When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have +// changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, +// else you may wastefully sort your data every frame! +// - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. +TableGetSortSpecs :: () -> *TableSortSpecs #foreign imgui "?TableGetSortSpecs@ImGui@@YAPEAUImGuiTableSortSpecs@@XZ"; +TableGetColumnCount :: () -> s32 #foreign imgui "?TableGetColumnCount@ImGui@@YAHXZ"; +TableGetColumnIndex :: () -> s32 #foreign imgui "?TableGetColumnIndex@ImGui@@YAHXZ"; +TableGetRowIndex :: () -> s32 #foreign imgui "?TableGetRowIndex@ImGui@@YAHXZ"; +TableGetColumnName :: (column_n: s32 = -1) -> *u8 #foreign imgui "?TableGetColumnName@ImGui@@YAPEBDH@Z"; +TableGetColumnFlags :: (column_n: s32 = -1) -> TableColumnFlags #foreign imgui "?TableGetColumnFlags@ImGui@@YAHH@Z"; +TableSetColumnEnabled :: (column_n: s32, v: bool) -> void #foreign imgui "?TableSetColumnEnabled@ImGui@@YAXH_N@Z"; +TableGetHoveredColumn :: () -> s32 #foreign imgui "?TableGetHoveredColumn@ImGui@@YAHXZ"; +TableSetBgColor :: (target: TableBgTarget, color: ImU32, column_n: s32 = -1) -> void #foreign imgui "?TableSetBgColor@ImGui@@YAXHIH@Z"; + +// Legacy Columns API (prefer using Tables!) +// - You can also use SameLine(pos_x) to mimic simplified columns. +Columns :: (count: s32 = 1, id: *u8 = null, borders := true) -> void #foreign imgui "?Columns@ImGui@@YAXHPEBD_N@Z"; +NextColumn :: () -> void #foreign imgui "?NextColumn@ImGui@@YAXXZ"; +GetColumnIndex :: () -> s32 #foreign imgui "?GetColumnIndex@ImGui@@YAHXZ"; +GetColumnWidth :: (column_index: s32 = -1) -> float #foreign imgui "?GetColumnWidth@ImGui@@YAMH@Z"; +SetColumnWidth :: (column_index: s32, width: float) -> void #foreign imgui "?SetColumnWidth@ImGui@@YAXHM@Z"; +GetColumnOffset :: (column_index: s32 = -1) -> float #foreign imgui "?GetColumnOffset@ImGui@@YAMH@Z"; +SetColumnOffset :: (column_index: s32, offset_x: float) -> void #foreign imgui "?SetColumnOffset@ImGui@@YAXHM@Z"; +GetColumnsCount :: () -> s32 #foreign imgui "?GetColumnsCount@ImGui@@YAHXZ"; + +// Tab Bars, Tabs +// - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab bars/tabs yourself. +BeginTabBar :: (str_id: *u8, flags: TabBarFlags = .None) -> bool #foreign imgui "?BeginTabBar@ImGui@@YA_NPEBDH@Z"; +EndTabBar :: () -> void #foreign imgui "?EndTabBar@ImGui@@YAXXZ"; +BeginTabItem :: (label: *u8, p_open: *bool = null, flags: TabItemFlags = .None) -> bool #foreign imgui "?BeginTabItem@ImGui@@YA_NPEBDPEA_NH@Z"; +EndTabItem :: () -> void #foreign imgui "?EndTabItem@ImGui@@YAXXZ"; +TabItemButton :: (label: *u8, flags: TabItemFlags = .None) -> bool #foreign imgui "?TabItemButton@ImGui@@YA_NPEBDH@Z"; +SetTabItemClosed :: (tab_or_docked_window_label: *u8) -> void #foreign imgui "?SetTabItemClosed@ImGui@@YAXPEBD@Z"; + +// Docking +// - Read https://github.com/ocornut/imgui/wiki/Docking for details. +// - Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. +// - You can use many Docking facilities without calling any API. +// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking. +// - Drag from window menu button (upper-left button) to undock an entire node (all windows). +// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking. +// - DockSpaceOverViewport: +// - This is a helper to create an invisible window covering a viewport, then submit a DockSpace() into it. +// - Most applications can simply call DockSpaceOverViewport() once to allow docking windows into e.g. the edge of your screen. +// e.g. ImGui::NewFrame(); ImGui::DockSpaceOverViewport(); // Create a dockspace in main viewport. +// or: ImGui::NewFrame(); ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Create a dockspace in main viewport, central node is transparent. +// - Dockspaces: +// - A dockspace is an explicit dock node within an existing window. +// - IMPORTANT: Dockspaces need to be submitted _before_ any window they can host. Submit them early in your frame! +// - IMPORTANT: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked. +// If you have e.g. multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly. +// - See 'Demo->Examples->Dockspace' or 'Demo->Examples->Documents' for more detailed demos. +// - Programmatic docking: +// - There is no public API yet other than the very limited SetNextWindowDockID() function. Sorry for that! +// - Read https://github.com/ocornut/imgui/wiki/Docking for examples of how to use current internal API. +DockSpace :: (dockspace_id: ID, size: *ImVec2, flags: DockNodeFlags = .None, window_class: *WindowClass = null) -> ID #foreign imgui "?DockSpace@ImGui@@YAIIAEBUImVec2@@HPEBUImGuiWindowClass@@@Z"; +DockSpace :: (dockspace_id: ID, size: ImVec2 = ImVec2.{0, 0}, flags: DockNodeFlags = .None, window_class: *WindowClass = null) -> ID #no_context { + return DockSpace(dockspace_id, *size, flags, window_class); +} +DockSpaceOverViewport :: (dockspace_id: ID = 0, viewport: *Viewport = null, flags: DockNodeFlags = .None, window_class: *WindowClass = null) -> ID #foreign imgui "?DockSpaceOverViewport@ImGui@@YAIIPEBUImGuiViewport@@HPEBUImGuiWindowClass@@@Z"; +SetNextWindowDockID :: (dock_id: ID, cond: Cond = .None) -> void #foreign imgui "?SetNextWindowDockID@ImGui@@YAXIH@Z"; +SetNextWindowClass :: (window_class: *WindowClass) -> void #foreign imgui "?SetNextWindowClass@ImGui@@YAXPEBUImGuiWindowClass@@@Z"; +GetWindowDockID :: () -> ID #foreign imgui "?GetWindowDockID@ImGui@@YAIXZ"; +IsWindowDocked :: () -> bool #foreign imgui "?IsWindowDocked@ImGui@@YA_NXZ"; + +// Logging/Capture +// - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. +LogToTTY :: (auto_open_depth: s32 = -1) -> void #foreign imgui "?LogToTTY@ImGui@@YAXH@Z"; +LogToFile :: (auto_open_depth: s32 = -1, filename: *u8 = null) -> void #foreign imgui "?LogToFile@ImGui@@YAXHPEBD@Z"; +LogToClipboard :: (auto_open_depth: s32 = -1) -> void #foreign imgui "?LogToClipboard@ImGui@@YAXH@Z"; +LogFinish :: () -> void #foreign imgui "?LogFinish@ImGui@@YAXXZ"; +LogButtons :: () -> void #foreign imgui "?LogButtons@ImGui@@YAXXZ"; +LogText_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?LogText@ImGui@@YAXPEBDZZ"; +LogText :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + LogText_CFormat("%s", formatted_text.data); +} @PrintLike + +// Drag and Drop +// - On source items, call BeginDragDropSource(), if it returns true also call SetDragDropPayload() + EndDragDropSource(). +// - On target candidates, call BeginDragDropTarget(), if it returns true also call AcceptDragDropPayload() + EndDragDropTarget(). +// - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip, see #1725) +// - An item can be both drag source and drop target. +BeginDragDropSource :: (flags: DragDropFlags = .None) -> bool #foreign imgui "?BeginDragDropSource@ImGui@@YA_NH@Z"; +SetDragDropPayload :: (type: *u8, data: *void, sz: u64, cond: Cond = .None) -> bool #foreign imgui "?SetDragDropPayload@ImGui@@YA_NPEBDPEBX_KH@Z"; +EndDragDropSource :: () -> void #foreign imgui "?EndDragDropSource@ImGui@@YAXXZ"; +BeginDragDropTarget :: () -> bool #foreign imgui "?BeginDragDropTarget@ImGui@@YA_NXZ"; +AcceptDragDropPayload :: (type: *u8, flags: DragDropFlags = .None) -> *Payload #foreign imgui "?AcceptDragDropPayload@ImGui@@YAPEBUImGuiPayload@@PEBDH@Z"; +EndDragDropTarget :: () -> void #foreign imgui "?EndDragDropTarget@ImGui@@YAXXZ"; +GetDragDropPayload :: () -> *Payload #foreign imgui "?GetDragDropPayload@ImGui@@YAPEBUImGuiPayload@@XZ"; + +// Disabling [BETA API] +// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) +// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) +// - Tooltips windows are automatically opted out of disabling. Note that IsItemHovered() by default returns false on disabled items, unless using ImGuiHoveredFlags_AllowWhenDisabled. +// - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls) +BeginDisabled :: (disabled := true) -> void #foreign imgui "?BeginDisabled@ImGui@@YAX_N@Z"; +EndDisabled :: () -> void #foreign imgui "?EndDisabled@ImGui@@YAXXZ"; + +// Clipping +// - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only. +PushClipRect :: (clip_rect_min: *ImVec2, clip_rect_max: *ImVec2, intersect_with_current_clip_rect: bool) -> void #foreign imgui "?PushClipRect@ImGui@@YAXAEBUImVec2@@0_N@Z"; +PushClipRect :: (clip_rect_min: ImVec2, clip_rect_max: ImVec2, intersect_with_current_clip_rect: bool) #no_context { + PushClipRect(*clip_rect_min, *clip_rect_max, intersect_with_current_clip_rect); +} +PopClipRect :: () -> void #foreign imgui "?PopClipRect@ImGui@@YAXXZ"; + +// Focus, Activation +SetItemDefaultFocus :: () -> void #foreign imgui "?SetItemDefaultFocus@ImGui@@YAXXZ"; +SetKeyboardFocusHere :: (offset: s32 = 0) -> void #foreign imgui "?SetKeyboardFocusHere@ImGui@@YAXH@Z"; + +// Keyboard/Gamepad Navigation +SetNavCursorVisible :: (visible: bool) -> void #foreign imgui "?SetNavCursorVisible@ImGui@@YAX_N@Z"; + +// Overlapping mode +SetNextItemAllowOverlap :: () -> void #foreign imgui "?SetNextItemAllowOverlap@ImGui@@YAXXZ"; + +// Item/Widgets Utilities and Query Functions +// - Most of the functions are referring to the previous Item that has been submitted. +// - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. +IsItemHovered :: (flags: HoveredFlags = .None) -> bool #foreign imgui "?IsItemHovered@ImGui@@YA_NH@Z"; +IsItemActive :: () -> bool #foreign imgui "?IsItemActive@ImGui@@YA_NXZ"; +IsItemFocused :: () -> bool #foreign imgui "?IsItemFocused@ImGui@@YA_NXZ"; +IsItemClicked :: (mouse_button: MouseButton = .Left) -> bool #foreign imgui "?IsItemClicked@ImGui@@YA_NH@Z"; +IsItemVisible :: () -> bool #foreign imgui "?IsItemVisible@ImGui@@YA_NXZ"; +IsItemEdited :: () -> bool #foreign imgui "?IsItemEdited@ImGui@@YA_NXZ"; +IsItemActivated :: () -> bool #foreign imgui "?IsItemActivated@ImGui@@YA_NXZ"; +IsItemDeactivated :: () -> bool #foreign imgui "?IsItemDeactivated@ImGui@@YA_NXZ"; +IsItemDeactivatedAfterEdit :: () -> bool #foreign imgui "?IsItemDeactivatedAfterEdit@ImGui@@YA_NXZ"; +IsItemToggledOpen :: () -> bool #foreign imgui "?IsItemToggledOpen@ImGui@@YA_NXZ"; +IsAnyItemHovered :: () -> bool #foreign imgui "?IsAnyItemHovered@ImGui@@YA_NXZ"; +IsAnyItemActive :: () -> bool #foreign imgui "?IsAnyItemActive@ImGui@@YA_NXZ"; +IsAnyItemFocused :: () -> bool #foreign imgui "?IsAnyItemFocused@ImGui@@YA_NXZ"; +GetItemID :: () -> ID #foreign imgui "?GetItemID@ImGui@@YAIXZ"; +GetItemRectMin :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetItemRectMin@ImGui@@YA?AUImVec2@@XZ"; +GetItemRectMax :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetItemRectMax@ImGui@@YA?AUImVec2@@XZ"; +GetItemRectSize :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetItemRectSize@ImGui@@YA?AUImVec2@@XZ"; +GetItemFlags :: () -> ItemFlags #foreign imgui "?GetItemFlags@ImGui@@YAHXZ"; + +// Viewports +// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. +// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. +GetMainViewport :: () -> *Viewport #foreign imgui "?GetMainViewport@ImGui@@YAPEAUImGuiViewport@@XZ"; + +// Background/Foreground Draw Lists +GetBackgroundDrawList :: (viewport: *Viewport = null) -> *ImDrawList #foreign imgui "?GetBackgroundDrawList@ImGui@@YAPEAUImDrawList@@PEAUImGuiViewport@@@Z"; +GetForegroundDrawList :: (viewport: *Viewport = null) -> *ImDrawList #foreign imgui "?GetForegroundDrawList@ImGui@@YAPEAUImDrawList@@PEAUImGuiViewport@@@Z"; + +// Miscellaneous Utilities +IsRectVisible :: (size: *ImVec2) -> bool #foreign imgui "?IsRectVisible@ImGui@@YA_NAEBUImVec2@@@Z"; +IsRectVisible :: (size: ImVec2) -> bool #no_context { + return IsRectVisible(*size); +} +IsRectVisible :: (rect_min: *ImVec2, rect_max: *ImVec2) -> bool #foreign imgui "?IsRectVisible@ImGui@@YA_NAEBUImVec2@@0@Z"; +IsRectVisible :: (rect_min: ImVec2, rect_max: ImVec2) -> bool #no_context { + return IsRectVisible(*rect_min, *rect_max); +} +GetTime :: () -> float64 #foreign imgui "?GetTime@ImGui@@YANXZ"; +GetFrameCount :: () -> s32 #foreign imgui "?GetFrameCount@ImGui@@YAHXZ"; +GetDrawListSharedData :: () -> *ImDrawListSharedData #foreign imgui "?GetDrawListSharedData@ImGui@@YAPEAUImDrawListSharedData@@XZ"; +GetStyleColorName :: (idx: Col) -> *u8 #foreign imgui "?GetStyleColorName@ImGui@@YAPEBDH@Z"; +SetStateStorage :: (storage: *Storage) -> void #foreign imgui "?SetStateStorage@ImGui@@YAXPEAUImGuiStorage@@@Z"; +GetStateStorage :: () -> *Storage #foreign imgui "?GetStateStorage@ImGui@@YAPEAUImGuiStorage@@XZ"; + +// Text Utilities +CalcTextSize :: (text: *u8, text_end: *u8 = null, hide_text_after_double_hash := false, wrap_width: float = -1.0) -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?CalcTextSize@ImGui@@YA?AUImVec2@@PEBD0_NM@Z"; +CalcTextSize :: (text: string, hide_text_after_double_hash := false, wrap_width: float = -1.0) -> ImVec2 #no_context { + return CalcTextSize(text.data, text.data + text.count, hide_text_after_double_hash, wrap_width); +} + +// Color Utilities +ColorConvertU32ToFloat4 :: (in: ImU32) -> ImVec4 #cpp_return_type_is_non_pod #foreign imgui "?ColorConvertU32ToFloat4@ImGui@@YA?AUImVec4@@I@Z"; +ColorConvertFloat4ToU32 :: (in: *ImVec4) -> ImU32 #foreign imgui "?ColorConvertFloat4ToU32@ImGui@@YAIAEBUImVec4@@@Z"; +ColorConvertFloat4ToU32 :: (in: ImVec4) -> ImU32 #no_context { + return ColorConvertFloat4ToU32(*in); +} +ColorConvertRGBtoHSV :: (r: float, g: float, b: float, out_h: *float, out_s: *float, out_v: *float) -> void #foreign imgui "?ColorConvertRGBtoHSV@ImGui@@YAXMMMAEAM00@Z"; +ColorConvertHSVtoRGB :: (h: float, s: float, v: float, out_r: *float, out_g: *float, out_b: *float) -> void #foreign imgui "?ColorConvertHSVtoRGB@ImGui@@YAXMMMAEAM00@Z"; + +// Inputs Utilities: Raw Keyboard/Mouse/Gamepad Access +// - Consider using the Shortcut() function instead of IsKeyPressed()/IsKeyChordPressed()! Shortcut() is easier to use and better featured (can do focus routing check). +// - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). +// - (legacy: before v1.87 (2022-02), we used ImGuiKey < 512 values to carry native/user indices as defined by each backends. This was obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See https://github.com/ocornut/imgui/issues/4921) +IsKeyDown :: (key: Key) -> bool #foreign imgui "?IsKeyDown@ImGui@@YA_NW4ImGuiKey@@@Z"; +IsKeyPressed :: (key: Key, repeat := true) -> bool #foreign imgui "?IsKeyPressed@ImGui@@YA_NW4ImGuiKey@@_N@Z"; +IsKeyReleased :: (key: Key) -> bool #foreign imgui "?IsKeyReleased@ImGui@@YA_NW4ImGuiKey@@@Z"; +IsKeyChordPressed :: (key_chord: KeyChord) -> bool #foreign imgui "?IsKeyChordPressed@ImGui@@YA_NH@Z"; +GetKeyPressedAmount :: (key: Key, repeat_delay: float, rate: float) -> s32 #foreign imgui "?GetKeyPressedAmount@ImGui@@YAHW4ImGuiKey@@MM@Z"; +GetKeyName :: (key: Key) -> *u8 #foreign imgui "?GetKeyName@ImGui@@YAPEBDW4ImGuiKey@@@Z"; +SetNextFrameWantCaptureKeyboard :: (want_capture_keyboard: bool) -> void #foreign imgui "?SetNextFrameWantCaptureKeyboard@ImGui@@YAX_N@Z"; + +// Inputs Utilities: Shortcut Testing & Routing +// - Typical use is e.g.: 'if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_S)) { ... }'. +// - Flags: Default route use ImGuiInputFlags_RouteFocused, but see ImGuiInputFlags_RouteGlobal and other options in ImGuiInputFlags_! +// - Flags: Use ImGuiInputFlags_Repeat to support repeat. +// - ImGuiKeyChord = a ImGuiKey + optional ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. +// ImGuiKey_C // Accepted by functions taking ImGuiKey or ImGuiKeyChord arguments +// ImGuiMod_Ctrl | ImGuiKey_C // Accepted by functions taking ImGuiKeyChord arguments +// only ImGuiMod_XXX values are legal to combine with an ImGuiKey. You CANNOT combine two ImGuiKey values. +// - The general idea is that several callers may register interest in a shortcut, and only one owner gets it. +// Parent -> call Shortcut(Ctrl+S) // When Parent is focused, Parent gets the shortcut. +// Child1 -> call Shortcut(Ctrl+S) // When Child1 is focused, Child1 gets the shortcut (Child1 overrides Parent shortcuts) +// Child2 -> no call // When Child2 is focused, Parent gets the shortcut. +// The whole system is order independent, so if Child1 makes its calls before Parent, results will be identical. +// This is an important property as it facilitate working with foreign code or larger codebase. +// - To understand the difference: +// - IsKeyChordPressed() compares mods and call IsKeyPressed() +// -> the function has no side-effect. +// - Shortcut() submits a route, routes are resolved, if it currently can be routed it calls IsKeyChordPressed() +// -> the function has (desirable) side-effects as it can prevents another call from getting the route. +// - Visualize registered routes in 'Metrics/Debugger->Inputs'. +Shortcut :: (key_chord: KeyChord, flags: InputFlags = .None) -> bool #foreign imgui "?Shortcut@ImGui@@YA_NHH@Z"; +SetNextItemShortcut :: (key_chord: KeyChord, flags: InputFlags = .None) -> void #foreign imgui "?SetNextItemShortcut@ImGui@@YAXHH@Z"; + +// Inputs Utilities: Key/Input Ownership [BETA] +// - One common use case would be to allow your items to disable standard inputs behaviors such +// as Tab or Alt key handling, Mouse Wheel scrolling, etc. +// e.g. Button(...); SetItemKeyOwner(ImGuiKey_MouseWheelY); to make hovering/activating a button disable wheel for scrolling. +// - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them. +// - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version. +SetItemKeyOwner :: (key: Key) -> void #foreign imgui "?SetItemKeyOwner@ImGui@@YAXW4ImGuiKey@@@Z"; + +// Inputs Utilities: Mouse +// - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. +// - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. +// - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') +IsMouseDown :: (button: MouseButton) -> bool #foreign imgui "?IsMouseDown@ImGui@@YA_NH@Z"; +IsMouseClicked :: (button: MouseButton, repeat := false) -> bool #foreign imgui "?IsMouseClicked@ImGui@@YA_NH_N@Z"; +IsMouseReleased :: (button: MouseButton) -> bool #foreign imgui "?IsMouseReleased@ImGui@@YA_NH@Z"; +IsMouseDoubleClicked :: (button: MouseButton) -> bool #foreign imgui "?IsMouseDoubleClicked@ImGui@@YA_NH@Z"; +IsMouseReleasedWithDelay :: (button: MouseButton, delay: float) -> bool #foreign imgui "?IsMouseReleasedWithDelay@ImGui@@YA_NHM@Z"; +GetMouseClickedCount :: (button: MouseButton) -> s32 #foreign imgui "?GetMouseClickedCount@ImGui@@YAHH@Z"; +IsMouseHoveringRect :: (r_min: *ImVec2, r_max: *ImVec2, clip := true) -> bool #foreign imgui "?IsMouseHoveringRect@ImGui@@YA_NAEBUImVec2@@0_N@Z"; +IsMouseHoveringRect :: (r_min: ImVec2, r_max: ImVec2, clip := true) -> bool #no_context { + return IsMouseHoveringRect(*r_min, *r_max, clip); +} +IsMousePosValid :: (mouse_pos: *ImVec2 = null) -> bool #foreign imgui "?IsMousePosValid@ImGui@@YA_NPEBUImVec2@@@Z"; +IsAnyMouseDown :: () -> bool #foreign imgui "?IsAnyMouseDown@ImGui@@YA_NXZ"; +GetMousePos :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetMousePos@ImGui@@YA?AUImVec2@@XZ"; +GetMousePosOnOpeningCurrentPopup :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetMousePosOnOpeningCurrentPopup@ImGui@@YA?AUImVec2@@XZ"; +IsMouseDragging :: (button: MouseButton, lock_threshold: float = -1.0) -> bool #foreign imgui "?IsMouseDragging@ImGui@@YA_NHM@Z"; +GetMouseDragDelta :: (button: MouseButton = .Left, lock_threshold: float = -1.0) -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetMouseDragDelta@ImGui@@YA?AUImVec2@@HM@Z"; +ResetMouseDragDelta :: (button: MouseButton = .Left) -> void #foreign imgui "?ResetMouseDragDelta@ImGui@@YAXH@Z"; +GetMouseCursor :: () -> MouseCursor #foreign imgui "?GetMouseCursor@ImGui@@YAHXZ"; +SetMouseCursor :: (cursor_type: MouseCursor) -> void #foreign imgui "?SetMouseCursor@ImGui@@YAXH@Z"; +SetNextFrameWantCaptureMouse :: (want_capture_mouse: bool) -> void #foreign imgui "?SetNextFrameWantCaptureMouse@ImGui@@YAX_N@Z"; + +// Clipboard Utilities +// - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. +GetClipboardText :: () -> *u8 #foreign imgui "?GetClipboardText@ImGui@@YAPEBDXZ"; +SetClipboardText :: (text: *u8) -> void #foreign imgui "?SetClipboardText@ImGui@@YAXPEBD@Z"; + +// Settings/.Ini Utilities +// - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). +// - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. +// - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables). +LoadIniSettingsFromDisk :: (ini_filename: *u8) -> void #foreign imgui "?LoadIniSettingsFromDisk@ImGui@@YAXPEBD@Z"; +LoadIniSettingsFromMemory :: (ini_data: *u8, ini_size: u64 = 0) -> void #foreign imgui "?LoadIniSettingsFromMemory@ImGui@@YAXPEBD_K@Z"; +SaveIniSettingsToDisk :: (ini_filename: *u8) -> void #foreign imgui "?SaveIniSettingsToDisk@ImGui@@YAXPEBD@Z"; +SaveIniSettingsToMemory :: (out_ini_size: *u64 = null) -> *u8 #foreign imgui "?SaveIniSettingsToMemory@ImGui@@YAPEBDPEA_K@Z"; + +// Debug Utilities +// - Your main debugging friend is the ShowMetricsWindow() function. +// - Interactive tools are all accessible from the 'Dear ImGui Demo->Tools' menu. +// - Read https://github.com/ocornut/imgui/wiki/Debug-Tools for a description of all available debug tools. +DebugTextEncoding :: (text: *u8) -> void #foreign imgui "?DebugTextEncoding@ImGui@@YAXPEBD@Z"; +DebugFlashStyleColor :: (idx: Col) -> void #foreign imgui "?DebugFlashStyleColor@ImGui@@YAXH@Z"; +DebugStartItemPicker :: () -> void #foreign imgui "?DebugStartItemPicker@ImGui@@YAXXZ"; +DebugCheckVersionAndDataLayout :: (version_str: *u8, sz_io: u64, sz_style: u64, sz_vec2: u64, sz_vec4: u64, sz_drawvert: u64, sz_drawidx: u64) -> bool #foreign imgui "?DebugCheckVersionAndDataLayout@ImGui@@YA_NPEBD_K11111@Z"; + +DebugLog_CFormat :: (fmt: *u8, __args: ..Any) -> void #foreign imgui "?DebugLog@ImGui@@YAXPEBDZZ"; +DebugLog :: (fmt: string, __args: ..Any) { + push_allocator(temp); + formatted_text_builder: String_Builder; + print_to_builder(*formatted_text_builder, fmt, ..__args); + append(*formatted_text_builder, "\0"); + formatted_text := builder_to_string(*formatted_text_builder); + DebugLog_CFormat("%s", formatted_text.data); +} @PrintLike + +// Memory Allocators +// - Those functions are not reliant on the current context. +// - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. +SetAllocatorFunctions :: (alloc_func: MemAllocFunc, free_func: MemFreeFunc, user_data: *void = null) -> void #foreign imgui "?SetAllocatorFunctions@ImGui@@YAXP6APEAX_KPEAX@ZP6AX11@Z1@Z"; +GetAllocatorFunctions :: (p_alloc_func: *MemAllocFunc, p_free_func: *MemFreeFunc, p_user_data: **void) -> void #foreign imgui "?GetAllocatorFunctions@ImGui@@YAXPEAP6APEAX_KPEAX@ZPEAP6AX11@ZPEAPEAX@Z"; +MemAlloc :: (size: u64) -> *void #foreign imgui "?MemAlloc@ImGui@@YAPEAX_K@Z"; +MemFree :: (ptr: *void) -> void #foreign imgui "?MemFree@ImGui@@YAXPEAX@Z"; + +// (Optional) Platform/OS interface for multi-viewport support +// Read comments around the ImGuiPlatformIO structure for more details. +// Note: You may use GetWindowViewport() to get the current viewport of the current window. +UpdatePlatformWindows :: () -> void #foreign imgui "?UpdatePlatformWindows@ImGui@@YAXXZ"; +RenderPlatformWindowsDefault :: (platform_render_arg: *void = null, renderer_render_arg: *void = null) -> void #foreign imgui "?RenderPlatformWindowsDefault@ImGui@@YAXPEAX0@Z"; +DestroyPlatformWindows :: () -> void #foreign imgui "?DestroyPlatformWindows@ImGui@@YAXXZ"; +FindViewportByID :: (viewport_id: ID) -> *Viewport #foreign imgui "?FindViewportByID@ImGui@@YAPEAUImGuiViewport@@I@Z"; +FindViewportByPlatformHandle :: (platform_handle: *void) -> *Viewport #foreign imgui "?FindViewportByPlatformHandle@ImGui@@YAPEAUImGuiViewport@@PEAX@Z"; + +SetWindowFontScale :: (scale: float) -> void #foreign imgui "?SetWindowFontScale@ImGui@@YAXM@Z"; + +// OBSOLETED in 1.91.9 (from February 2025) +Image :: (tex_ref: ImTextureRef, image_size: *ImVec2, uv0: *ImVec2, uv1: *ImVec2, tint_col: *ImVec4, border_col: *ImVec4) -> void #foreign imgui "?Image@ImGui@@YAXUImTextureRef@@AEBUImVec2@@11AEBUImVec4@@2@Z"; +Image :: (tex_ref: ImTextureRef, image_size: ImVec2, uv0: ImVec2, uv1: ImVec2, tint_col: ImVec4, border_col: ImVec4) #no_context { + Image(tex_ref, *image_size, *uv0, *uv1, *tint_col, *border_col); +} + +// You do not need those functions! See #7838 on GitHub for more info. +GetContentRegionMax :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetContentRegionMax@ImGui@@YA?AUImVec2@@XZ"; +GetWindowContentRegionMin :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetWindowContentRegionMin@ImGui@@YA?AUImVec2@@XZ"; +GetWindowContentRegionMax :: () -> ImVec2 #cpp_return_type_is_non_pod #foreign imgui "?GetWindowContentRegionMax@ImGui@@YA?AUImVec2@@XZ"; + +// OBSOLETED in 1.90.0 (from September 2023) +Combo :: (label: *u8, current_item: *s32, old_callback: #type (user_data: *void, idx: s32, out_text: **u8) -> bool #c_call, user_data: *void, items_count: s32, popup_max_height_in_items: s32 = -1) -> bool #foreign imgui "?Combo@ImGui@@YA_NPEBDPEAHP6A_NPEAXHPEAPEBD@Z2HH@Z"; +ListBox :: (label: *u8, current_item: *s32, old_callback: #type (user_data: *void, idx: s32, out_text: **u8) -> bool #c_call, user_data: *void, items_count: s32, height_in_items: s32 = -1) -> bool #foreign imgui "?ListBox@ImGui@@YA_NPEBDPEAHP6A_NPEAXHPEAPEBD@Z2HH@Z"; + +// Flags for ImGui::Begin() +// (Those are per-window flags. There are shared flags in ImGuiIO: io.ConfigWindowsResizeFromEdges and io.ConfigWindowsMoveFromTitleBarOnly) +WindowFlags :: enum_flags s32 { + None :: 0x0; + NoTitleBar :: 0x1; + NoResize :: 0x2; + NoMove :: 0x4; + NoScrollbar :: 0x8; + NoScrollWithMouse :: 0x10; + NoCollapse :: 0x20; + AlwaysAutoResize :: 0x40; + NoBackground :: 0x80; + NoSavedSettings :: 0x100; + NoMouseInputs :: 0x200; + MenuBar :: 0x400; + HorizontalScrollbar :: 0x800; + NoFocusOnAppearing :: 0x1000; + NoBringToFrontOnFocus :: 0x2000; + AlwaysVerticalScrollbar :: 0x4000; + AlwaysHorizontalScrollbar :: 0x8000; + NoNavInputs :: 0x10000; + NoNavFocus :: 0x20000; + UnsavedDocument :: 0x40000; + NoDocking :: 0x80000; + NoNav :: 0x30000; + NoDecoration :: 0x2b; + NoInputs :: 0x30200; + + DockNodeHost :: 0x800000; + ChildWindow :: 0x1000000; + Tooltip :: 0x2000000; + Popup :: 0x4000000; + Modal :: 0x8000000; + ChildMenu :: 0x10000000; + + ImGuiWindowFlags_None :: None; + ImGuiWindowFlags_NoTitleBar :: NoTitleBar; + ImGuiWindowFlags_NoResize :: NoResize; + ImGuiWindowFlags_NoMove :: NoMove; + ImGuiWindowFlags_NoScrollbar :: NoScrollbar; + ImGuiWindowFlags_NoScrollWithMouse :: NoScrollWithMouse; + ImGuiWindowFlags_NoCollapse :: NoCollapse; + ImGuiWindowFlags_AlwaysAutoResize :: AlwaysAutoResize; + ImGuiWindowFlags_NoBackground :: NoBackground; + ImGuiWindowFlags_NoSavedSettings :: NoSavedSettings; + ImGuiWindowFlags_NoMouseInputs :: NoMouseInputs; + ImGuiWindowFlags_MenuBar :: MenuBar; + ImGuiWindowFlags_HorizontalScrollbar :: HorizontalScrollbar; + ImGuiWindowFlags_NoFocusOnAppearing :: NoFocusOnAppearing; + ImGuiWindowFlags_NoBringToFrontOnFocus :: NoBringToFrontOnFocus; + ImGuiWindowFlags_AlwaysVerticalScrollbar :: AlwaysVerticalScrollbar; + ImGuiWindowFlags_AlwaysHorizontalScrollbar :: AlwaysHorizontalScrollbar; + ImGuiWindowFlags_NoNavInputs :: NoNavInputs; + ImGuiWindowFlags_NoNavFocus :: NoNavFocus; + ImGuiWindowFlags_UnsavedDocument :: UnsavedDocument; + ImGuiWindowFlags_NoDocking :: NoDocking; + ImGuiWindowFlags_NoNav :: NoNav; + ImGuiWindowFlags_NoDecoration :: NoDecoration; + ImGuiWindowFlags_NoInputs :: NoInputs; + + ImGuiWindowFlags_DockNodeHost :: DockNodeHost; + ImGuiWindowFlags_ChildWindow :: ChildWindow; + ImGuiWindowFlags_Tooltip :: Tooltip; + ImGuiWindowFlags_Popup :: Popup; + ImGuiWindowFlags_Modal :: Modal; + ImGuiWindowFlags_ChildMenu :: ChildMenu; +} + +// Flags for ImGui::BeginChild() +// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Borders to be backward compatible with old API using 'bool border = false'.) +// About using AutoResizeX/AutoResizeY flags: +// - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see "Demo->Child->Auto-resize with Constraints"). +// - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing. +// - This allows BeginChild() to return false when not within boundaries (e.g. when scrolling), which is more optimal. BUT it won't update its auto-size while clipped. +// While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the occasional "resizing after becoming visible again" glitch. +// - You may also use ImGuiChildFlags_AlwaysAutoResize to force an update even when child window is not in view. +// HOWEVER PLEASE UNDERSTAND THAT DOING SO WILL PREVENT BeginChild() FROM EVER RETURNING FALSE, disabling benefits of coarse clipping. +ChildFlags :: enum_flags s32 { + None :: 0x0; + Borders :: 0x1; + AlwaysUseWindowPadding :: 0x2; + ResizeX :: 0x4; + ResizeY :: 0x8; + AutoResizeX :: 0x10; + AutoResizeY :: 0x20; + AlwaysAutoResize :: 0x40; + FrameStyle :: 0x80; + NavFlattened :: 0x100; + + ImGuiChildFlags_None :: None; + ImGuiChildFlags_Borders :: Borders; + ImGuiChildFlags_AlwaysUseWindowPadding :: AlwaysUseWindowPadding; + ImGuiChildFlags_ResizeX :: ResizeX; + ImGuiChildFlags_ResizeY :: ResizeY; + ImGuiChildFlags_AutoResizeX :: AutoResizeX; + ImGuiChildFlags_AutoResizeY :: AutoResizeY; + ImGuiChildFlags_AlwaysAutoResize :: AlwaysAutoResize; + ImGuiChildFlags_FrameStyle :: FrameStyle; + ImGuiChildFlags_NavFlattened :: NavFlattened; +} + +// Flags for ImGui::PushItemFlag() +// (Those are shared by all submitted items) +ItemFlags :: enum_flags s32 { + None :: 0x0; + NoTabStop :: 0x1; + NoNav :: 0x2; + NoNavDefaultFocus :: 0x4; + ButtonRepeat :: 0x8; + AutoClosePopups :: 0x10; + AllowDuplicateId :: 0x20; + Disabled :: 0x40; + + ImGuiItemFlags_None :: None; + ImGuiItemFlags_NoTabStop :: NoTabStop; + ImGuiItemFlags_NoNav :: NoNav; + ImGuiItemFlags_NoNavDefaultFocus :: NoNavDefaultFocus; + ImGuiItemFlags_ButtonRepeat :: ButtonRepeat; + ImGuiItemFlags_AutoClosePopups :: AutoClosePopups; + ImGuiItemFlags_AllowDuplicateId :: AllowDuplicateId; + ImGuiItemFlags_Disabled :: Disabled; +} + +// Flags for ImGui::InputText() +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive) +InputTextFlags :: enum_flags s32 { + None :: 0x0; + CharsDecimal :: 0x1; + CharsHexadecimal :: 0x2; + CharsScientific :: 0x4; + CharsUppercase :: 0x8; + CharsNoBlank :: 0x10; + + AllowTabInput :: 0x20; + EnterReturnsTrue :: 0x40; + EscapeClearsAll :: 0x80; + CtrlEnterForNewLine :: 0x100; + + ReadOnly :: 0x200; + Password :: 0x400; + AlwaysOverwrite :: 0x800; + AutoSelectAll :: 0x1000; + ParseEmptyRefVal :: 0x2000; + DisplayEmptyRefVal :: 0x4000; + NoHorizontalScroll :: 0x8000; + NoUndoRedo :: 0x10000; + + ElideLeft :: 0x20000; + + CallbackCompletion :: 0x40000; + CallbackHistory :: 0x80000; + CallbackAlways :: 0x100000; + CallbackCharFilter :: 0x200000; + CallbackResize :: 0x400000; + CallbackEdit :: 0x800000; + + WordWrap :: 0x1000000; + + ImGuiInputTextFlags_None :: None; + ImGuiInputTextFlags_CharsDecimal :: CharsDecimal; + ImGuiInputTextFlags_CharsHexadecimal :: CharsHexadecimal; + ImGuiInputTextFlags_CharsScientific :: CharsScientific; + ImGuiInputTextFlags_CharsUppercase :: CharsUppercase; + ImGuiInputTextFlags_CharsNoBlank :: CharsNoBlank; + + ImGuiInputTextFlags_AllowTabInput :: AllowTabInput; + ImGuiInputTextFlags_EnterReturnsTrue :: EnterReturnsTrue; + ImGuiInputTextFlags_EscapeClearsAll :: EscapeClearsAll; + ImGuiInputTextFlags_CtrlEnterForNewLine :: CtrlEnterForNewLine; + + ImGuiInputTextFlags_ReadOnly :: ReadOnly; + ImGuiInputTextFlags_Password :: Password; + ImGuiInputTextFlags_AlwaysOverwrite :: AlwaysOverwrite; + ImGuiInputTextFlags_AutoSelectAll :: AutoSelectAll; + ImGuiInputTextFlags_ParseEmptyRefVal :: ParseEmptyRefVal; + ImGuiInputTextFlags_DisplayEmptyRefVal :: DisplayEmptyRefVal; + ImGuiInputTextFlags_NoHorizontalScroll :: NoHorizontalScroll; + ImGuiInputTextFlags_NoUndoRedo :: NoUndoRedo; + + ImGuiInputTextFlags_ElideLeft :: ElideLeft; + + ImGuiInputTextFlags_CallbackCompletion :: CallbackCompletion; + ImGuiInputTextFlags_CallbackHistory :: CallbackHistory; + ImGuiInputTextFlags_CallbackAlways :: CallbackAlways; + ImGuiInputTextFlags_CallbackCharFilter :: CallbackCharFilter; + ImGuiInputTextFlags_CallbackResize :: CallbackResize; + ImGuiInputTextFlags_CallbackEdit :: CallbackEdit; + + ImGuiInputTextFlags_WordWrap :: WordWrap; +} + +// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() +TreeNodeFlags :: enum_flags s32 { + None :: 0x0; + Selected :: 0x1; + Framed :: 0x2; + AllowOverlap :: 0x4; + NoTreePushOnOpen :: 0x8; + NoAutoOpenOnLog :: 0x10; + DefaultOpen :: 0x20; + OpenOnDoubleClick :: 0x40; + OpenOnArrow :: 0x80; + Leaf :: 0x100; + Bullet :: 0x200; + FramePadding :: 0x400; + SpanAvailWidth :: 0x800; + SpanFullWidth :: 0x1000; + SpanLabelWidth :: 0x2000; + SpanAllColumns :: 0x4000; + LabelSpanAllColumns :: 0x8000; + + NavLeftJumpsToParent :: 0x20000; + CollapsingHeader :: 0x1a; + + DrawLinesNone :: 0x40000; + DrawLinesFull :: 0x80000; + DrawLinesToNodes :: 0x100000; + + NavLeftJumpsBackHere :: 0x20000; + SpanTextWidth :: 0x2000; + + ImGuiTreeNodeFlags_None :: None; + ImGuiTreeNodeFlags_Selected :: Selected; + ImGuiTreeNodeFlags_Framed :: Framed; + ImGuiTreeNodeFlags_AllowOverlap :: AllowOverlap; + ImGuiTreeNodeFlags_NoTreePushOnOpen :: NoTreePushOnOpen; + ImGuiTreeNodeFlags_NoAutoOpenOnLog :: NoAutoOpenOnLog; + ImGuiTreeNodeFlags_DefaultOpen :: DefaultOpen; + ImGuiTreeNodeFlags_OpenOnDoubleClick :: OpenOnDoubleClick; + ImGuiTreeNodeFlags_OpenOnArrow :: OpenOnArrow; + ImGuiTreeNodeFlags_Leaf :: Leaf; + ImGuiTreeNodeFlags_Bullet :: Bullet; + ImGuiTreeNodeFlags_FramePadding :: FramePadding; + ImGuiTreeNodeFlags_SpanAvailWidth :: SpanAvailWidth; + ImGuiTreeNodeFlags_SpanFullWidth :: SpanFullWidth; + ImGuiTreeNodeFlags_SpanLabelWidth :: SpanLabelWidth; + ImGuiTreeNodeFlags_SpanAllColumns :: SpanAllColumns; + ImGuiTreeNodeFlags_LabelSpanAllColumns :: LabelSpanAllColumns; + + ImGuiTreeNodeFlags_NavLeftJumpsToParent :: NavLeftJumpsToParent; + ImGuiTreeNodeFlags_CollapsingHeader :: CollapsingHeader; + + ImGuiTreeNodeFlags_DrawLinesNone :: DrawLinesNone; + ImGuiTreeNodeFlags_DrawLinesFull :: DrawLinesFull; + ImGuiTreeNodeFlags_DrawLinesToNodes :: DrawLinesToNodes; + + ImGuiTreeNodeFlags_NavLeftJumpsBackHere :: NavLeftJumpsBackHere; + ImGuiTreeNodeFlags_SpanTextWidth :: SpanTextWidth; +} + +// Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. +// - IMPORTANT: If you ever used the left mouse button with BeginPopupContextXXX() helpers before 1.92.6: Read "API BREAKING CHANGES" 2026/01/07 (1.92.6) entry in imgui.cpp or GitHub topic #9157. +// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). +PopupFlags :: enum_flags s32 { + None :: 0x0; + MouseButtonLeft :: 0x4; + MouseButtonRight :: 0x8; + MouseButtonMiddle :: 0xc; + NoReopen :: 0x20; + + NoOpenOverExistingPopup :: 0x80; + NoOpenOverItems :: 0x100; + AnyPopupId :: 0x400; + AnyPopupLevel :: 0x800; + AnyPopup :: 0xc00; + MouseButtonShift_ :: 0x2; + MouseButtonMask_ :: 0xc; + InvalidMask_ :: 0x3; + + ImGuiPopupFlags_None :: None; + ImGuiPopupFlags_MouseButtonLeft :: MouseButtonLeft; + ImGuiPopupFlags_MouseButtonRight :: MouseButtonRight; + ImGuiPopupFlags_MouseButtonMiddle :: MouseButtonMiddle; + ImGuiPopupFlags_NoReopen :: NoReopen; + + ImGuiPopupFlags_NoOpenOverExistingPopup :: NoOpenOverExistingPopup; + ImGuiPopupFlags_NoOpenOverItems :: NoOpenOverItems; + ImGuiPopupFlags_AnyPopupId :: AnyPopupId; + ImGuiPopupFlags_AnyPopupLevel :: AnyPopupLevel; + ImGuiPopupFlags_AnyPopup :: AnyPopup; + ImGuiPopupFlags_MouseButtonShift_ :: MouseButtonShift_; + ImGuiPopupFlags_MouseButtonMask_ :: MouseButtonMask_; + ImGuiPopupFlags_InvalidMask_ :: InvalidMask_; +} + +// Flags for ImGui::Selectable() +SelectableFlags :: enum_flags s32 { + None :: 0x0; + NoAutoClosePopups :: 0x1; + SpanAllColumns :: 0x2; + AllowDoubleClick :: 0x4; + Disabled :: 0x8; + AllowOverlap :: 0x10; + Highlight :: 0x20; + SelectOnNav :: 0x40; + + DontClosePopups :: 0x1; + + ImGuiSelectableFlags_None :: None; + ImGuiSelectableFlags_NoAutoClosePopups :: NoAutoClosePopups; + ImGuiSelectableFlags_SpanAllColumns :: SpanAllColumns; + ImGuiSelectableFlags_AllowDoubleClick :: AllowDoubleClick; + ImGuiSelectableFlags_Disabled :: Disabled; + ImGuiSelectableFlags_AllowOverlap :: AllowOverlap; + ImGuiSelectableFlags_Highlight :: Highlight; + ImGuiSelectableFlags_SelectOnNav :: SelectOnNav; + + ImGuiSelectableFlags_DontClosePopups :: DontClosePopups; +} + +// Flags for ImGui::BeginCombo() +ComboFlags :: enum_flags s32 { + None :: 0x0; + PopupAlignLeft :: 0x1; + HeightSmall :: 0x2; + HeightRegular :: 0x4; + HeightLarge :: 0x8; + HeightLargest :: 0x10; + NoArrowButton :: 0x20; + NoPreview :: 0x40; + WidthFitPreview :: 0x80; + HeightMask_ :: 0x1e; + + ImGuiComboFlags_None :: None; + ImGuiComboFlags_PopupAlignLeft :: PopupAlignLeft; + ImGuiComboFlags_HeightSmall :: HeightSmall; + ImGuiComboFlags_HeightRegular :: HeightRegular; + ImGuiComboFlags_HeightLarge :: HeightLarge; + ImGuiComboFlags_HeightLargest :: HeightLargest; + ImGuiComboFlags_NoArrowButton :: NoArrowButton; + ImGuiComboFlags_NoPreview :: NoPreview; + ImGuiComboFlags_WidthFitPreview :: WidthFitPreview; + ImGuiComboFlags_HeightMask_ :: HeightMask_; +} + +// Flags for ImGui::BeginTabBar() +TabBarFlags :: enum_flags s32 { + None :: 0x0; + Reorderable :: 0x1; + AutoSelectNewTabs :: 0x2; + TabListPopupButton :: 0x4; + NoCloseWithMiddleMouseButton :: 0x8; + NoTabListScrollingButtons :: 0x10; + NoTooltip :: 0x20; + DrawSelectedOverline :: 0x40; + + FittingPolicyMixed :: 0x80; + FittingPolicyShrink :: 0x100; + FittingPolicyScroll :: 0x200; + FittingPolicyMask_ :: 0x380; + FittingPolicyDefault_ :: 0x80; + + FittingPolicyResizeDown :: 0x100; + + ImGuiTabBarFlags_None :: None; + ImGuiTabBarFlags_Reorderable :: Reorderable; + ImGuiTabBarFlags_AutoSelectNewTabs :: AutoSelectNewTabs; + ImGuiTabBarFlags_TabListPopupButton :: TabListPopupButton; + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton :: NoCloseWithMiddleMouseButton; + ImGuiTabBarFlags_NoTabListScrollingButtons :: NoTabListScrollingButtons; + ImGuiTabBarFlags_NoTooltip :: NoTooltip; + ImGuiTabBarFlags_DrawSelectedOverline :: DrawSelectedOverline; + + ImGuiTabBarFlags_FittingPolicyMixed :: FittingPolicyMixed; + ImGuiTabBarFlags_FittingPolicyShrink :: FittingPolicyShrink; + ImGuiTabBarFlags_FittingPolicyScroll :: FittingPolicyScroll; + ImGuiTabBarFlags_FittingPolicyMask_ :: FittingPolicyMask_; + ImGuiTabBarFlags_FittingPolicyDefault_ :: FittingPolicyDefault_; + + ImGuiTabBarFlags_FittingPolicyResizeDown :: FittingPolicyResizeDown; +} + +// Flags for ImGui::BeginTabItem() +TabItemFlags :: enum_flags s32 { + None :: 0x0; + UnsavedDocument :: 0x1; + SetSelected :: 0x2; + NoCloseWithMiddleMouseButton :: 0x4; + NoPushId :: 0x8; + NoTooltip :: 0x10; + NoReorder :: 0x20; + Leading :: 0x40; + Trailing :: 0x80; + NoAssumedClosure :: 0x100; + + ImGuiTabItemFlags_None :: None; + ImGuiTabItemFlags_UnsavedDocument :: UnsavedDocument; + ImGuiTabItemFlags_SetSelected :: SetSelected; + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton :: NoCloseWithMiddleMouseButton; + ImGuiTabItemFlags_NoPushId :: NoPushId; + ImGuiTabItemFlags_NoTooltip :: NoTooltip; + ImGuiTabItemFlags_NoReorder :: NoReorder; + ImGuiTabItemFlags_Leading :: Leading; + ImGuiTabItemFlags_Trailing :: Trailing; + ImGuiTabItemFlags_NoAssumedClosure :: NoAssumedClosure; +} + +// Flags for ImGui::IsWindowFocused() +FocusedFlags :: enum_flags s32 { + None :: 0x0; + ChildWindows :: 0x1; + RootWindow :: 0x2; + AnyWindow :: 0x4; + NoPopupHierarchy :: 0x8; + DockHierarchy :: 0x10; + RootAndChildWindows :: 0x3; + + ImGuiFocusedFlags_None :: None; + ImGuiFocusedFlags_ChildWindows :: ChildWindows; + ImGuiFocusedFlags_RootWindow :: RootWindow; + ImGuiFocusedFlags_AnyWindow :: AnyWindow; + ImGuiFocusedFlags_NoPopupHierarchy :: NoPopupHierarchy; + ImGuiFocusedFlags_DockHierarchy :: DockHierarchy; + ImGuiFocusedFlags_RootAndChildWindows :: RootAndChildWindows; +} + +// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() +// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! +// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. +HoveredFlags :: enum_flags s32 { + None :: 0x0; + ChildWindows :: 0x1; + RootWindow :: 0x2; + AnyWindow :: 0x4; + NoPopupHierarchy :: 0x8; + DockHierarchy :: 0x10; + AllowWhenBlockedByPopup :: 0x20; + + AllowWhenBlockedByActiveItem :: 0x80; + AllowWhenOverlappedByItem :: 0x100; + AllowWhenOverlappedByWindow :: 0x200; + AllowWhenDisabled :: 0x400; + NoNavOverride :: 0x800; + AllowWhenOverlapped :: 0x300; + RectOnly :: 0x3a0; + RootAndChildWindows :: 0x3; + + ForTooltip :: 0x1000; + + Stationary :: 0x2000; + DelayNone :: 0x4000; + DelayShort :: 0x8000; + DelayNormal :: 0x10000; + NoSharedDelay :: 0x20000; + + ImGuiHoveredFlags_None :: None; + ImGuiHoveredFlags_ChildWindows :: ChildWindows; + ImGuiHoveredFlags_RootWindow :: RootWindow; + ImGuiHoveredFlags_AnyWindow :: AnyWindow; + ImGuiHoveredFlags_NoPopupHierarchy :: NoPopupHierarchy; + ImGuiHoveredFlags_DockHierarchy :: DockHierarchy; + ImGuiHoveredFlags_AllowWhenBlockedByPopup :: AllowWhenBlockedByPopup; + + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem :: AllowWhenBlockedByActiveItem; + ImGuiHoveredFlags_AllowWhenOverlappedByItem :: AllowWhenOverlappedByItem; + ImGuiHoveredFlags_AllowWhenOverlappedByWindow :: AllowWhenOverlappedByWindow; + ImGuiHoveredFlags_AllowWhenDisabled :: AllowWhenDisabled; + ImGuiHoveredFlags_NoNavOverride :: NoNavOverride; + ImGuiHoveredFlags_AllowWhenOverlapped :: AllowWhenOverlapped; + ImGuiHoveredFlags_RectOnly :: RectOnly; + ImGuiHoveredFlags_RootAndChildWindows :: RootAndChildWindows; + + ImGuiHoveredFlags_ForTooltip :: ForTooltip; + + ImGuiHoveredFlags_Stationary :: Stationary; + ImGuiHoveredFlags_DelayNone :: DelayNone; + ImGuiHoveredFlags_DelayShort :: DelayShort; + ImGuiHoveredFlags_DelayNormal :: DelayNormal; + ImGuiHoveredFlags_NoSharedDelay :: NoSharedDelay; +} + +// Flags for ImGui::DockSpace(), shared/inherited by child nodes. +// (Some flags can be applied to individual nodes directly) +// FIXME-DOCK: Also see ImGuiDockNodeFlagsPrivate_ which may involve using the WIP and internal DockBuilder api. +DockNodeFlags :: enum_flags s32 { + None :: 0x0; + KeepAliveOnly :: 0x1; + + NoDockingOverCentralNode :: 0x4; + PassthruCentralNode :: 0x8; + NoDockingSplit :: 0x10; + NoResize :: 0x20; + AutoHideTabBar :: 0x40; + NoUndocking :: 0x80; + + NoSplit :: 0x10; + NoDockingInCentralNode :: 0x4; + + ImGuiDockNodeFlags_None :: None; + ImGuiDockNodeFlags_KeepAliveOnly :: KeepAliveOnly; + + ImGuiDockNodeFlags_NoDockingOverCentralNode :: NoDockingOverCentralNode; + ImGuiDockNodeFlags_PassthruCentralNode :: PassthruCentralNode; + ImGuiDockNodeFlags_NoDockingSplit :: NoDockingSplit; + ImGuiDockNodeFlags_NoResize :: NoResize; + ImGuiDockNodeFlags_AutoHideTabBar :: AutoHideTabBar; + ImGuiDockNodeFlags_NoUndocking :: NoUndocking; + + ImGuiDockNodeFlags_NoSplit :: NoSplit; + ImGuiDockNodeFlags_NoDockingInCentralNode :: NoDockingInCentralNode; +} + +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +DragDropFlags :: enum_flags s32 { + None :: 0x0; + + SourceNoPreviewTooltip :: 0x1; + SourceNoDisableHover :: 0x2; + SourceNoHoldToOpenOthers :: 0x4; + SourceAllowNullID :: 0x8; + SourceExtern :: 0x10; + PayloadAutoExpire :: 0x20; + PayloadNoCrossContext :: 0x40; + PayloadNoCrossProcess :: 0x80; + + AcceptBeforeDelivery :: 0x400; + AcceptNoDrawDefaultRect :: 0x800; + AcceptNoPreviewTooltip :: 0x1000; + AcceptDrawAsHovered :: 0x2000; + AcceptPeekOnly :: 0xc00; + + SourceAutoExpirePayload :: 0x20; + + ImGuiDragDropFlags_None :: None; + + ImGuiDragDropFlags_SourceNoPreviewTooltip :: SourceNoPreviewTooltip; + ImGuiDragDropFlags_SourceNoDisableHover :: SourceNoDisableHover; + ImGuiDragDropFlags_SourceNoHoldToOpenOthers :: SourceNoHoldToOpenOthers; + ImGuiDragDropFlags_SourceAllowNullID :: SourceAllowNullID; + ImGuiDragDropFlags_SourceExtern :: SourceExtern; + ImGuiDragDropFlags_PayloadAutoExpire :: PayloadAutoExpire; + ImGuiDragDropFlags_PayloadNoCrossContext :: PayloadNoCrossContext; + ImGuiDragDropFlags_PayloadNoCrossProcess :: PayloadNoCrossProcess; + + ImGuiDragDropFlags_AcceptBeforeDelivery :: AcceptBeforeDelivery; + ImGuiDragDropFlags_AcceptNoDrawDefaultRect :: AcceptNoDrawDefaultRect; + ImGuiDragDropFlags_AcceptNoPreviewTooltip :: AcceptNoPreviewTooltip; + ImGuiDragDropFlags_AcceptDrawAsHovered :: AcceptDrawAsHovered; + ImGuiDragDropFlags_AcceptPeekOnly :: AcceptPeekOnly; + + ImGuiDragDropFlags_SourceAutoExpirePayload :: SourceAutoExpirePayload; +} + +// A primary data type +DataType :: enum s32 { + S8 :: 0; + U8 :: 1; + S16 :: 2; + U16 :: 3; + S32 :: 4; + U32 :: 5; + S64 :: 6; + U64 :: 7; + Float :: 8; + Double :: 9; + Bool :: 10; + String :: 11; + COUNT :: 12; + + ImGuiDataType_S8 :: S8; + ImGuiDataType_U8 :: U8; + ImGuiDataType_S16 :: S16; + ImGuiDataType_U16 :: U16; + ImGuiDataType_S32 :: S32; + ImGuiDataType_U32 :: U32; + ImGuiDataType_S64 :: S64; + ImGuiDataType_U64 :: U64; + ImGuiDataType_Float :: Float; + ImGuiDataType_Double :: Double; + ImGuiDataType_Bool :: Bool; + ImGuiDataType_String :: String; + ImGuiDataType_COUNT :: COUNT; +} + +// Flags for Shortcut(), SetNextItemShortcut(), +// (and for upcoming extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner() that are still in imgui_internal.h) +// Don't mistake with ImGuiInputTextFlags! (which is for ImGui::InputText() function) +InputFlags :: enum_flags s32 { + None :: 0x0; + Repeat :: 0x1; + + RouteActive :: 0x400; + RouteFocused :: 0x800; + RouteGlobal :: 0x1000; + RouteAlways :: 0x2000; + + RouteOverFocused :: 0x4000; + RouteOverActive :: 0x8000; + RouteUnlessBgFocused :: 0x10000; + RouteFromRootWindow :: 0x20000; + + Tooltip :: 0x40000; + + ImGuiInputFlags_None :: None; + ImGuiInputFlags_Repeat :: Repeat; + + ImGuiInputFlags_RouteActive :: RouteActive; + ImGuiInputFlags_RouteFocused :: RouteFocused; + ImGuiInputFlags_RouteGlobal :: RouteGlobal; + ImGuiInputFlags_RouteAlways :: RouteAlways; + + ImGuiInputFlags_RouteOverFocused :: RouteOverFocused; + ImGuiInputFlags_RouteOverActive :: RouteOverActive; + ImGuiInputFlags_RouteUnlessBgFocused :: RouteUnlessBgFocused; + ImGuiInputFlags_RouteFromRootWindow :: RouteFromRootWindow; + + ImGuiInputFlags_Tooltip :: Tooltip; +} + +// Configuration flags stored in io.ConfigFlags. Set by user/application. +ConfigFlags :: enum_flags s32 { + None :: 0x0; + NavEnableKeyboard :: 0x1; + NavEnableGamepad :: 0x2; + NoMouse :: 0x10; + NoMouseCursorChange :: 0x20; + NoKeyboard :: 0x40; + + DockingEnable :: 0x80; + + ViewportsEnable :: 0x400; + + IsSRGB :: 0x100000; + IsTouchScreen :: 0x200000; + + NavEnableSetMousePos :: 0x4; + NavNoCaptureKeyboard :: 0x8; + DpiEnableScaleFonts :: 0x4000; + DpiEnableScaleViewports :: 0x8000; + + ImGuiConfigFlags_None :: None; + ImGuiConfigFlags_NavEnableKeyboard :: NavEnableKeyboard; + ImGuiConfigFlags_NavEnableGamepad :: NavEnableGamepad; + ImGuiConfigFlags_NoMouse :: NoMouse; + ImGuiConfigFlags_NoMouseCursorChange :: NoMouseCursorChange; + ImGuiConfigFlags_NoKeyboard :: NoKeyboard; + + ImGuiConfigFlags_DockingEnable :: DockingEnable; + + ImGuiConfigFlags_ViewportsEnable :: ViewportsEnable; + + ImGuiConfigFlags_IsSRGB :: IsSRGB; + ImGuiConfigFlags_IsTouchScreen :: IsTouchScreen; + + ImGuiConfigFlags_NavEnableSetMousePos :: NavEnableSetMousePos; + ImGuiConfigFlags_NavNoCaptureKeyboard :: NavNoCaptureKeyboard; + ImGuiConfigFlags_DpiEnableScaleFonts :: DpiEnableScaleFonts; + ImGuiConfigFlags_DpiEnableScaleViewports :: DpiEnableScaleViewports; +} + +// Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend. +BackendFlags :: enum_flags s32 { + None :: 0x0; + HasGamepad :: 0x1; + HasMouseCursors :: 0x2; + HasSetMousePos :: 0x4; + RendererHasVtxOffset :: 0x8; + RendererHasTextures :: 0x10; + + RendererHasViewports :: 0x400; + PlatformHasViewports :: 0x800; + HasMouseHoveredViewport :: 0x1000; + HasParentViewport :: 0x2000; + + ImGuiBackendFlags_None :: None; + ImGuiBackendFlags_HasGamepad :: HasGamepad; + ImGuiBackendFlags_HasMouseCursors :: HasMouseCursors; + ImGuiBackendFlags_HasSetMousePos :: HasSetMousePos; + ImGuiBackendFlags_RendererHasVtxOffset :: RendererHasVtxOffset; + ImGuiBackendFlags_RendererHasTextures :: RendererHasTextures; + + ImGuiBackendFlags_RendererHasViewports :: RendererHasViewports; + ImGuiBackendFlags_PlatformHasViewports :: PlatformHasViewports; + ImGuiBackendFlags_HasMouseHoveredViewport :: HasMouseHoveredViewport; + ImGuiBackendFlags_HasParentViewport :: HasParentViewport; +} + +// Enumeration for PushStyleColor() / PopStyleColor() +Col :: enum s32 { + Text :: 0; + TextDisabled :: 1; + WindowBg :: 2; + ChildBg :: 3; + PopupBg :: 4; + Border :: 5; + BorderShadow :: 6; + FrameBg :: 7; + FrameBgHovered :: 8; + FrameBgActive :: 9; + TitleBg :: 10; + TitleBgActive :: 11; + TitleBgCollapsed :: 12; + MenuBarBg :: 13; + ScrollbarBg :: 14; + ScrollbarGrab :: 15; + ScrollbarGrabHovered :: 16; + ScrollbarGrabActive :: 17; + CheckMark :: 18; + SliderGrab :: 19; + SliderGrabActive :: 20; + Button :: 21; + ButtonHovered :: 22; + ButtonActive :: 23; + Header :: 24; + HeaderHovered :: 25; + HeaderActive :: 26; + Separator :: 27; + SeparatorHovered :: 28; + SeparatorActive :: 29; + ResizeGrip :: 30; + ResizeGripHovered :: 31; + ResizeGripActive :: 32; + InputTextCursor :: 33; + TabHovered :: 34; + Tab :: 35; + TabSelected :: 36; + TabSelectedOverline :: 37; + TabDimmed :: 38; + TabDimmedSelected :: 39; + TabDimmedSelectedOverline :: 40; + DockingPreview :: 41; + DockingEmptyBg :: 42; + PlotLines :: 43; + PlotLinesHovered :: 44; + PlotHistogram :: 45; + PlotHistogramHovered :: 46; + TableHeaderBg :: 47; + TableBorderStrong :: 48; + TableBorderLight :: 49; + TableRowBg :: 50; + TableRowBgAlt :: 51; + TextLink :: 52; + TextSelectedBg :: 53; + TreeLines :: 54; + DragDropTarget :: 55; + DragDropTargetBg :: 56; + UnsavedMarker :: 57; + NavCursor :: 58; + NavWindowingHighlight :: 59; + NavWindowingDimBg :: 60; + ModalWindowDimBg :: 61; + COUNT :: 62; + + TabActive :: 36; + TabUnfocused :: 38; + TabUnfocusedActive :: 39; + NavHighlight :: 58; + + ImGuiCol_Text :: Text; + ImGuiCol_TextDisabled :: TextDisabled; + ImGuiCol_WindowBg :: WindowBg; + ImGuiCol_ChildBg :: ChildBg; + ImGuiCol_PopupBg :: PopupBg; + ImGuiCol_Border :: Border; + ImGuiCol_BorderShadow :: BorderShadow; + ImGuiCol_FrameBg :: FrameBg; + ImGuiCol_FrameBgHovered :: FrameBgHovered; + ImGuiCol_FrameBgActive :: FrameBgActive; + ImGuiCol_TitleBg :: TitleBg; + ImGuiCol_TitleBgActive :: TitleBgActive; + ImGuiCol_TitleBgCollapsed :: TitleBgCollapsed; + ImGuiCol_MenuBarBg :: MenuBarBg; + ImGuiCol_ScrollbarBg :: ScrollbarBg; + ImGuiCol_ScrollbarGrab :: ScrollbarGrab; + ImGuiCol_ScrollbarGrabHovered :: ScrollbarGrabHovered; + ImGuiCol_ScrollbarGrabActive :: ScrollbarGrabActive; + ImGuiCol_CheckMark :: CheckMark; + ImGuiCol_SliderGrab :: SliderGrab; + ImGuiCol_SliderGrabActive :: SliderGrabActive; + ImGuiCol_Button :: Button; + ImGuiCol_ButtonHovered :: ButtonHovered; + ImGuiCol_ButtonActive :: ButtonActive; + ImGuiCol_Header :: Header; + ImGuiCol_HeaderHovered :: HeaderHovered; + ImGuiCol_HeaderActive :: HeaderActive; + ImGuiCol_Separator :: Separator; + ImGuiCol_SeparatorHovered :: SeparatorHovered; + ImGuiCol_SeparatorActive :: SeparatorActive; + ImGuiCol_ResizeGrip :: ResizeGrip; + ImGuiCol_ResizeGripHovered :: ResizeGripHovered; + ImGuiCol_ResizeGripActive :: ResizeGripActive; + ImGuiCol_InputTextCursor :: InputTextCursor; + ImGuiCol_TabHovered :: TabHovered; + ImGuiCol_Tab :: Tab; + ImGuiCol_TabSelected :: TabSelected; + ImGuiCol_TabSelectedOverline :: TabSelectedOverline; + ImGuiCol_TabDimmed :: TabDimmed; + ImGuiCol_TabDimmedSelected :: TabDimmedSelected; + ImGuiCol_TabDimmedSelectedOverline :: TabDimmedSelectedOverline; + ImGuiCol_DockingPreview :: DockingPreview; + ImGuiCol_DockingEmptyBg :: DockingEmptyBg; + ImGuiCol_PlotLines :: PlotLines; + ImGuiCol_PlotLinesHovered :: PlotLinesHovered; + ImGuiCol_PlotHistogram :: PlotHistogram; + ImGuiCol_PlotHistogramHovered :: PlotHistogramHovered; + ImGuiCol_TableHeaderBg :: TableHeaderBg; + ImGuiCol_TableBorderStrong :: TableBorderStrong; + ImGuiCol_TableBorderLight :: TableBorderLight; + ImGuiCol_TableRowBg :: TableRowBg; + ImGuiCol_TableRowBgAlt :: TableRowBgAlt; + ImGuiCol_TextLink :: TextLink; + ImGuiCol_TextSelectedBg :: TextSelectedBg; + ImGuiCol_TreeLines :: TreeLines; + ImGuiCol_DragDropTarget :: DragDropTarget; + ImGuiCol_DragDropTargetBg :: DragDropTargetBg; + ImGuiCol_UnsavedMarker :: UnsavedMarker; + ImGuiCol_NavCursor :: NavCursor; + ImGuiCol_NavWindowingHighlight :: NavWindowingHighlight; + ImGuiCol_NavWindowingDimBg :: NavWindowingDimBg; + ImGuiCol_ModalWindowDimBg :: ModalWindowDimBg; + ImGuiCol_COUNT :: COUNT; + + ImGuiCol_TabActive :: TabActive; + ImGuiCol_TabUnfocused :: TabUnfocused; + ImGuiCol_TabUnfocusedActive :: TabUnfocusedActive; + ImGuiCol_NavHighlight :: NavHighlight; +} + +// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. +// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. +// During initialization or between frames, feel free to just poke into ImGuiStyle directly. +// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. +// - In Visual Studio: Ctrl+Comma ("Edit.GoToAll") can follow symbols inside comments, whereas Ctrl+F12 ("Edit.GoToImplementation") cannot. +// - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +// - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments. +// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +StyleVar :: enum s32 { + Alpha :: 0; + DisabledAlpha :: 1; + WindowPadding :: 2; + WindowRounding :: 3; + WindowBorderSize :: 4; + WindowMinSize :: 5; + WindowTitleAlign :: 6; + ChildRounding :: 7; + ChildBorderSize :: 8; + PopupRounding :: 9; + PopupBorderSize :: 10; + FramePadding :: 11; + FrameRounding :: 12; + FrameBorderSize :: 13; + ItemSpacing :: 14; + ItemInnerSpacing :: 15; + IndentSpacing :: 16; + CellPadding :: 17; + ScrollbarSize :: 18; + ScrollbarRounding :: 19; + ScrollbarPadding :: 20; + GrabMinSize :: 21; + GrabRounding :: 22; + ImageRounding :: 23; + ImageBorderSize :: 24; + TabRounding :: 25; + TabBorderSize :: 26; + TabMinWidthBase :: 27; + TabMinWidthShrink :: 28; + TabBarBorderSize :: 29; + TabBarOverlineSize :: 30; + TableAngledHeadersAngle :: 31; + TableAngledHeadersTextAlign :: 32; + TreeLinesSize :: 33; + TreeLinesRounding :: 34; + ButtonTextAlign :: 35; + SelectableTextAlign :: 36; + SeparatorTextBorderSize :: 37; + SeparatorTextAlign :: 38; + SeparatorTextPadding :: 39; + DockingSeparatorSize :: 40; + COUNT :: 41; + + ImGuiStyleVar_Alpha :: Alpha; + ImGuiStyleVar_DisabledAlpha :: DisabledAlpha; + ImGuiStyleVar_WindowPadding :: WindowPadding; + ImGuiStyleVar_WindowRounding :: WindowRounding; + ImGuiStyleVar_WindowBorderSize :: WindowBorderSize; + ImGuiStyleVar_WindowMinSize :: WindowMinSize; + ImGuiStyleVar_WindowTitleAlign :: WindowTitleAlign; + ImGuiStyleVar_ChildRounding :: ChildRounding; + ImGuiStyleVar_ChildBorderSize :: ChildBorderSize; + ImGuiStyleVar_PopupRounding :: PopupRounding; + ImGuiStyleVar_PopupBorderSize :: PopupBorderSize; + ImGuiStyleVar_FramePadding :: FramePadding; + ImGuiStyleVar_FrameRounding :: FrameRounding; + ImGuiStyleVar_FrameBorderSize :: FrameBorderSize; + ImGuiStyleVar_ItemSpacing :: ItemSpacing; + ImGuiStyleVar_ItemInnerSpacing :: ItemInnerSpacing; + ImGuiStyleVar_IndentSpacing :: IndentSpacing; + ImGuiStyleVar_CellPadding :: CellPadding; + ImGuiStyleVar_ScrollbarSize :: ScrollbarSize; + ImGuiStyleVar_ScrollbarRounding :: ScrollbarRounding; + ImGuiStyleVar_ScrollbarPadding :: ScrollbarPadding; + ImGuiStyleVar_GrabMinSize :: GrabMinSize; + ImGuiStyleVar_GrabRounding :: GrabRounding; + ImGuiStyleVar_ImageRounding :: ImageRounding; + ImGuiStyleVar_ImageBorderSize :: ImageBorderSize; + ImGuiStyleVar_TabRounding :: TabRounding; + ImGuiStyleVar_TabBorderSize :: TabBorderSize; + ImGuiStyleVar_TabMinWidthBase :: TabMinWidthBase; + ImGuiStyleVar_TabMinWidthShrink :: TabMinWidthShrink; + ImGuiStyleVar_TabBarBorderSize :: TabBarBorderSize; + ImGuiStyleVar_TabBarOverlineSize :: TabBarOverlineSize; + ImGuiStyleVar_TableAngledHeadersAngle :: TableAngledHeadersAngle; + ImGuiStyleVar_TableAngledHeadersTextAlign :: TableAngledHeadersTextAlign; + ImGuiStyleVar_TreeLinesSize :: TreeLinesSize; + ImGuiStyleVar_TreeLinesRounding :: TreeLinesRounding; + ImGuiStyleVar_ButtonTextAlign :: ButtonTextAlign; + ImGuiStyleVar_SelectableTextAlign :: SelectableTextAlign; + ImGuiStyleVar_SeparatorTextBorderSize :: SeparatorTextBorderSize; + ImGuiStyleVar_SeparatorTextAlign :: SeparatorTextAlign; + ImGuiStyleVar_SeparatorTextPadding :: SeparatorTextPadding; + ImGuiStyleVar_DockingSeparatorSize :: DockingSeparatorSize; + ImGuiStyleVar_COUNT :: COUNT; +} + +// Flags for InvisibleButton() [extended in imgui_internal.h] +ButtonFlags :: enum_flags s32 { + None :: 0x0; + MouseButtonLeft :: 0x1; + MouseButtonRight :: 0x2; + MouseButtonMiddle :: 0x4; + MouseButtonMask_ :: 0x7; + EnableNav :: 0x8; + + ImGuiButtonFlags_None :: None; + ImGuiButtonFlags_MouseButtonLeft :: MouseButtonLeft; + ImGuiButtonFlags_MouseButtonRight :: MouseButtonRight; + ImGuiButtonFlags_MouseButtonMiddle :: MouseButtonMiddle; + ImGuiButtonFlags_MouseButtonMask_ :: MouseButtonMask_; + ImGuiButtonFlags_EnableNav :: EnableNav; +} + +// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() +ColorEditFlags :: enum_flags s32 { + None :: 0x0; + NoAlpha :: 0x2; + NoPicker :: 0x4; + NoOptions :: 0x8; + NoSmallPreview :: 0x10; + NoInputs :: 0x20; + NoTooltip :: 0x40; + NoLabel :: 0x80; + NoSidePreview :: 0x100; + NoDragDrop :: 0x200; + NoBorder :: 0x400; + NoColorMarkers :: 0x800; + + AlphaOpaque :: 0x1000; + AlphaNoBg :: 0x2000; + AlphaPreviewHalf :: 0x4000; + + AlphaBar :: 0x40000; + HDR :: 0x80000; + DisplayRGB :: 0x100000; + DisplayHSV :: 0x200000; + DisplayHex :: 0x400000; + Uint8 :: 0x800000; + Float :: 0x1000000; + PickerHueBar :: 0x2000000; + PickerHueWheel :: 0x4000000; + InputRGB :: 0x8000000; + InputHSV :: 0x10000000; + + DefaultOptions_ :: 0xa900000; + + AlphaMask_ :: 0x7002; + DisplayMask_ :: 0x700000; + DataTypeMask_ :: 0x1800000; + PickerMask_ :: 0x6000000; + InputMask_ :: 0x18000000; + + AlphaPreview :: 0x0; + + ImGuiColorEditFlags_None :: None; + ImGuiColorEditFlags_NoAlpha :: NoAlpha; + ImGuiColorEditFlags_NoPicker :: NoPicker; + ImGuiColorEditFlags_NoOptions :: NoOptions; + ImGuiColorEditFlags_NoSmallPreview :: NoSmallPreview; + ImGuiColorEditFlags_NoInputs :: NoInputs; + ImGuiColorEditFlags_NoTooltip :: NoTooltip; + ImGuiColorEditFlags_NoLabel :: NoLabel; + ImGuiColorEditFlags_NoSidePreview :: NoSidePreview; + ImGuiColorEditFlags_NoDragDrop :: NoDragDrop; + ImGuiColorEditFlags_NoBorder :: NoBorder; + ImGuiColorEditFlags_NoColorMarkers :: NoColorMarkers; + + ImGuiColorEditFlags_AlphaOpaque :: AlphaOpaque; + ImGuiColorEditFlags_AlphaNoBg :: AlphaNoBg; + ImGuiColorEditFlags_AlphaPreviewHalf :: AlphaPreviewHalf; + + ImGuiColorEditFlags_AlphaBar :: AlphaBar; + ImGuiColorEditFlags_HDR :: HDR; + ImGuiColorEditFlags_DisplayRGB :: DisplayRGB; + ImGuiColorEditFlags_DisplayHSV :: DisplayHSV; + ImGuiColorEditFlags_DisplayHex :: DisplayHex; + ImGuiColorEditFlags_Uint8 :: Uint8; + ImGuiColorEditFlags_Float :: Float; + ImGuiColorEditFlags_PickerHueBar :: PickerHueBar; + ImGuiColorEditFlags_PickerHueWheel :: PickerHueWheel; + ImGuiColorEditFlags_InputRGB :: InputRGB; + ImGuiColorEditFlags_InputHSV :: InputHSV; + + ImGuiColorEditFlags_DefaultOptions_ :: DefaultOptions_; + + ImGuiColorEditFlags_AlphaMask_ :: AlphaMask_; + ImGuiColorEditFlags_DisplayMask_ :: DisplayMask_; + ImGuiColorEditFlags_DataTypeMask_ :: DataTypeMask_; + ImGuiColorEditFlags_PickerMask_ :: PickerMask_; + ImGuiColorEditFlags_InputMask_ :: InputMask_; + + ImGuiColorEditFlags_AlphaPreview :: AlphaPreview; +} + +// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. +// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. +// (Those are per-item flags. There is shared behavior flag too: ImGuiIO: io.ConfigDragClickToInputText) +SliderFlags :: enum_flags s32 { + None :: 0x0; + Logarithmic :: 0x20; + NoRoundToFormat :: 0x40; + NoInput :: 0x80; + WrapAround :: 0x100; + ClampOnInput :: 0x200; + ClampZeroRange :: 0x400; + NoSpeedTweaks :: 0x800; + ColorMarkers :: 0x1000; + AlwaysClamp :: 0x600; + InvalidMask_ :: 0x7000000f; + + ImGuiSliderFlags_None :: None; + ImGuiSliderFlags_Logarithmic :: Logarithmic; + ImGuiSliderFlags_NoRoundToFormat :: NoRoundToFormat; + ImGuiSliderFlags_NoInput :: NoInput; + ImGuiSliderFlags_WrapAround :: WrapAround; + ImGuiSliderFlags_ClampOnInput :: ClampOnInput; + ImGuiSliderFlags_ClampZeroRange :: ClampZeroRange; + ImGuiSliderFlags_NoSpeedTweaks :: NoSpeedTweaks; + ImGuiSliderFlags_ColorMarkers :: ColorMarkers; + ImGuiSliderFlags_AlwaysClamp :: AlwaysClamp; + ImGuiSliderFlags_InvalidMask_ :: InvalidMask_; +} + +// Identify a mouse button. +// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. +MouseButton :: enum s32 { + Left :: 0; + Right :: 1; + Middle :: 2; + COUNT :: 5; + + ImGuiMouseButton_Left :: Left; + ImGuiMouseButton_Right :: Right; + ImGuiMouseButton_Middle :: Middle; + ImGuiMouseButton_COUNT :: COUNT; +} + +// Enumeration for GetMouseCursor() +// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +MouseCursor :: enum s32 { + None :: -1; + Arrow :: 0; + TextInput :: 1; + ResizeAll :: 2; + ResizeNS :: 3; + ResizeEW :: 4; + ResizeNESW :: 5; + ResizeNWSE :: 6; + Hand :: 7; + Wait :: 8; + Progress :: 9; + NotAllowed :: 10; + COUNT :: 11; + + ImGuiMouseCursor_None :: None; + ImGuiMouseCursor_Arrow :: Arrow; + ImGuiMouseCursor_TextInput :: TextInput; + ImGuiMouseCursor_ResizeAll :: ResizeAll; + ImGuiMouseCursor_ResizeNS :: ResizeNS; + ImGuiMouseCursor_ResizeEW :: ResizeEW; + ImGuiMouseCursor_ResizeNESW :: ResizeNESW; + ImGuiMouseCursor_ResizeNWSE :: ResizeNWSE; + ImGuiMouseCursor_Hand :: Hand; + ImGuiMouseCursor_Wait :: Wait; + ImGuiMouseCursor_Progress :: Progress; + ImGuiMouseCursor_NotAllowed :: NotAllowed; + ImGuiMouseCursor_COUNT :: COUNT; +} + +// Enumeration for ImGui::SetNextWindow***(), SetWindow***(), SetNextItem***() functions +// Represent a condition. +// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. +Cond :: enum s32 { + None :: 0; + Always :: 1; + Once :: 2; + FirstUseEver :: 4; + Appearing :: 8; + + ImGuiCond_None :: None; + ImGuiCond_Always :: Always; + ImGuiCond_Once :: Once; + ImGuiCond_FirstUseEver :: FirstUseEver; + ImGuiCond_Appearing :: Appearing; +} + +// Flags for ImGui::BeginTable() +// - Important! Sizing policies have complex and subtle side effects, much more so than you would expect. +// Read comments/demos carefully + experiment with live demos to get acquainted with them. +// - The DEFAULT sizing policies are: +// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. +// - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off. +// - When ScrollX is off: +// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight. +// - Columns sizing policy allowed: Stretch (default), Fixed/Auto. +// - Fixed Columns (if any) will generally obtain their requested width (unless the table cannot fit them all). +// - Stretch Columns will share the remaining width according to their respective weight. +// - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. +// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). +// - When ScrollX is on: +// - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed +// - Columns sizing policy allowed: Fixed/Auto mostly. +// - Fixed Columns can be enlarged as needed. Table will show a horizontal scrollbar if needed. +// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop. +// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). +// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. +// - Read on documentation at the top of imgui_tables.cpp for details. +TableFlags :: enum_flags s32 { + None :: 0x0; + Resizable :: 0x1; + Reorderable :: 0x2; + Hideable :: 0x4; + Sortable :: 0x8; + NoSavedSettings :: 0x10; + ContextMenuInBody :: 0x20; + + RowBg :: 0x40; + BordersInnerH :: 0x80; + BordersOuterH :: 0x100; + BordersInnerV :: 0x200; + BordersOuterV :: 0x400; + BordersH :: 0x180; + BordersV :: 0x600; + BordersInner :: 0x280; + BordersOuter :: 0x500; + Borders :: 0x780; + NoBordersInBody :: 0x800; + NoBordersInBodyUntilResize :: 0x1000; + + SizingFixedFit :: 0x2000; + SizingFixedSame :: 0x4000; + SizingStretchProp :: 0x6000; + SizingStretchSame :: 0x8000; + + NoHostExtendX :: 0x10000; + NoHostExtendY :: 0x20000; + NoKeepColumnsVisible :: 0x40000; + PreciseWidths :: 0x80000; + + NoClip :: 0x100000; + + PadOuterX :: 0x200000; + NoPadOuterX :: 0x400000; + NoPadInnerX :: 0x800000; + + ScrollX :: 0x1000000; + ScrollY :: 0x2000000; + + SortMulti :: 0x4000000; + SortTristate :: 0x8000000; + + HighlightHoveredColumn :: 0x10000000; + + SizingMask_ :: 0xe000; + + ImGuiTableFlags_None :: None; + ImGuiTableFlags_Resizable :: Resizable; + ImGuiTableFlags_Reorderable :: Reorderable; + ImGuiTableFlags_Hideable :: Hideable; + ImGuiTableFlags_Sortable :: Sortable; + ImGuiTableFlags_NoSavedSettings :: NoSavedSettings; + ImGuiTableFlags_ContextMenuInBody :: ContextMenuInBody; + + ImGuiTableFlags_RowBg :: RowBg; + ImGuiTableFlags_BordersInnerH :: BordersInnerH; + ImGuiTableFlags_BordersOuterH :: BordersOuterH; + ImGuiTableFlags_BordersInnerV :: BordersInnerV; + ImGuiTableFlags_BordersOuterV :: BordersOuterV; + ImGuiTableFlags_BordersH :: BordersH; + ImGuiTableFlags_BordersV :: BordersV; + ImGuiTableFlags_BordersInner :: BordersInner; + ImGuiTableFlags_BordersOuter :: BordersOuter; + ImGuiTableFlags_Borders :: Borders; + ImGuiTableFlags_NoBordersInBody :: NoBordersInBody; + ImGuiTableFlags_NoBordersInBodyUntilResize :: NoBordersInBodyUntilResize; + + ImGuiTableFlags_SizingFixedFit :: SizingFixedFit; + ImGuiTableFlags_SizingFixedSame :: SizingFixedSame; + ImGuiTableFlags_SizingStretchProp :: SizingStretchProp; + ImGuiTableFlags_SizingStretchSame :: SizingStretchSame; + + ImGuiTableFlags_NoHostExtendX :: NoHostExtendX; + ImGuiTableFlags_NoHostExtendY :: NoHostExtendY; + ImGuiTableFlags_NoKeepColumnsVisible :: NoKeepColumnsVisible; + ImGuiTableFlags_PreciseWidths :: PreciseWidths; + + ImGuiTableFlags_NoClip :: NoClip; + + ImGuiTableFlags_PadOuterX :: PadOuterX; + ImGuiTableFlags_NoPadOuterX :: NoPadOuterX; + ImGuiTableFlags_NoPadInnerX :: NoPadInnerX; + + ImGuiTableFlags_ScrollX :: ScrollX; + ImGuiTableFlags_ScrollY :: ScrollY; + + ImGuiTableFlags_SortMulti :: SortMulti; + ImGuiTableFlags_SortTristate :: SortTristate; + + ImGuiTableFlags_HighlightHoveredColumn :: HighlightHoveredColumn; + + ImGuiTableFlags_SizingMask_ :: SizingMask_; +} + +// Flags for ImGui::TableSetupColumn() +TableColumnFlags :: enum_flags s32 { + None :: 0x0; + Disabled :: 0x1; + DefaultHide :: 0x2; + DefaultSort :: 0x4; + WidthStretch :: 0x8; + WidthFixed :: 0x10; + NoResize :: 0x20; + NoReorder :: 0x40; + NoHide :: 0x80; + NoClip :: 0x100; + NoSort :: 0x200; + NoSortAscending :: 0x400; + NoSortDescending :: 0x800; + NoHeaderLabel :: 0x1000; + NoHeaderWidth :: 0x2000; + PreferSortAscending :: 0x4000; + PreferSortDescending :: 0x8000; + IndentEnable :: 0x10000; + IndentDisable :: 0x20000; + AngledHeader :: 0x40000; + + IsEnabled :: 0x1000000; + IsVisible :: 0x2000000; + IsSorted :: 0x4000000; + IsHovered :: 0x8000000; + + WidthMask_ :: 0x18; + IndentMask_ :: 0x30000; + StatusMask_ :: 0xf000000; + NoDirectResize_ :: 0x40000000; + + ImGuiTableColumnFlags_None :: None; + ImGuiTableColumnFlags_Disabled :: Disabled; + ImGuiTableColumnFlags_DefaultHide :: DefaultHide; + ImGuiTableColumnFlags_DefaultSort :: DefaultSort; + ImGuiTableColumnFlags_WidthStretch :: WidthStretch; + ImGuiTableColumnFlags_WidthFixed :: WidthFixed; + ImGuiTableColumnFlags_NoResize :: NoResize; + ImGuiTableColumnFlags_NoReorder :: NoReorder; + ImGuiTableColumnFlags_NoHide :: NoHide; + ImGuiTableColumnFlags_NoClip :: NoClip; + ImGuiTableColumnFlags_NoSort :: NoSort; + ImGuiTableColumnFlags_NoSortAscending :: NoSortAscending; + ImGuiTableColumnFlags_NoSortDescending :: NoSortDescending; + ImGuiTableColumnFlags_NoHeaderLabel :: NoHeaderLabel; + ImGuiTableColumnFlags_NoHeaderWidth :: NoHeaderWidth; + ImGuiTableColumnFlags_PreferSortAscending :: PreferSortAscending; + ImGuiTableColumnFlags_PreferSortDescending :: PreferSortDescending; + ImGuiTableColumnFlags_IndentEnable :: IndentEnable; + ImGuiTableColumnFlags_IndentDisable :: IndentDisable; + ImGuiTableColumnFlags_AngledHeader :: AngledHeader; + + ImGuiTableColumnFlags_IsEnabled :: IsEnabled; + ImGuiTableColumnFlags_IsVisible :: IsVisible; + ImGuiTableColumnFlags_IsSorted :: IsSorted; + ImGuiTableColumnFlags_IsHovered :: IsHovered; + + ImGuiTableColumnFlags_WidthMask_ :: WidthMask_; + ImGuiTableColumnFlags_IndentMask_ :: IndentMask_; + ImGuiTableColumnFlags_StatusMask_ :: StatusMask_; + ImGuiTableColumnFlags_NoDirectResize_ :: NoDirectResize_; +} + +// Flags for ImGui::TableNextRow() +TableRowFlags :: enum_flags s32 { + None :: 0x0; + Headers :: 0x1; + + ImGuiTableRowFlags_None :: None; + ImGuiTableRowFlags_Headers :: Headers; +} + +// Enum for ImGui::TableSetBgColor() +// Background colors are rendering in 3 layers: +// - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set. +// - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set. +// - Layer 2: draw with CellBg color if set. +// The purpose of the two row/columns layers is to let you decide if a background color change should override or blend with the existing color. +// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows. +// If you set the color of RowBg0 target, your color will override the existing RowBg0 color. +// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color. +TableBgTarget :: enum s32 { + None :: 0; + RowBg0 :: 1; + RowBg1 :: 2; + CellBg :: 3; + + ImGuiTableBgTarget_None :: None; + ImGuiTableBgTarget_RowBg0 :: RowBg0; + ImGuiTableBgTarget_RowBg1 :: RowBg1; + ImGuiTableBgTarget_CellBg :: CellBg; +} + +// Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +// Obtained by calling TableGetSortSpecs(). +// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. +// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! +TableSortSpecs :: struct { + Specs: *TableColumnSortSpecs; // Pointer to sort spec array. + SpecsCount: s32; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled. + SpecsDirty: bool; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. +} + +// Sorting specification for one column of a table (sizeof == 12 bytes) +TableColumnSortSpecs :: struct { + ColumnUserID: ID; // User id of the column (if specified by a TableSetupColumn() call) + ColumnIndex: ImS16; // Index of the column + SortOrder: ImS16; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) + SortDirection_: SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending +} + +//----------------------------------------------------------------------------- +// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() +// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. +// Defining a custom placement new() with a custom parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +//----------------------------------------------------------------------------- +ImNewWrapper :: struct { + __empty_struct_padding: u8; // C++ makes empty structs have length 1 +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStyle +//----------------------------------------------------------------------------- +// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). +// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, +// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. +//----------------------------------------------------------------------------- +Style :: struct { + FontSizeBase: float; // Current base font size before external global factors are applied. Use PushFont(NULL, size) to modify. Use ImGui::GetFontSize() to obtain scaled value. + FontScaleMain: float; // Main global scale factor. May be set by application once, or exposed to end-user. + FontScaleDpi: float; // Additional global scale factor from viewport/monitor contents scale. In docking branch: when io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. + + Alpha: float; // Global alpha applies to everything in Dear ImGui. + DisabledAlpha: float; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. + WindowPadding: ImVec2; // Padding within a window. + WindowRounding: float; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. + WindowBorderSize: float; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + WindowBorderHoverPadding: float; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders. + WindowMinSize: ImVec2; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints(). + WindowTitleAlign: ImVec2; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. + WindowMenuButtonPosition: Dir; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. + ChildRounding: float; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. + ChildBorderSize: float; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + PopupRounding: float; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) + PopupBorderSize: float; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + FramePadding: ImVec2; // Padding within a framed rectangle (used by most widgets). + FrameRounding: float; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). + FrameBorderSize: float; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ItemSpacing: ImVec2; // Horizontal and vertical spacing between widgets/lines. + ItemInnerSpacing: ImVec2; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). + CellPadding: ImVec2; // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be altered between different rows. + TouchExtraPadding: ImVec2; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + IndentSpacing: float; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + ColumnsMinSpacing: float; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + ScrollbarSize: float; // Width of the vertical scrollbar, Height of the horizontal scrollbar. + ScrollbarRounding: float; // Radius of grab corners for scrollbar. + ScrollbarPadding: float; // Padding of scrollbar grab within its frame (same for both axes). + GrabMinSize: float; // Minimum width/height of a grab box for slider/scrollbar. + GrabRounding: float; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + LogSliderDeadzone: float; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + ImageRounding: float; // Rounding of Image() calls. + ImageBorderSize: float; // Thickness of border around Image() calls. + TabRounding: float; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabBorderSize: float; // Thickness of border around tabs. + TabMinWidthBase: float; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected. + TabMinWidthShrink: float; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy. + TabCloseButtonMinWidthSelected: float; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. + TabCloseButtonMinWidthUnselected: float; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected. + TabBarBorderSize: float; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. + TabBarOverlineSize: float; // Thickness of tab-bar overline, which highlights the selected tab-bar. + TableAngledHeadersAngle: float; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). + TableAngledHeadersTextAlign: ImVec2; // Alignment of angled headers within the cell + TreeLinesFlags: TreeNodeFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. + TreeLinesSize: float; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + TreeLinesRounding: float; // Radius of lines connecting child nodes to the vertical line. + DragDropTargetRounding: float; // Radius of the drag and drop target frame. + DragDropTargetBorderSize: float; // Thickness of the drag and drop target border. + DragDropTargetPadding: float; // Size to expand the drag and drop target from actual target item size. + ColorMarkerSize: float; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers. + ColorButtonPosition: Dir; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ButtonTextAlign: ImVec2; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). + SelectableTextAlign: ImVec2; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + SeparatorTextBorderSize: float; // Thickness of border in SeparatorText() + SeparatorTextAlign: ImVec2; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + SeparatorTextPadding: ImVec2; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. + DisplayWindowPadding: ImVec2; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen. + DisplaySafeAreaPadding: ImVec2; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured). + DockingNodeHasCloseButton: bool; // Docking node has their own CloseButton() to close all docked windows. + DockingSeparatorSize: float; // Thickness of resizing border between docked windows + MouseCursorScale: float; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later. + AntiAliasedLines: bool; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + AntiAliasedLinesUseTex: bool; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList). + AntiAliasedFill: bool; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + CurveTessellationTol: float; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + CircleTessellationMaxError: float; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + + // Colors + Colors: [62] ImVec4; + + HoverStationaryDelay: float; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary. + HoverDelayShort: float; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay. + HoverDelayNormal: float; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " + HoverFlagsForTooltipMouse: HoveredFlags; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. + HoverFlagsForTooltipNav: HoveredFlags; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. + + _MainScale: float; // FIXME-WIP: Reference scale, as applied by ScaleAllSizes(). PLEASE DO NOT USE THIS FOR NOW. + _NextFrameFontSizeBase: float; // FIXME: Temporary hack until we finish remaining work. + + // Functions + Constructor :: (this: *Style) -> void #cpp_method #foreign imgui "??0ImGuiStyle@@QEAA@XZ"; + ScaleAllSizes :: (this: *Style, scale_factor: float) -> void #cpp_method #foreign imgui "?ScaleAllSizes@ImGuiStyle@@QEAAXM@Z"; +} + +// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. +// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. +KeyData :: struct { + Down: bool; // True for if key is down + DownDuration: float; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) + DownDurationPrev: float; // Last frame duration the key has been down + AnalogValue: float; // 0.0f..1.0f for gamepad values +} + +IO :: struct { + ConfigFlags_: ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc. + BackendFlags_: BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. + DisplaySize: ImVec2; // // Main display size, in pixels (== GetMainViewport()->Size). May change every frame. + DisplayFramebufferScale: ImVec2; // = (1, 1) // Main display density. For retina display where window coordinates are different from framebuffer coordinates. This will affect font density + will end up in ImDrawData::FramebufferScale. + DeltaTime: float; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. + IniSavingRate: float; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. + IniFilename: *u8; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. + LogFilename: *u8; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). + UserData: *void; // = NULL // Store your own data. + + Fonts: *ImFontAtlas; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. + FontDefault: *ImFont; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + FontAllowUserScaling: bool; // = false // Allow user scaling text of individual window with Ctrl+Wheel. + + ConfigNavSwapGamepadButtons: bool; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. + ConfigNavMoveSetMousePos: bool; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. + ConfigNavCaptureKeyboard: bool; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. + ConfigNavEscapeClearFocusItem: bool; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. + ConfigNavEscapeClearFocusWindow: bool; // = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). + ConfigNavCursorVisibleAuto: bool; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor. + ConfigNavCursorVisibleAlways: bool; // = false // Navigation cursor is always visible. + + ConfigDockingNoSplit: bool; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars. + ConfigDockingNoDockingOver: bool; // = false // Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows. + ConfigDockingWithShift: bool; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space) + ConfigDockingAlwaysTabBar: bool; // = false // [BETA] [FIXME: This currently creates regression with auto-sizing and general overhead] Make every single floating window display within a docking node. + ConfigDockingTransparentPayload: bool; // = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge. + + ConfigViewportsNoAutoMerge: bool; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. May also set ImGuiViewportFlags_NoAutoMerge on individual viewport. + ConfigViewportsNoTaskBarIcon: bool; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it. + ConfigViewportsNoDecoration: bool; // = true // Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size). + ConfigViewportsNoDefaultParent: bool; // = true // When false: set secondary viewports' ParentViewportId to main viewport ID by default. Expects the platform backend to setup a parent/child relationship between the OS windows based on this value. Some backend may ignore this. Set to true if you want viewports to automatically be parent of main viewport, otherwise all viewports will be top-level OS windows. + ConfigViewportsPlatformFocusSetsImGuiFocus: bool; //= true // When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change). + + ConfigDpiScaleFonts: bool; // = false // [EXPERIMENTAL] Automatically overwrite style.FontScaleDpi when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. + ConfigDpiScaleViewports: bool; // = false // [EXPERIMENTAL] Scale Dear ImGui and Platform Windows when Monitor DPI changes. + + MouseDrawCursor: bool; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. + ConfigMacOSXBehaviors: bool; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + ConfigInputTrickleEventQueue: bool; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. + ConfigInputTextCursorBlink: bool; // = true // Enable blinking cursor (optional as some users consider it to be distracting). + ConfigInputTextEnterKeepActive: bool; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). + ConfigDragClickToInputText: bool; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. + ConfigWindowsResizeFromEdges: bool; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + ConfigWindowsMoveFromTitleBarOnly: bool; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. + ConfigWindowsCopyContentsWithCtrlC: bool; // = false // [EXPERIMENTAL] Ctrl+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order. + ConfigScrollbarScrollByPage: bool; // = true // Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location. + ConfigMemoryCompactTimer: float; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. + + MouseDoubleClickTime: float; // = 0.30f // Time for a double-click, in seconds. + MouseDoubleClickMaxDist: float; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + MouseDragThreshold: float; // = 6.0f // Distance threshold before considering we are dragging. + KeyRepeatDelay: float; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + KeyRepeatRate: float; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + + ConfigErrorRecovery: bool; // = true // Enable error recovery support. Some errors won't be detected and lead to direct crashes if recovery is disabled. + ConfigErrorRecoveryEnableAssert: bool; // = true // Enable asserts on recoverable error. By default call IM_ASSERT() when returning from a failing IM_ASSERT_USER_ERROR() + ConfigErrorRecoveryEnableDebugLog: bool; // = true // Enable debug log output on recoverable errors. + ConfigErrorRecoveryEnableTooltip: bool; // = true // Enable tooltip on recoverable errors. The tooltip include a way to enable asserts if they were disabled. + + ConfigDebugIsDebuggerPresent: bool; // = false // Enable various tools calling IM_DEBUG_BREAK(). + + ConfigDebugHighlightIdConflicts: bool; // = true // Highlight and show an error message popup when multiple items have conflicting identifiers. + ConfigDebugHighlightIdConflictsShowItemPicker: bool; //=true // Show "Item Picker" button in aforementioned popup. + + ConfigDebugBeginReturnValueOnce: bool; // = false // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows. + ConfigDebugBeginReturnValueLoop: bool; // = false // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running. + + ConfigDebugIgnoreFocusLoss: bool; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys()/io.ClearInputMouse() in input processing. + + ConfigDebugIniSettings: bool; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) + + BackendPlatformName: *u8; // = NULL + BackendRendererName: *u8; // = NULL + BackendPlatformUserData: *void; // = NULL // User data for platform backend + BackendRendererUserData: *void; // = NULL // User data for renderer backend + BackendLanguageUserData: *void; // = NULL // User data for non C++ programming language backend + + // Input Functions + AddKeyEvent :: (this: *IO, key: Key, down: bool) -> void #cpp_method #foreign imgui "?AddKeyEvent@ImGuiIO@@QEAAXW4ImGuiKey@@_N@Z"; + AddKeyAnalogEvent :: (this: *IO, key: Key, down: bool, v: float) -> void #cpp_method #foreign imgui "?AddKeyAnalogEvent@ImGuiIO@@QEAAXW4ImGuiKey@@_NM@Z"; + AddMousePosEvent :: (this: *IO, x: float, y: float) -> void #cpp_method #foreign imgui "?AddMousePosEvent@ImGuiIO@@QEAAXMM@Z"; + AddMouseButtonEvent :: (this: *IO, button: s32, down: bool) -> void #cpp_method #foreign imgui "?AddMouseButtonEvent@ImGuiIO@@QEAAXH_N@Z"; + AddMouseWheelEvent :: (this: *IO, wheel_x: float, wheel_y: float) -> void #cpp_method #foreign imgui "?AddMouseWheelEvent@ImGuiIO@@QEAAXMM@Z"; + AddMouseSourceEvent :: (this: *IO, source: MouseSource) -> void #cpp_method #foreign imgui "?AddMouseSourceEvent@ImGuiIO@@QEAAXW4ImGuiMouseSource@@@Z"; + AddMouseViewportEvent :: (this: *IO, id: ID) -> void #cpp_method #foreign imgui "?AddMouseViewportEvent@ImGuiIO@@QEAAXI@Z"; + AddFocusEvent :: (this: *IO, focused: bool) -> void #cpp_method #foreign imgui "?AddFocusEvent@ImGuiIO@@QEAAX_N@Z"; + AddInputCharacter :: (this: *IO, c: u32) -> void #cpp_method #foreign imgui "?AddInputCharacter@ImGuiIO@@QEAAXI@Z"; + AddInputCharacterUTF16 :: (this: *IO, c: ImWchar16) -> void #cpp_method #foreign imgui "?AddInputCharacterUTF16@ImGuiIO@@QEAAXG@Z"; + AddInputCharactersUTF8 :: (this: *IO, str: *u8) -> void #cpp_method #foreign imgui "?AddInputCharactersUTF8@ImGuiIO@@QEAAXPEBD@Z"; + + SetKeyEventNativeData :: (this: *IO, key: Key, native_keycode: s32, native_scancode: s32, native_legacy_index: s32 = -1) -> void #cpp_method #foreign imgui "?SetKeyEventNativeData@ImGuiIO@@QEAAXW4ImGuiKey@@HHH@Z"; + SetAppAcceptingEvents :: (this: *IO, accepting_events: bool) -> void #cpp_method #foreign imgui "?SetAppAcceptingEvents@ImGuiIO@@QEAAX_N@Z"; + ClearEventsQueue :: (this: *IO) -> void #cpp_method #foreign imgui "?ClearEventsQueue@ImGuiIO@@QEAAXXZ"; + ClearInputKeys :: (this: *IO) -> void #cpp_method #foreign imgui "?ClearInputKeys@ImGuiIO@@QEAAXXZ"; + ClearInputMouse :: (this: *IO) -> void #cpp_method #foreign imgui "?ClearInputMouse@ImGuiIO@@QEAAXXZ"; + + WantCaptureMouse: bool; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + WantCaptureKeyboard: bool; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + WantTextInput: bool; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + WantSetMousePos: bool; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when io.ConfigNavMoveSetMousePos is enabled. + WantSaveIniSettings: bool; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! + NavActive: bool; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + NavVisible: bool; // Keyboard/Gamepad navigation highlight is visible and allowed (will handle ImGuiKey_NavXXX events). + Framerate: float; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally. + MetricsRenderVertices: s32; // Vertices output during last call to Render() + MetricsRenderIndices: s32; // Indices output during last call to Render() = number of triangles * 3 + MetricsRenderWindows: s32; // Number of visible windows + MetricsActiveWindows: s32; // Number of active windows + MouseDelta: ImVec2; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + Ctx: *ImGuiContext; // Parent UI context (needs to be set explicitly by parent). + + MousePos: ImVec2; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) + MouseDown: [5] bool; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + MouseWheel: float; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold Shift to turn vertical scroll into horizontal scroll. + MouseWheelH: float; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. + MouseSource_: MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). + MouseHoveredViewport: ID; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). + KeyCtrl: bool; // Keyboard modifier down: Ctrl (non-macOS), Cmd (macOS) + KeyShift: bool; // Keyboard modifier down: Shift + KeyAlt: bool; // Keyboard modifier down: Alt + KeySuper: bool; // Keyboard modifier down: Windows/Super (non-macOS), Ctrl (macOS) + + KeyMods: KeyChord; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame() + KeysData: [155] KeyData; // Key state for all known keys. MUST use 'key - ImGuiKey_NamedKey_BEGIN' as index. Use IsKeyXXX() functions to access this. + WantCaptureMouseUnlessPopupClose: bool; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. + MousePosPrev: ImVec2; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + MouseClickedPos: [5] ImVec2; // Position at time of clicking + MouseClickedTime: [5] float64; // Time of last click (used to figure out double-click) + MouseClicked: [5] bool; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) + MouseDoubleClicked: [5] bool; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) + MouseClickedCount: [5] ImU16; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down + MouseClickedLastCount: [5] ImU16; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. + MouseReleased: [5] bool; // Mouse button went from Down to !Down + MouseReleasedTime: [5] float64; // Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click). + MouseDownOwned: [5] bool; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. + MouseDownOwnedUnlessPopupClose: [5] bool; // Track if button was clicked inside a dear imgui window. + MouseWheelRequestAxisSwap: bool; // On a non-Mac system, holding Shift requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. + MouseCtrlLeftAsRightClick: bool; // (OSX) Set to true when the current click was a Ctrl+Click that spawned a simulated right click + MouseDownDuration: [5] float; // Duration the mouse button has been down (0.0f == just clicked) + MouseDownDurationPrev: [5] float; // Previous time the mouse button has been down + MouseDragMaxDistanceAbs: [5] ImVec2; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point + MouseDragMaxDistanceSqr: [5] float; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) + PenPressure: float; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. + AppFocusLost: bool; // Only modify via AddFocusEvent() + AppAcceptingEvents: bool; // Only modify via SetAppAcceptingEvents() + InputQueueSurrogate: ImWchar16; // For AddInputCharacterUTF16() + InputQueueCharacters: ImVector(ImWchar); // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. + + FontGlobalScale: float; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92 (June 2025) + + // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. + // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). + GetClipboardTextFn: #type (user_data: *void) -> *u8 #c_call; + SetClipboardTextFn: #type (user_data: *void, text: *u8) -> void #c_call; + ClipboardUserData: *void; + + Constructor :: (this: *IO) -> void #cpp_method #foreign imgui "??0ImGuiIO@@QEAA@XZ"; +} + +// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. +// The callback function should return 0 by default. +// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. +// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration +// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB +// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows +// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +InputTextCallbackData :: struct { + Ctx: *ImGuiContext; // Parent UI context + EventFlag: InputTextFlags; // One ImGuiInputTextFlags_Callback* // Read-only + Flags: InputTextFlags; // What user passed to InputText() // Read-only + UserData: *void; // What user passed to InputText() // Read-only + ID_: ID; // Widget ID // Read-only + + EventKey: Key; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + EventChar: ImWchar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + EventActivated: bool; // Input field just got activated // Read-only // [Always] + BufDirty: bool; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] + Buf: *u8; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + BufTextLen: s32; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() + BufSize: s32; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land: == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 + CursorPos: s32; // // Read-write // [Completion,History,Always] + SelectionStart: s32; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection + SelectionEnd: s32; // // Read-write // [Completion,History,Always] + + // Helper functions for text manipulation. + // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. + Constructor :: (this: *InputTextCallbackData) -> void #cpp_method #foreign imgui "??0ImGuiInputTextCallbackData@@QEAA@XZ"; + DeleteChars :: (this: *InputTextCallbackData, pos: s32, bytes_count: s32) -> void #cpp_method #foreign imgui "?DeleteChars@ImGuiInputTextCallbackData@@QEAAXHH@Z"; + InsertChars :: (this: *InputTextCallbackData, pos: s32, text: *u8, text_end: *u8 = null) -> void #cpp_method #foreign imgui "?InsertChars@ImGuiInputTextCallbackData@@QEAAXHPEBD0@Z"; + InsertChars :: (this: *InputTextCallbackData, pos: s32, text: string) #no_context { + InsertChars(this, pos, text.data, text.data + text.count); + } +} + +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. +SizeCallbackData :: struct { + UserData: *void; // Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here (need reinterpret_cast<>). + Pos: ImVec2; // Read-only. Window position, for reference. + CurrentSize: ImVec2; // Read-only. Current window size. + DesiredSize: ImVec2; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. +} + +// [ALPHA] Rarely used / very advanced uses only. Use with SetNextWindowClass() and DockSpace() functions. +// Important: the content of this class is still highly WIP and likely to change and be refactored +// before we stabilize Docking features. Please be mindful if using this. +// Provide hints: +// - To the platform backend via altered viewport flags (enable/disable OS decoration, OS task bar icons, etc.) +// - To the platform backend for OS level parent/child relationships of viewport. +// - To the docking system for various options and filtering. +WindowClass :: struct { + ClassId: ID; // User data. 0 = Default class (unclassed). Windows of different classes cannot be docked with each others. + ParentViewportId: ID; // Hint for the platform backend. -1: use default. 0: request platform backend to not parent the platform. != 0: request platform backend to create a parent<>child relationship between the platform windows. Not conforming backends are free to e.g. parent every viewport to the main viewport or not. + FocusRouteParentWindowId: ID; // ID of parent window for shortcut focus route evaluation, e.g. Shortcut() call from Parent Window will succeed when this window is focused. + ViewportFlagsOverrideSet: ViewportFlags; // Viewport flags to set when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. + ViewportFlagsOverrideClear: ViewportFlags; // Viewport flags to clear when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. + TabItemFlagsOverrideSet: TabItemFlags; // [EXPERIMENTAL] TabItem flags to set when a window of this class gets submitted into a dock node tab bar. May use with ImGuiTabItemFlags_Leading or ImGuiTabItemFlags_Trailing. + DockNodeFlagsOverrideSet: DockNodeFlags; // [EXPERIMENTAL] Dock node flags to set when a window of this class is hosted by a dock node (it doesn't have to be selected!) + DockingAlwaysTabBar: bool; // Set to true to enforce single floating windows of this class always having their own docking node (equivalent of setting the global io.ConfigDockingAlwaysTabBar) + DockingAllowUnclassed: bool; // Set to true to allow windows of this class to be docked/merged with an unclassed window. // FIXME-DOCK: Move to DockNodeFlags override? +} + +// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() +Payload :: struct { + Data: *void; // Data (copied and owned by dear imgui) + DataSize: s32; // Data size + + SourceId: ID; // Source item id + SourceParentId: ID; // Source parent id (if available) + DataFrameCount: s32; // Data timestamp + DataType: [33] u8; // Data type tag (short user-supplied string, 32 characters max) + Preview: bool; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) + Delivery: bool; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. +} + +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within deep-nested code that runs multiple times every frame. +// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); +OnceUponAFrame :: struct { + RefFrame: s32; +} + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +TextFilter :: struct { + Constructor :: (this: *TextFilter, default_filter: *u8 = "") -> void #cpp_method #foreign imgui "??0ImGuiTextFilter@@QEAA@PEBD@Z"; + Draw :: (this: *TextFilter, label: *u8 = "Filter (inc,-exc)", width: float = 0.0) -> bool #cpp_method #foreign imgui "?Draw@ImGuiTextFilter@@QEAA_NPEBDM@Z"; + PassFilter :: (this: *TextFilter, text: *u8, text_end: *u8 = null) -> bool #cpp_method #foreign imgui "?PassFilter@ImGuiTextFilter@@QEBA_NPEBD0@Z"; + PassFilter :: (this: *TextFilter, text: string) -> bool #no_context { + return PassFilter(this, text.data, text.data + text.count); + } + Build :: (this: *TextFilter) -> void #cpp_method #foreign imgui "?Build@ImGuiTextFilter@@QEAAXXZ"; + + // [Internal] + TextRange :: struct { + b: *u8; + e: *u8; + + split :: (this: *TextRange, separator: u8, out: *ImVector(TextRange)) -> void #cpp_method #foreign imgui "?split@ImGuiTextRange@ImGuiTextFilter@@QEBAXDPEAU?$ImVector@UImGuiTextRange@ImGuiTextFilter@@@@@Z"; + } + + InputBuf: [256] u8; + Filters: ImVector(TextRange); + CountGrep: s32; +} + +// [Internal] Key+Value for ImGuiStorage +StoragePair :: struct { + key: ID; + union { + val_i: s32; + val_f: float; + val_p: *void; + } +} + +// Helper: Key->Value storage +// Typically you don't have to worry about this since a storage is held within each Window. +// We use it to e.g. store collapse state for a tree (Int 0/1) +// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) +// You can use it as custom user storage for temporary values. Declare your own storage if, for example: +// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). +// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) +// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. +Storage :: struct { + // [Internal] + Data: ImVector(StoragePair); + + GetInt :: (this: *Storage, key: ID, default_val: s32 = 0) -> s32 #cpp_method #foreign imgui "?GetInt@ImGuiStorage@@QEBAHIH@Z"; + SetInt :: (this: *Storage, key: ID, val: s32) -> void #cpp_method #foreign imgui "?SetInt@ImGuiStorage@@QEAAXIH@Z"; + GetBool :: (this: *Storage, key: ID, default_val := false) -> bool #cpp_method #foreign imgui "?GetBool@ImGuiStorage@@QEBA_NI_N@Z"; + SetBool :: (this: *Storage, key: ID, val: bool) -> void #cpp_method #foreign imgui "?SetBool@ImGuiStorage@@QEAAXI_N@Z"; + GetFloat :: (this: *Storage, key: ID, default_val: float = 0.0) -> float #cpp_method #foreign imgui "?GetFloat@ImGuiStorage@@QEBAMIM@Z"; + SetFloat :: (this: *Storage, key: ID, val: float) -> void #cpp_method #foreign imgui "?SetFloat@ImGuiStorage@@QEAAXIM@Z"; + GetVoidPtr :: (this: *Storage, key: ID) -> *void #cpp_method #foreign imgui "?GetVoidPtr@ImGuiStorage@@QEBAPEAXI@Z"; + SetVoidPtr :: (this: *Storage, key: ID, val: *void) -> void #cpp_method #foreign imgui "?SetVoidPtr@ImGuiStorage@@QEAAXIPEAX@Z"; + + // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. + // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) + // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; + GetIntRef :: (this: *Storage, key: ID, default_val: s32 = 0) -> *s32 #cpp_method #foreign imgui "?GetIntRef@ImGuiStorage@@QEAAPEAHIH@Z"; + GetBoolRef :: (this: *Storage, key: ID, default_val := false) -> *bool #cpp_method #foreign imgui "?GetBoolRef@ImGuiStorage@@QEAAPEA_NI_N@Z"; + GetFloatRef :: (this: *Storage, key: ID, default_val: float = 0.0) -> *float #cpp_method #foreign imgui "?GetFloatRef@ImGuiStorage@@QEAAPEAMIM@Z"; + GetVoidPtrRef :: (this: *Storage, key: ID, default_val: *void = null) -> **void #cpp_method #foreign imgui "?GetVoidPtrRef@ImGuiStorage@@QEAAPEAPEAXIPEAX@Z"; + + // Advanced: for quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + BuildSortByKey :: (this: *Storage) -> void #cpp_method #foreign imgui "?BuildSortByKey@ImGuiStorage@@QEAAXXZ"; + + // Obsolete: use on your own storage if you know only integer are being stored (open/close all tree nodes) + SetAllInt :: (this: *Storage, val: s32) -> void #cpp_method #foreign imgui "?SetAllInt@ImGuiStorage@@QEAAXH@Z"; +} + +// Flags for ImGuiListClipper (currently not fully exposed in function calls: a future refactor will likely add this to ImGuiListClipper::Begin function equivalent) +ListClipperFlags :: enum_flags s32 { + None :: 0x0; + NoSetTableRowCounters :: 0x1; + + ImGuiListClipperFlags_None :: None; + ImGuiListClipperFlags_NoSetTableRowCounters :: NoSetTableRowCounters; +} + +// Helper: Manually clip large list of items. +// If you have lots evenly spaced items and you have random access to the list, you can perform coarse +// clipping based on visibility to only submit items that are in view. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, and generally +// fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to easily +// scale using lists with tens of thousands of items without a problem) +// Usage: +// ImGuiListClipper clipper; +// clipper.Begin(1000); // We have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// Generally what happens is: +// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not. +// - User code submit that one element. +// - Clipper can measure the height of the first element +// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element. +// - User code submit visible elements. +// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. +ListClipper :: struct { + Ctx: *ImGuiContext; // Parent UI context + DisplayStart: s32; // First item to display, updated by each call to Step() + DisplayEnd: s32; // End of items to display (exclusive) + ItemsCount: s32; // [Internal] Number of items + ItemsHeight: float; // [Internal] Height of item after a first step and item submission can calculate it + StartPosY: float64; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed + StartSeekOffsetY: float64; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows. + TempData: *void; // [Internal] Internal data + Flags: ListClipperFlags; // [Internal] Flags, currently not yet well exposed. + + // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step, and you can call SeekCursorForItem() manually if you need) + // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). + Constructor :: (this: *ListClipper) -> void #cpp_method #foreign imgui "??0ImGuiListClipper@@QEAA@XZ"; + Destructor :: (this: *ListClipper) -> void #cpp_method #foreign imgui "??1ImGuiListClipper@@QEAA@XZ"; + Begin :: (this: *ListClipper, items_count: s32, items_height: float = -1.0) -> void #cpp_method #foreign imgui "?Begin@ImGuiListClipper@@QEAAXHM@Z"; + End :: (this: *ListClipper) -> void #cpp_method #foreign imgui "?End@ImGuiListClipper@@QEAAXXZ"; + Step :: (this: *ListClipper) -> bool #cpp_method #foreign imgui "?Step@ImGuiListClipper@@QEAA_NXZ"; + + IncludeItemsByIndex :: (this: *ListClipper, item_begin: s32, item_end: s32) -> void #cpp_method #foreign imgui "?IncludeItemsByIndex@ImGuiListClipper@@QEAAXHH@Z"; + + // Seek cursor toward given item. This is automatically called while stepping. + // - The only reason to call this is: you can use ImGuiListClipper::Begin(INT_MAX) if you don't know item count ahead of time. + // - In this case, after all steps are done, you'll want to call SeekCursorForItem(item_count). + SeekCursorForItem :: (this: *ListClipper, item_index: s32) -> void #cpp_method #foreign imgui "?SeekCursorForItem@ImGuiListClipper@@QEAAXH@Z"; +} + +// Flags for BeginMultiSelect() +MultiSelectFlags :: enum_flags s32 { + None :: 0x0; + SingleSelect :: 0x1; + NoSelectAll :: 0x2; + NoRangeSelect :: 0x4; + NoAutoSelect :: 0x8; + NoAutoClear :: 0x10; + NoAutoClearOnReselect :: 0x20; + BoxSelect1d :: 0x40; + BoxSelect2d :: 0x80; + BoxSelectNoScroll :: 0x100; + ClearOnEscape :: 0x200; + ClearOnClickVoid :: 0x400; + ScopeWindow :: 0x800; + ScopeRect :: 0x1000; + SelectOnClick :: 0x2000; + SelectOnClickRelease :: 0x4000; + + NavWrapX :: 0x10000; + NoSelectOnRightClick :: 0x20000; + + ImGuiMultiSelectFlags_None :: None; + ImGuiMultiSelectFlags_SingleSelect :: SingleSelect; + ImGuiMultiSelectFlags_NoSelectAll :: NoSelectAll; + ImGuiMultiSelectFlags_NoRangeSelect :: NoRangeSelect; + ImGuiMultiSelectFlags_NoAutoSelect :: NoAutoSelect; + ImGuiMultiSelectFlags_NoAutoClear :: NoAutoClear; + ImGuiMultiSelectFlags_NoAutoClearOnReselect :: NoAutoClearOnReselect; + ImGuiMultiSelectFlags_BoxSelect1d :: BoxSelect1d; + ImGuiMultiSelectFlags_BoxSelect2d :: BoxSelect2d; + ImGuiMultiSelectFlags_BoxSelectNoScroll :: BoxSelectNoScroll; + ImGuiMultiSelectFlags_ClearOnEscape :: ClearOnEscape; + ImGuiMultiSelectFlags_ClearOnClickVoid :: ClearOnClickVoid; + ImGuiMultiSelectFlags_ScopeWindow :: ScopeWindow; + ImGuiMultiSelectFlags_ScopeRect :: ScopeRect; + ImGuiMultiSelectFlags_SelectOnClick :: SelectOnClick; + ImGuiMultiSelectFlags_SelectOnClickRelease :: SelectOnClickRelease; + + ImGuiMultiSelectFlags_NavWrapX :: NavWrapX; + ImGuiMultiSelectFlags_NoSelectOnRightClick :: NoSelectOnRightClick; +} + +// Main IO structure returned by BeginMultiSelect()/EndMultiSelect(). +// This mainly contains a list of selection requests. +// - Use 'Demo->Tools->Debug Log->Selection' to see requests as they happen. +// - Some fields are only useful if your list is dynamic and allows deletion (getting post-deletion focus/state right is shown in the demo) +// - Below: who reads/writes each fields? 'r'=read, 'w'=write, 'ms'=multi-select code, 'app'=application/user code. +MultiSelectIO :: struct { + Requests: ImVector(SelectionRequest); // ms:w, app:r / ms:w app:r // Requests to apply to your selection data. + RangeSrcItem: SelectionUserData; // ms:w app:r / // (If using clipper) Begin: Source item (often the first selected item) must never be clipped: use clipper.IncludeItemByIndex() to ensure it is submitted. + NavIdItem: SelectionUserData; // ms:w, app:r / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items). + NavIdSelected: bool; // ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId (if part of submitted items). + RangeSrcReset: bool; // app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection). + ItemsCount: s32; // ms:w, app:r / app:r // 'int items_count' parameter to BeginMultiSelect() is copied here for convenience, allowing simpler calls to your ApplyRequests handler. Not used internally. +} + +// Selection request type +SelectionRequestType :: enum s32 { + None :: 0; + SetAll :: 1; + SetRange :: 2; + + ImGuiSelectionRequestType_None :: None; + ImGuiSelectionRequestType_SetAll :: SetAll; + ImGuiSelectionRequestType_SetRange :: SetRange; +} + +// Selection request item +SelectionRequest :: struct { + Type: SelectionRequestType; // ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 Clear + 1 SetRange with a single-item range. + Selected: bool; // ms:w, app:r / ms:w, app:r // Parameter for SetAll/SetRange requests (true = select, false = unselect) + RangeDirection: ImS8; // / ms:w app:r // Parameter for SetRange request: +1 when RangeFirstItem comes before RangeLastItem, -1 otherwise. Useful if you want to preserve selection order on a backward Shift+Click. + RangeFirstItem: SelectionUserData; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom). + RangeLastItem: SelectionUserData; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top). Inclusive! +} + +// Optional helper to store multi-selection state + apply multi-selection requests. +// - Used by our demos and provided as a convenience to easily implement basic multi-selection. +// - Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' +// Or you can check 'if (Contains(id)) { ... }' for each possible object if their number is not too high to iterate. +// - USING THIS IS NOT MANDATORY. This is only a helper and not a required API. +// To store a multi-selection, in your application you could: +// - Use this helper as a convenience. We use our simple key->value ImGuiStorage as a std::set replacement. +// - Use your own external storage: e.g. std::set, std::vector, interval trees, intrusively stored selection etc. +// In ImGuiSelectionBasicStorage we: +// - always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO) +// - use the AdapterIndexToStorageId() indirection layer to abstract how persistent selection data is derived from an index. +// - use decently optimized logic to allow queries and insertion of very large selection sets. +// - do not preserve selection order. +// Many combinations are possible depending on how you prefer to store your items and how you prefer to store your selection. +// Large applications are likely to eventually want to get rid of this indirection layer and do their own thing. +// See https://github.com/ocornut/imgui/wiki/Multi-Select for details and pseudo-code using this helper. +SelectionBasicStorage :: struct { + Size: s32; // // Number of selected items, maintained by this helper. + PreserveOrder: bool; // = false // GetNextSelectedItem() will return ordered selection (currently implemented by two additional sorts of selection. Could be improved) + UserData: *void; // = NULL // User data for use by adapter function // e.g. selection.UserData = (void*)my_items; + AdapterIndexToStorageId: #type (self: *SelectionBasicStorage, idx: s32) -> ID #c_call; // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->UserData)[idx]->ID; }; + _SelectionOrder: s32; // [Internal] Increasing counter to store selection order + _Storage: Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not accessing directly: iterate with GetNextSelectedItem(). + + // Methods + Constructor :: (this: *SelectionBasicStorage) -> void #cpp_method #foreign imgui "??0ImGuiSelectionBasicStorage@@QEAA@XZ"; + ApplyRequests :: (this: *SelectionBasicStorage, ms_io: *MultiSelectIO) -> void #cpp_method #foreign imgui "?ApplyRequests@ImGuiSelectionBasicStorage@@QEAAXPEAUImGuiMultiSelectIO@@@Z"; + Contains :: (this: *SelectionBasicStorage, id: ID) -> bool #cpp_method #foreign imgui "?Contains@ImGuiSelectionBasicStorage@@QEBA_NI@Z"; + Clear :: (this: *SelectionBasicStorage) -> void #cpp_method #foreign imgui "?Clear@ImGuiSelectionBasicStorage@@QEAAXXZ"; + Swap :: (this: *SelectionBasicStorage, r: *SelectionBasicStorage) -> void #cpp_method #foreign imgui "?Swap@ImGuiSelectionBasicStorage@@QEAAXAEAU1@@Z"; + SetItemSelected :: (this: *SelectionBasicStorage, id: ID, selected: bool) -> void #cpp_method #foreign imgui "?SetItemSelected@ImGuiSelectionBasicStorage@@QEAAXI_N@Z"; + GetNextSelectedItem :: (this: *SelectionBasicStorage, opaque_it: **void, out_id: *ID) -> bool #cpp_method #foreign imgui "?GetNextSelectedItem@ImGuiSelectionBasicStorage@@QEAA_NPEAPEAXPEAI@Z"; +} + +// Optional helper to apply multi-selection requests to existing randomly accessible storage. +// Convenient if you want to quickly wire multi-select API on e.g. an array of bool or items storing their own selection state. +SelectionExternalStorage :: struct { + UserData: *void; // User data for use by adapter function // e.g. selection.UserData = (void*)my_items; + AdapterSetItemSelected: #type (self: *SelectionExternalStorage, idx: s32, selected: bool) -> void #c_call; // e.g. AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int idx, bool selected) { ((MyItems**)self->UserData)[idx]->Selected = selected; } + + // Methods + Constructor :: (this: *SelectionExternalStorage) -> void #cpp_method #foreign imgui "??0ImGuiSelectionExternalStorage@@QEAA@XZ"; + ApplyRequests :: (this: *SelectionExternalStorage, ms_io: *MultiSelectIO) -> void #cpp_method #foreign imgui "?ApplyRequests@ImGuiSelectionExternalStorage@@QEAAXPEAUImGuiMultiSelectIO@@@Z"; +} + +ImDrawIdx :: u16; + +// Typically, 1 command = 1 GPU draw call (unless command is a callback) +// - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, +// this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// Backends made for <1.71. will typically ignore the VtxOffset fields. +// - The ClipRect/TexRef/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). +ImDrawCmd :: struct { + ClipRect: ImVec4; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + TexRef: ImTextureRef; // 16 // Reference to a font/texture atlas (where backend called ImTextureData::SetTexID()) or to a user-provided texture ID (via e.g. ImGui::Image() calls). Both will lead to a ImTextureID value. + VtxOffset: u32; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. + IdxOffset: u32; // 4 // Start offset in index buffer. + ElemCount: u32; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + UserCallback: ImDrawCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. + UserCallbackData: *void; // 4-8 // Callback user data (when UserCallback != NULL). If called AddCallback() with size == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > 0, this is pointing to a buffer where data is stored. + UserCallbackDataSize: s32; // 4 // Size of callback user data when using storage, otherwise 0. + UserCallbackDataOffset: s32; // 4 // [Internal] Offset of callback user data when using storage, otherwise -1. +} + +ImDrawVert :: struct { + pos: ImVec2; + uv: ImVec2; + col: ImU32; +} + +// [Internal] For use by ImDrawList +ImDrawCmdHeader :: struct { + ClipRect: ImVec4; + TexRef: ImTextureRef; + VtxOffset: u32; +} + +// Forward declarations: ImDrawList, ImFontAtlas layer +ImDrawChannel :: struct { + _CmdBuffer: ImVector(ImDrawCmd); + _IdxBuffer: ImVector(ImDrawIdx); +} + +// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. +// This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. +ImDrawListSplitter :: struct { + _Current: s32; // Current channel number (0) + _Count: s32; // Number of active channels (1+) + _Channels: ImVector(ImDrawChannel); // Draw channels (not resized down so _Count might be < Channels.Size) + + ClearFreeMemory :: (this: *ImDrawListSplitter) -> void #cpp_method #foreign imgui "?ClearFreeMemory@ImDrawListSplitter@@QEAAXXZ"; + Split :: (this: *ImDrawListSplitter, draw_list: *ImDrawList, count: s32) -> void #cpp_method #foreign imgui "?Split@ImDrawListSplitter@@QEAAXPEAUImDrawList@@H@Z"; + Merge :: (this: *ImDrawListSplitter, draw_list: *ImDrawList) -> void #cpp_method #foreign imgui "?Merge@ImDrawListSplitter@@QEAAXPEAUImDrawList@@@Z"; + SetCurrentChannel :: (this: *ImDrawListSplitter, draw_list: *ImDrawList, channel_idx: s32) -> void #cpp_method #foreign imgui "?SetCurrentChannel@ImDrawListSplitter@@QEAAXPEAUImDrawList@@H@Z"; +} + +// Flags for ImDrawList functions +// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused) +ImDrawFlags :: enum_flags s32 { + None :: 0x0; + Closed :: 0x1; + RoundCornersTopLeft :: 0x10; + RoundCornersTopRight :: 0x20; + RoundCornersBottomLeft :: 0x40; + RoundCornersBottomRight :: 0x80; + RoundCornersNone :: 0x100; + RoundCornersTop :: 0x30; + RoundCornersBottom :: 0xc0; + RoundCornersLeft :: 0x50; + RoundCornersRight :: 0xa0; + RoundCornersAll :: 0xf0; + RoundCornersDefault_ :: 0xf0; + RoundCornersMask_ :: 0x1f0; + + ImDrawFlags_None :: None; + ImDrawFlags_Closed :: Closed; + ImDrawFlags_RoundCornersTopLeft :: RoundCornersTopLeft; + ImDrawFlags_RoundCornersTopRight :: RoundCornersTopRight; + ImDrawFlags_RoundCornersBottomLeft :: RoundCornersBottomLeft; + ImDrawFlags_RoundCornersBottomRight :: RoundCornersBottomRight; + ImDrawFlags_RoundCornersNone :: RoundCornersNone; + ImDrawFlags_RoundCornersTop :: RoundCornersTop; + ImDrawFlags_RoundCornersBottom :: RoundCornersBottom; + ImDrawFlags_RoundCornersLeft :: RoundCornersLeft; + ImDrawFlags_RoundCornersRight :: RoundCornersRight; + ImDrawFlags_RoundCornersAll :: RoundCornersAll; + ImDrawFlags_RoundCornersDefault_ :: RoundCornersDefault_; + ImDrawFlags_RoundCornersMask_ :: RoundCornersMask_; +} + +// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. +// It is however possible to temporarily alter flags between calls to ImDrawList:: functions. +ImDrawListFlags :: enum_flags s32 { + None :: 0x0; + AntiAliasedLines :: 0x1; + AntiAliasedLinesUseTex :: 0x2; + AntiAliasedFill :: 0x4; + AllowVtxOffset :: 0x8; + + ImDrawListFlags_None :: None; + ImDrawListFlags_AntiAliasedLines :: AntiAliasedLines; + ImDrawListFlags_AntiAliasedLinesUseTex :: AntiAliasedLinesUseTex; + ImDrawListFlags_AntiAliasedFill :: AntiAliasedFill; + ImDrawListFlags_AllowVtxOffset :: AllowVtxOffset; +} + +// Draw command list +// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame, +// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. +// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to +// access the current window draw list and draw custom primitives. +// You can interleave normal ImGui:: calls and adding primitives to the current draw list. +// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). +// You are totally free to apply whatever transformation matrix you want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) +// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. +ImDrawList :: struct { + CmdBuffer: ImVector(ImDrawCmd); // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + IdxBuffer: ImVector(ImDrawIdx); // Index buffer. Each command consume ImDrawCmd::ElemCount of those + VtxBuffer: ImVector(ImDrawVert); // Vertex buffer. + Flags: ImDrawListFlags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + + _VtxCurrentIdx: u32; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. + _Data: *ImDrawListSharedData; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) + _VtxWritePtr: *ImDrawVert; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + _IdxWritePtr: *ImDrawIdx; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + _Path: ImVector(ImVec2); // [Internal] current path building + _CmdHeader: ImDrawCmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). + _Splitter: ImDrawListSplitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) + _ClipRectStack: ImVector(ImVec4); // [Internal] + _TextureStack: ImVector(ImTextureRef); // [Internal] + _CallbacksDataBuf: ImVector(ImU8); // [Internal] + _FringeScale: float; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content + _OwnerName: *u8; // Pointer to owner window's name for debugging + + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData(). + // (advanced: you may create and use your own ImDrawListSharedData so you can use ImDrawList without ImGui, but that's more involved) + Constructor :: (this: *ImDrawList, shared_data: *ImDrawListSharedData) -> void #cpp_method #foreign imgui "??0ImDrawList@@QEAA@PEAUImDrawListSharedData@@@Z"; + Destructor :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "??1ImDrawList@@QEAA@XZ"; + + PushClipRect :: (this: *ImDrawList, clip_rect_min: *ImVec2, clip_rect_max: *ImVec2, intersect_with_current_clip_rect := false) -> void #cpp_method #foreign imgui "?PushClipRect@ImDrawList@@QEAAXAEBUImVec2@@0_N@Z"; + PushClipRect :: (this: *ImDrawList, clip_rect_min: ImVec2, clip_rect_max: ImVec2, intersect_with_current_clip_rect := false) #no_context { + PushClipRect(this, *clip_rect_min, *clip_rect_max, intersect_with_current_clip_rect); + } + PushClipRectFullScreen :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?PushClipRectFullScreen@ImDrawList@@QEAAXXZ"; + PopClipRect :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?PopClipRect@ImDrawList@@QEAAXXZ"; + PushTexture :: (this: *ImDrawList, tex_ref: ImTextureRef) -> void #cpp_method #foreign imgui "?PushTexture@ImDrawList@@QEAAXUImTextureRef@@@Z"; + PopTexture :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?PopTexture@ImDrawList@@QEAAXXZ"; + + // Primitives + // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. + // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. + // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). + // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. + // In future versions we will use textures to provide cheaper and higher-quality circles. + // Use AddNgon() and AddNgonFilled() functions if you need to guarantee a specific number of sides. + AddLine :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, col: ImU32, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddLine@ImDrawList@@QEAAXAEBUImVec2@@0IM@Z"; + AddLine :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, col: ImU32, thickness: float = 1.0) #no_context { + AddLine(this, *p1, *p2, col, thickness); + } + AddRect :: (this: *ImDrawList, p_min: *ImVec2, p_max: *ImVec2, col: ImU32, rounding: float = 0.0, flags: ImDrawFlags = .None, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddRect@ImDrawList@@QEAAXAEBUImVec2@@0IMHM@Z"; + AddRect :: (this: *ImDrawList, p_min: ImVec2, p_max: ImVec2, col: ImU32, rounding: float = 0.0, flags: ImDrawFlags = .None, thickness: float = 1.0) #no_context { + AddRect(this, *p_min, *p_max, col, rounding, flags, thickness); + } + AddRectFilled :: (this: *ImDrawList, p_min: *ImVec2, p_max: *ImVec2, col: ImU32, rounding: float = 0.0, flags: ImDrawFlags = .None) -> void #cpp_method #foreign imgui "?AddRectFilled@ImDrawList@@QEAAXAEBUImVec2@@0IMH@Z"; + AddRectFilled :: (this: *ImDrawList, p_min: ImVec2, p_max: ImVec2, col: ImU32, rounding: float = 0.0, flags: ImDrawFlags = .None) #no_context { + AddRectFilled(this, *p_min, *p_max, col, rounding, flags); + } + AddRectFilledMultiColor :: (this: *ImDrawList, p_min: *ImVec2, p_max: *ImVec2, col_upr_left: ImU32, col_upr_right: ImU32, col_bot_right: ImU32, col_bot_left: ImU32) -> void #cpp_method #foreign imgui "?AddRectFilledMultiColor@ImDrawList@@QEAAXAEBUImVec2@@0IIII@Z"; + AddRectFilledMultiColor :: (this: *ImDrawList, p_min: ImVec2, p_max: ImVec2, col_upr_left: ImU32, col_upr_right: ImU32, col_bot_right: ImU32, col_bot_left: ImU32) #no_context { + AddRectFilledMultiColor(this, *p_min, *p_max, col_upr_left, col_upr_right, col_bot_right, col_bot_left); + } + AddQuad :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, p4: *ImVec2, col: ImU32, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddQuad@ImDrawList@@QEAAXAEBUImVec2@@000IM@Z"; + AddQuad :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, p3: ImVec2, p4: ImVec2, col: ImU32, thickness: float = 1.0) #no_context { + AddQuad(this, *p1, *p2, *p3, *p4, col, thickness); + } + AddQuadFilled :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, p4: *ImVec2, col: ImU32) -> void #cpp_method #foreign imgui "?AddQuadFilled@ImDrawList@@QEAAXAEBUImVec2@@000I@Z"; + AddQuadFilled :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, p3: ImVec2, p4: ImVec2, col: ImU32) #no_context { + AddQuadFilled(this, *p1, *p2, *p3, *p4, col); + } + AddTriangle :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, col: ImU32, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddTriangle@ImDrawList@@QEAAXAEBUImVec2@@00IM@Z"; + AddTriangle :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, p3: ImVec2, col: ImU32, thickness: float = 1.0) #no_context { + AddTriangle(this, *p1, *p2, *p3, col, thickness); + } + AddTriangleFilled :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, col: ImU32) -> void #cpp_method #foreign imgui "?AddTriangleFilled@ImDrawList@@QEAAXAEBUImVec2@@00I@Z"; + AddTriangleFilled :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, p3: ImVec2, col: ImU32) #no_context { + AddTriangleFilled(this, *p1, *p2, *p3, col); + } + AddCircle :: (this: *ImDrawList, center: *ImVec2, radius: float, col: ImU32, num_segments: s32 = 0, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddCircle@ImDrawList@@QEAAXAEBUImVec2@@MIHM@Z"; + AddCircle :: (this: *ImDrawList, center: ImVec2, radius: float, col: ImU32, num_segments: s32 = 0, thickness: float = 1.0) #no_context { + AddCircle(this, *center, radius, col, num_segments, thickness); + } + AddCircleFilled :: (this: *ImDrawList, center: *ImVec2, radius: float, col: ImU32, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?AddCircleFilled@ImDrawList@@QEAAXAEBUImVec2@@MIH@Z"; + AddCircleFilled :: (this: *ImDrawList, center: ImVec2, radius: float, col: ImU32, num_segments: s32 = 0) #no_context { + AddCircleFilled(this, *center, radius, col, num_segments); + } + AddNgon :: (this: *ImDrawList, center: *ImVec2, radius: float, col: ImU32, num_segments: s32, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddNgon@ImDrawList@@QEAAXAEBUImVec2@@MIHM@Z"; + AddNgon :: (this: *ImDrawList, center: ImVec2, radius: float, col: ImU32, num_segments: s32, thickness: float = 1.0) #no_context { + AddNgon(this, *center, radius, col, num_segments, thickness); + } + AddNgonFilled :: (this: *ImDrawList, center: *ImVec2, radius: float, col: ImU32, num_segments: s32) -> void #cpp_method #foreign imgui "?AddNgonFilled@ImDrawList@@QEAAXAEBUImVec2@@MIH@Z"; + AddNgonFilled :: (this: *ImDrawList, center: ImVec2, radius: float, col: ImU32, num_segments: s32) #no_context { + AddNgonFilled(this, *center, radius, col, num_segments); + } + AddEllipse :: (this: *ImDrawList, center: *ImVec2, radius: *ImVec2, col: ImU32, rot: float = 0.0, num_segments: s32 = 0, thickness: float = 1.0) -> void #cpp_method #foreign imgui "?AddEllipse@ImDrawList@@QEAAXAEBUImVec2@@0IMHM@Z"; + AddEllipse :: (this: *ImDrawList, center: ImVec2, radius: ImVec2, col: ImU32, rot: float = 0.0, num_segments: s32 = 0, thickness: float = 1.0) #no_context { + AddEllipse(this, *center, *radius, col, rot, num_segments, thickness); + } + AddEllipseFilled :: (this: *ImDrawList, center: *ImVec2, radius: *ImVec2, col: ImU32, rot: float = 0.0, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?AddEllipseFilled@ImDrawList@@QEAAXAEBUImVec2@@0IMH@Z"; + AddEllipseFilled :: (this: *ImDrawList, center: ImVec2, radius: ImVec2, col: ImU32, rot: float = 0.0, num_segments: s32 = 0) #no_context { + AddEllipseFilled(this, *center, *radius, col, rot, num_segments); + } + AddText :: (this: *ImDrawList, pos: *ImVec2, col: ImU32, text_begin: *u8, text_end: *u8 = null) -> void #cpp_method #foreign imgui "?AddText@ImDrawList@@QEAAXAEBUImVec2@@IPEBD1@Z"; + AddText :: (this: *ImDrawList, pos: ImVec2, col: ImU32, text: string) #no_context { + AddText(this, *pos, col, text.data, text.data + text.count); + } + AddText :: (this: *ImDrawList, font: *ImFont, font_size: float, pos: *ImVec2, col: ImU32, text_begin: *u8, text_end: *u8 = null, wrap_width: float = 0.0, cpu_fine_clip_rect: *ImVec4 = null) -> void #cpp_method #foreign imgui "?AddText@ImDrawList@@QEAAXPEAUImFont@@MAEBUImVec2@@IPEBD2MPEBUImVec4@@@Z"; + AddText :: (this: *ImDrawList, font: *ImFont, font_size: float, pos: ImVec2, col: ImU32, text: string, wrap_width: float = 0.0, cpu_fine_clip_rect: *ImVec4 = null) #no_context { + AddText(this, font, font_size, *pos, col, text.data, text.data + text.count, wrap_width, cpu_fine_clip_rect); + } + AddBezierCubic :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, p4: *ImVec2, col: ImU32, thickness: float, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?AddBezierCubic@ImDrawList@@QEAAXAEBUImVec2@@000IMH@Z"; + AddBezierCubic :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, p3: ImVec2, p4: ImVec2, col: ImU32, thickness: float, num_segments: s32 = 0) #no_context { + AddBezierCubic(this, *p1, *p2, *p3, *p4, col, thickness, num_segments); + } + AddBezierQuadratic :: (this: *ImDrawList, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, col: ImU32, thickness: float, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?AddBezierQuadratic@ImDrawList@@QEAAXAEBUImVec2@@00IMH@Z"; + AddBezierQuadratic :: (this: *ImDrawList, p1: ImVec2, p2: ImVec2, p3: ImVec2, col: ImU32, thickness: float, num_segments: s32 = 0) #no_context { + AddBezierQuadratic(this, *p1, *p2, *p3, col, thickness, num_segments); + } + + // General polygon + // - Only simple polygons are supported by filling functions (no self-intersections, no holes). + // - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library. + AddPolyline :: (this: *ImDrawList, points: *ImVec2, num_points: s32, col: ImU32, flags: ImDrawFlags, thickness: float) -> void #cpp_method #foreign imgui "?AddPolyline@ImDrawList@@QEAAXPEBUImVec2@@HIHM@Z"; + AddConvexPolyFilled :: (this: *ImDrawList, points: *ImVec2, num_points: s32, col: ImU32) -> void #cpp_method #foreign imgui "?AddConvexPolyFilled@ImDrawList@@QEAAXPEBUImVec2@@HI@Z"; + AddConcavePolyFilled :: (this: *ImDrawList, points: *ImVec2, num_points: s32, col: ImU32) -> void #cpp_method #foreign imgui "?AddConcavePolyFilled@ImDrawList@@QEAAXPEBUImVec2@@HI@Z"; + + // Image primitives + // - Read FAQ to understand what ImTextureID/ImTextureRef are. + // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. + // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. + AddImage :: (this: *ImDrawList, tex_ref: ImTextureRef, p_min: *ImVec2, p_max: *ImVec2, uv_min: *ImVec2, uv_max: *ImVec2, col: ImU32 = 4294967295) -> void #cpp_method #foreign imgui "?AddImage@ImDrawList@@QEAAXUImTextureRef@@AEBUImVec2@@111I@Z"; + AddImage :: (this: *ImDrawList, tex_ref: ImTextureRef, p_min: ImVec2, p_max: ImVec2, uv_min: ImVec2 = ImVec2.{0, 0}, uv_max: ImVec2 = ImVec2.{1, 1}, col: ImU32 = 4294967295) #no_context { + AddImage(this, tex_ref, *p_min, *p_max, *uv_min, *uv_max, col); + } + AddImageQuad :: (this: *ImDrawList, tex_ref: ImTextureRef, p1: *ImVec2, p2: *ImVec2, p3: *ImVec2, p4: *ImVec2, uv1: *ImVec2, uv2: *ImVec2, uv3: *ImVec2, uv4: *ImVec2, col: ImU32 = 4294967295) -> void #cpp_method #foreign imgui "?AddImageQuad@ImDrawList@@QEAAXUImTextureRef@@AEBUImVec2@@1111111I@Z"; + AddImageQuad :: (this: *ImDrawList, tex_ref: ImTextureRef, p1: ImVec2, p2: ImVec2, p3: ImVec2, p4: ImVec2, uv1: ImVec2 = ImVec2.{0, 0}, uv2: ImVec2 = ImVec2.{1, 0}, uv3: ImVec2 = ImVec2.{1, 1}, uv4: ImVec2 = ImVec2.{0, 1}, col: ImU32 = 4294967295) #no_context { + AddImageQuad(this, tex_ref, *p1, *p2, *p3, *p4, *uv1, *uv2, *uv3, *uv4, col); + } + AddImageRounded :: (this: *ImDrawList, tex_ref: ImTextureRef, p_min: *ImVec2, p_max: *ImVec2, uv_min: *ImVec2, uv_max: *ImVec2, col: ImU32, rounding: float, flags: ImDrawFlags = .None) -> void #cpp_method #foreign imgui "?AddImageRounded@ImDrawList@@QEAAXUImTextureRef@@AEBUImVec2@@111IMH@Z"; + AddImageRounded :: (this: *ImDrawList, tex_ref: ImTextureRef, p_min: ImVec2, p_max: ImVec2, uv_min: ImVec2, uv_max: ImVec2, col: ImU32, rounding: float, flags: ImDrawFlags = .None) #no_context { + AddImageRounded(this, tex_ref, *p_min, *p_max, *uv_min, *uv_max, col, rounding, flags); + } + + PathArcTo :: (this: *ImDrawList, center: *ImVec2, radius: float, a_min: float, a_max: float, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?PathArcTo@ImDrawList@@QEAAXAEBUImVec2@@MMMH@Z"; + PathArcTo :: (this: *ImDrawList, center: ImVec2, radius: float, a_min: float, a_max: float, num_segments: s32 = 0) #no_context { + PathArcTo(this, *center, radius, a_min, a_max, num_segments); + } + PathArcToFast :: (this: *ImDrawList, center: *ImVec2, radius: float, a_min_of_12: s32, a_max_of_12: s32) -> void #cpp_method #foreign imgui "?PathArcToFast@ImDrawList@@QEAAXAEBUImVec2@@MHH@Z"; + PathArcToFast :: (this: *ImDrawList, center: ImVec2, radius: float, a_min_of_12: s32, a_max_of_12: s32) #no_context { + PathArcToFast(this, *center, radius, a_min_of_12, a_max_of_12); + } + PathEllipticalArcTo :: (this: *ImDrawList, center: *ImVec2, radius: *ImVec2, rot: float, a_min: float, a_max: float, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?PathEllipticalArcTo@ImDrawList@@QEAAXAEBUImVec2@@0MMMH@Z"; + PathEllipticalArcTo :: (this: *ImDrawList, center: ImVec2, radius: ImVec2, rot: float, a_min: float, a_max: float, num_segments: s32 = 0) #no_context { + PathEllipticalArcTo(this, *center, *radius, rot, a_min, a_max, num_segments); + } + PathBezierCubicCurveTo :: (this: *ImDrawList, p2: *ImVec2, p3: *ImVec2, p4: *ImVec2, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?PathBezierCubicCurveTo@ImDrawList@@QEAAXAEBUImVec2@@00H@Z"; + PathBezierCubicCurveTo :: (this: *ImDrawList, p2: ImVec2, p3: ImVec2, p4: ImVec2, num_segments: s32 = 0) #no_context { + PathBezierCubicCurveTo(this, *p2, *p3, *p4, num_segments); + } + PathBezierQuadraticCurveTo :: (this: *ImDrawList, p2: *ImVec2, p3: *ImVec2, num_segments: s32 = 0) -> void #cpp_method #foreign imgui "?PathBezierQuadraticCurveTo@ImDrawList@@QEAAXAEBUImVec2@@0H@Z"; + PathBezierQuadraticCurveTo :: (this: *ImDrawList, p2: ImVec2, p3: ImVec2, num_segments: s32 = 0) #no_context { + PathBezierQuadraticCurveTo(this, *p2, *p3, num_segments); + } + PathRect :: (this: *ImDrawList, rect_min: *ImVec2, rect_max: *ImVec2, rounding: float = 0.0, flags: ImDrawFlags = .None) -> void #cpp_method #foreign imgui "?PathRect@ImDrawList@@QEAAXAEBUImVec2@@0MH@Z"; + PathRect :: (this: *ImDrawList, rect_min: ImVec2, rect_max: ImVec2, rounding: float = 0.0, flags: ImDrawFlags = .None) #no_context { + PathRect(this, *rect_min, *rect_max, rounding, flags); + } + + // Advanced: Draw Callbacks + // - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom rendering commands (difficult to do correctly, but possible). + // - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default. + // - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. All standard backends are honoring this. + // - For some backends, the callback may access selected render-states exposed by the backend in a ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState. + // - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and using size>0 (copying pointed data into a buffer). + // - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in ImDrawCmd::UserCallbackData during render. + // - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data. + // - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to copy/store a simple void*. + AddCallback :: (this: *ImDrawList, callback: ImDrawCallback, userdata: *void, userdata_size: u64 = 0) -> void #cpp_method #foreign imgui "?AddCallback@ImDrawList@@QEAAXP6AXPEBU1@PEBUImDrawCmd@@@ZPEAX_K@Z"; + + // Advanced: Miscellaneous + AddDrawCmd :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?AddDrawCmd@ImDrawList@@QEAAXXZ"; + CloneOutput :: (this: *ImDrawList) -> *ImDrawList #cpp_method #foreign imgui "?CloneOutput@ImDrawList@@QEBAPEAU1@XZ"; + + // Advanced: Primitives allocations + // - We render triangles (three vertices) + // - All primitives needs to be reserved via PrimReserve() beforehand. + PrimReserve :: (this: *ImDrawList, idx_count: s32, vtx_count: s32) -> void #cpp_method #foreign imgui "?PrimReserve@ImDrawList@@QEAAXHH@Z"; + PrimUnreserve :: (this: *ImDrawList, idx_count: s32, vtx_count: s32) -> void #cpp_method #foreign imgui "?PrimUnreserve@ImDrawList@@QEAAXHH@Z"; + PrimRect :: (this: *ImDrawList, a: *ImVec2, b: *ImVec2, col: ImU32) -> void #cpp_method #foreign imgui "?PrimRect@ImDrawList@@QEAAXAEBUImVec2@@0I@Z"; + PrimRect :: (this: *ImDrawList, a: ImVec2, b: ImVec2, col: ImU32) #no_context { + PrimRect(this, *a, *b, col); + } + PrimRectUV :: (this: *ImDrawList, a: *ImVec2, b: *ImVec2, uv_a: *ImVec2, uv_b: *ImVec2, col: ImU32) -> void #cpp_method #foreign imgui "?PrimRectUV@ImDrawList@@QEAAXAEBUImVec2@@000I@Z"; + PrimRectUV :: (this: *ImDrawList, a: ImVec2, b: ImVec2, uv_a: ImVec2, uv_b: ImVec2, col: ImU32) #no_context { + PrimRectUV(this, *a, *b, *uv_a, *uv_b, col); + } + PrimQuadUV :: (this: *ImDrawList, a: *ImVec2, b: *ImVec2, c: *ImVec2, d: *ImVec2, uv_a: *ImVec2, uv_b: *ImVec2, uv_c: *ImVec2, uv_d: *ImVec2, col: ImU32) -> void #cpp_method #foreign imgui "?PrimQuadUV@ImDrawList@@QEAAXAEBUImVec2@@0000000I@Z"; + PrimQuadUV :: (this: *ImDrawList, a: ImVec2, b: ImVec2, c: ImVec2, d: ImVec2, uv_a: ImVec2, uv_b: ImVec2, uv_c: ImVec2, uv_d: ImVec2, col: ImU32) #no_context { + PrimQuadUV(this, *a, *b, *c, *d, *uv_a, *uv_b, *uv_c, *uv_d, col); + } + + // [Internal helpers] + _SetDrawListSharedData :: (this: *ImDrawList, data: *ImDrawListSharedData) -> void #cpp_method #foreign imgui "?_SetDrawListSharedData@ImDrawList@@QEAAXPEAUImDrawListSharedData@@@Z"; + _ResetForNewFrame :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_ResetForNewFrame@ImDrawList@@QEAAXXZ"; + _ClearFreeMemory :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_ClearFreeMemory@ImDrawList@@QEAAXXZ"; + _PopUnusedDrawCmd :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_PopUnusedDrawCmd@ImDrawList@@QEAAXXZ"; + _TryMergeDrawCmds :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_TryMergeDrawCmds@ImDrawList@@QEAAXXZ"; + _OnChangedClipRect :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_OnChangedClipRect@ImDrawList@@QEAAXXZ"; + _OnChangedTexture :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_OnChangedTexture@ImDrawList@@QEAAXXZ"; + _OnChangedVtxOffset :: (this: *ImDrawList) -> void #cpp_method #foreign imgui "?_OnChangedVtxOffset@ImDrawList@@QEAAXXZ"; + _SetTexture :: (this: *ImDrawList, tex_ref: ImTextureRef) -> void #cpp_method #foreign imgui "?_SetTexture@ImDrawList@@QEAAXUImTextureRef@@@Z"; + _CalcCircleAutoSegmentCount :: (this: *ImDrawList, radius: float) -> s32 #cpp_method #foreign imgui "?_CalcCircleAutoSegmentCount@ImDrawList@@QEBAHM@Z"; + _PathArcToFastEx :: (this: *ImDrawList, center: *ImVec2, radius: float, a_min_sample: s32, a_max_sample: s32, a_step: s32) -> void #cpp_method #foreign imgui "?_PathArcToFastEx@ImDrawList@@QEAAXAEBUImVec2@@MHHH@Z"; + _PathArcToFastEx :: (this: *ImDrawList, center: ImVec2, radius: float, a_min_sample: s32, a_max_sample: s32, a_step: s32) #no_context { + _PathArcToFastEx(this, *center, radius, a_min_sample, a_max_sample, a_step); + } + _PathArcToN :: (this: *ImDrawList, center: *ImVec2, radius: float, a_min: float, a_max: float, num_segments: s32) -> void #cpp_method #foreign imgui "?_PathArcToN@ImDrawList@@QEAAXAEBUImVec2@@MMMH@Z"; + _PathArcToN :: (this: *ImDrawList, center: ImVec2, radius: float, a_min: float, a_max: float, num_segments: s32) #no_context { + _PathArcToN(this, *center, radius, a_min, a_max, num_segments); + } +} + +// All draw data to render a Dear ImGui frame +// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, +// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) +ImDrawData :: struct { + Valid: bool; // Only valid after Render() is called and before the next NewFrame() is called. + CmdListsCount: s32; // == CmdLists.Size. (OBSOLETE: exists for legacy reasons). Number of ImDrawList* to render. + TotalIdxCount: s32; // For convenience, sum of all ImDrawList's IdxBuffer.Size + TotalVtxCount: s32; // For convenience, sum of all ImDrawList's VtxBuffer.Size + CmdLists: ImVector(*ImDrawList); // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. + DisplayPos: ImVec2; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) + DisplaySize: ImVec2; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) + FramebufferScale: ImVec2; // Amount of pixels for each unit of DisplaySize. Copied from viewport->FramebufferScale (== io.DisplayFramebufferScale for main viewport). Generally (1,1) on normal display, (2,2) on OSX with Retina display. + OwnerViewport: *Viewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). + Textures: *ImVector(*ImTextureData); // List of textures to update. Most of the times the list is shared by all ImDrawData, has only 1 texture and it doesn't need any update. This almost always points to ImGui::GetPlatformIO().Textures[]. May be overridden or set to NULL if you want to manually update textures. + + Clear :: (this: *ImDrawData) -> void #cpp_method #foreign imgui "?Clear@ImDrawData@@QEAAXXZ"; + AddDrawList :: (this: *ImDrawData, draw_list: *ImDrawList) -> void #cpp_method #foreign imgui "?AddDrawList@ImDrawData@@QEAAXPEAUImDrawList@@@Z"; + DeIndexAllBuffers :: (this: *ImDrawData) -> void #cpp_method #foreign imgui "?DeIndexAllBuffers@ImDrawData@@QEAAXXZ"; + ScaleClipRects :: (this: *ImDrawData, fb_scale: *ImVec2) -> void #cpp_method #foreign imgui "?ScaleClipRects@ImDrawData@@QEAAXAEBUImVec2@@@Z"; + ScaleClipRects :: (this: *ImDrawData, fb_scale: ImVec2) #no_context { + ScaleClipRects(this, *fb_scale); + } +} + +// We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. +// Most standard backends only support RGBA32 but we provide a single channel option for low-resource/embedded systems. +ImTextureFormat :: enum s32 { + RGBA32 :: 0; + Alpha8 :: 1; + + ImTextureFormat_RGBA32 :: RGBA32; + ImTextureFormat_Alpha8 :: Alpha8; +} + +// Status of a texture to communicate with Renderer Backend. +ImTextureStatus :: enum s32 { + OK :: 0; + Destroyed :: 1; + WantCreate :: 2; + WantUpdates :: 3; + WantDestroy :: 4; + + ImTextureStatus_OK :: OK; + ImTextureStatus_Destroyed :: Destroyed; + ImTextureStatus_WantCreate :: WantCreate; + ImTextureStatus_WantUpdates :: WantUpdates; + ImTextureStatus_WantDestroy :: WantDestroy; +} + +// Coordinates of a rectangle within a texture. +// When a texture is in ImTextureStatus_WantUpdates state, we provide a list of individual rectangles to copy to the graphics system. +// You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box. +ImTextureRect :: struct { + x: u16; // Upper-left coordinates of rectangle to update + y: u16; // Upper-left coordinates of rectangle to update + w: u16; // Size of rectangle to update (in pixels) + h: u16; // Size of rectangle to update (in pixels) +} + +// Specs and pixel storage for a texture used by Dear ImGui. +// This is only useful for (1) core library and (2) backends. End-user/applications do not need to care about this. +// Renderer Backends will create a GPU-side version of this. +// Why does we store two identifiers: TexID and BackendUserData? +// - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. +// - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. +// In columns below: who reads/writes each fields? 'r'=read, 'w'=write, 'core'=main library, 'backend'=renderer backend +ImTextureData :: struct { + UniqueID: s32; // w - // [DEBUG] Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. + Status: ImTextureStatus; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! + BackendUserData: *void; // - rw // Convenience storage for backend. Some backends may have enough with TexID. + TexID: ImTextureID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. + Format: ImTextureFormat; // w r // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 + Width: s32; // w r // Texture width + Height: s32; // w r // Texture height + BytesPerPixel: s32; // w r // 4 or 1 + Pixels: *u8; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. + UsedRect: ImTextureRect; // w r // Bounding box encompassing all past and queued Updates[]. + UpdateRect: ImTextureRect; // w r // Bounding box encompassing all queued Updates[]. + Updates: ImVector(ImTextureRect); // w r // Array of individual updates. + UnusedFrames: s32; // w r // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. + RefCount: u16; // w r // Number of contexts using this texture. Used during backend shutdown. + UseColors: bool; // w r // Tell whether our texture data is known to use colors (rather than just white + alpha). + WantDestroyNextFrame: bool; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. + + Create :: (this: *ImTextureData, format: ImTextureFormat, w: s32, h: s32) -> void #cpp_method #foreign imgui "?Create@ImTextureData@@QEAAXW4ImTextureFormat@@HH@Z"; + DestroyPixels :: (this: *ImTextureData) -> void #cpp_method #foreign imgui "?DestroyPixels@ImTextureData@@QEAAXXZ"; +} + +// A font input/source (we may rename this to ImFontSource in the future) +ImFontConfig :: struct { + Name: [40] u8; // // Name (strictly to ease debugging, hence limited size buffer) + FontData: *void; // // TTF/OTF data + FontDataSize: s32; // // TTF/OTF data size + FontDataOwnedByAtlas: bool; // true // TTF/OTF data ownership taken by the owner ImFontAtlas (will delete memory itself). SINCE 1.92, THE DATA NEEDS TO PERSIST FOR WHOLE DURATION OF ATLAS. + + MergeMode: bool; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. + PixelSnapH: bool; // false // Align every glyph AdvanceX to pixel boundaries. Prevents fractional font size from working correctly! Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, OversampleH/V will default to 1. + OversampleH: ImS8; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + OversampleV: ImS8; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. + EllipsisChar: ImWchar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + SizePixels: float; // // Output size in pixels for rasterizer (more or less maps to the resulting font height). + GlyphRanges: *ImWchar; // NULL // *LEGACY* THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). + GlyphExcludeRanges: *ImWchar; // NULL // Pointer to a small user-provided list of Unicode ranges (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. + + GlyphOffset: ImVec2; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. + GlyphMinAdvanceX: float; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. + GlyphMaxAdvanceX: float; // FLT_MAX // Maximum AdvanceX for glyphs + GlyphExtraAdvanceX: float; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. // FIXME-NEWATLAS: Intentionally unscaled + FontNo: ImU32; // 0 // Index of font within TTF/OTF file + FontLoaderFlags: u32; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. + + RasterizerMultiply: float; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. + RasterizerDensity: float; // 1.0f // [LEGACY: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported] DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. + ExtraSizeScale: float; // 1.0f // Extra rasterizer scale over SizePixels. + + Flags: ImFontFlags; // Font flags (don't use just yet, will be exposed in upcoming 1.92.X updates) + DstFont: *ImFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) + FontLoader: *ImFontLoader; // Custom font backend for this source (default source is the one stored in ImFontAtlas) + FontLoaderData: *void; // Font loader opaque storage (per font config) + + PixelSnapV: bool; // true // [Obsoleted in 1.91.6] Align Scaled GlyphOffset.y to pixel boundaries. + + Constructor :: (this: *ImFontConfig) -> void #cpp_method #foreign imgui "??0ImFontConfig@@QEAA@XZ"; +} + +// Hold rendering data for one glyph. +// (Note: some language parsers may fail to convert the bitfield members, in this case maybe drop store a single u32 or we can rework this) +ImFontGlyph :: struct { + __bitfield: u32; + /* + Colored: u32; /* 1 bits */ // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) + Visible: u32; /* 1 bits */ // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + SourceIdx: u32; /* 4 bits */ // Index of source in parent font + Codepoint: u32; /* 26 bits */ // 0x0000..0x10FFFF; + */ + + AdvanceX: float; // Horizontal distance to advance cursor/layout position. + X0: float; // Glyph corners. Offsets from current cursor/layout position. + Y0: float; // Glyph corners. Offsets from current cursor/layout position. + X1: float; // Glyph corners. Offsets from current cursor/layout position. + Y1: float; // Glyph corners. Offsets from current cursor/layout position. + U0: float; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. + V0: float; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. + U1: float; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. + V1: float; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. + PackId: s32; // [Internal] ImFontAtlasRectId value (FIXME: Cold data, could be moved elsewhere?) +} + +set_Colored :: (fields: *ImFontGlyph, value: bool) { + if value fields.__bitfield |= 1 << 0; + else fields.__bitfield &= ~cast(u32)(1 << 0); +} +get_Colored :: (fields: ImFontGlyph) -> bool { + return (fields.__bitfield & (1 << 0)) != 0; +} + +set_Visible :: (fields: *ImFontGlyph, value: bool) { + if value fields.__bitfield |= 1 << 1; + else fields.__bitfield &= ~cast(u32)(1 << 1); +} +get_Visible :: (fields: ImFontGlyph) -> bool { + return (fields.__bitfield & (1 << 1)) != 0; +} + +set_SourceIdx :: (fields: *ImFontGlyph, value: u32) { + MASK0: u32 : (0b1111 << 2); + fields.__bitfield = (fields.__bitfield & ~MASK0) | ((value << 2) & MASK0); +} +get_SourceIdx :: (fields: ImFontGlyph) -> u32 { + return ((fields.__bitfield & (0b1111 << 2)) >> 2); +} + +set_Codepoint :: (fields: *ImFontGlyph, value: u32) { + MASK0: u32 : (0b11_1111_1111_1111_1111_1111_1111 << 6); + fields.__bitfield = (fields.__bitfield & ~MASK0) | ((value << 6) & MASK0); +} +get_Codepoint :: (fields: ImFontGlyph) -> u32 { + return ((fields.__bitfield & (0b11_1111_1111_1111_1111_1111_1111 << 6)) >> 6); +} + + +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. +ImFontGlyphRangesBuilder :: struct { + UsedChars: ImVector(ImU32); // Store 1-bit per Unicode code point (0=unused, 1=used) + + AddText :: (this: *ImFontGlyphRangesBuilder, text: *u8, text_end: *u8 = null) -> void #cpp_method #foreign imgui "?AddText@ImFontGlyphRangesBuilder@@QEAAXPEBD0@Z"; + AddText :: (this: *ImFontGlyphRangesBuilder, text: string) #no_context { + AddText(this, text.data, text.data + text.count); + } + AddRanges :: (this: *ImFontGlyphRangesBuilder, ranges: *ImWchar) -> void #cpp_method #foreign imgui "?AddRanges@ImFontGlyphRangesBuilder@@QEAAXPEBG@Z"; + BuildRanges :: (this: *ImFontGlyphRangesBuilder, out_ranges: *ImVector(ImWchar)) -> void #cpp_method #foreign imgui "?BuildRanges@ImFontGlyphRangesBuilder@@QEAAXPEAU?$ImVector@G@@@Z"; +} + +// An opaque identifier to a rectangle in the atlas. -1 when invalid. +// The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it. +ImFontAtlasRectId :: s32; + +// Output of ImFontAtlas::GetCustomRect() when using custom rectangles. +// Those values may not be cached/stored as they are only valid for the current value of atlas->TexRef +// (this is in theory derived from ImTextureRect but we use separate structures for reasons) +ImFontAtlasRect :: struct { + x: u16; // Position (in current texture) + y: u16; // Position (in current texture) + w: u16; // Size + h: u16; // Size + uv0: ImVec2; // UV coordinates (in current texture) + uv1: ImVec2; // UV coordinates (in current texture) +} + +// Flags for ImFontAtlas build +ImFontAtlasFlags :: enum_flags s32 { + None :: 0x0; + NoPowerOfTwoHeight :: 0x1; + NoMouseCursors :: 0x2; + NoBakedLines :: 0x4; + + ImFontAtlasFlags_None :: None; + ImFontAtlasFlags_NoPowerOfTwoHeight :: NoPowerOfTwoHeight; + ImFontAtlasFlags_NoMouseCursors :: NoMouseCursors; + ImFontAtlasFlags_NoBakedLines :: NoBakedLines; +} + +// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: +// - One or more fonts. +// - Custom graphics data needed to render the shapes needed by Dear ImGui. +// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). +// - If you don't call any AddFont*** functions, the default font embedded in the code will be loaded for you. +// It is the rendering backend responsibility to upload texture into your graphics API: +// - ImGui_ImplXXXX_RenderDrawData() functions generally iterate platform_io->Textures[] to create/update/destroy each ImTextureData instance. +// - Backend then set ImTextureData's TexID and BackendUserData. +// - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID/ImTextureRef for more details. +// Legacy path: +// - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// Common pitfalls: +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. +// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. +// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, +// - Even though many functions are suffixed with "TTF", OTF data is supported just as well. +// - This is an old API and it is currently awkward for those and various other reasons! We will address them in the future! +ImFontAtlas :: struct { + Constructor :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "??0ImFontAtlas@@QEAA@XZ"; + Destructor :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "??1ImFontAtlas@@QEAA@XZ"; + AddFont :: (this: *ImFontAtlas, font_cfg: *ImFontConfig) -> *ImFont #cpp_method #foreign imgui "?AddFont@ImFontAtlas@@QEAAPEAUImFont@@PEBUImFontConfig@@@Z"; + AddFontDefault :: (this: *ImFontAtlas, font_cfg: *ImFontConfig = null) -> *ImFont #cpp_method #foreign imgui "?AddFontDefault@ImFontAtlas@@QEAAPEAUImFont@@PEBUImFontConfig@@@Z"; + AddFontDefaultVector :: (this: *ImFontAtlas, font_cfg: *ImFontConfig = null) -> *ImFont #cpp_method #foreign imgui "?AddFontDefaultVector@ImFontAtlas@@QEAAPEAUImFont@@PEBUImFontConfig@@@Z"; + AddFontDefaultBitmap :: (this: *ImFontAtlas, font_cfg: *ImFontConfig = null) -> *ImFont #cpp_method #foreign imgui "?AddFontDefaultBitmap@ImFontAtlas@@QEAAPEAUImFont@@PEBUImFontConfig@@@Z"; + AddFontFromFileTTF :: (this: *ImFontAtlas, filename: *u8, size_pixels: float = 0.0, font_cfg: *ImFontConfig = null, glyph_ranges: *ImWchar = null) -> *ImFont #cpp_method #foreign imgui "?AddFontFromFileTTF@ImFontAtlas@@QEAAPEAUImFont@@PEBDMPEBUImFontConfig@@PEBG@Z"; + AddFontFromMemoryTTF :: (this: *ImFontAtlas, font_data: *void, font_data_size: s32, size_pixels: float = 0.0, font_cfg: *ImFontConfig = null, glyph_ranges: *ImWchar = null) -> *ImFont #cpp_method #foreign imgui "?AddFontFromMemoryTTF@ImFontAtlas@@QEAAPEAUImFont@@PEAXHMPEBUImFontConfig@@PEBG@Z"; + AddFontFromMemoryCompressedTTF :: (this: *ImFontAtlas, compressed_font_data: *void, compressed_font_data_size: s32, size_pixels: float = 0.0, font_cfg: *ImFontConfig = null, glyph_ranges: *ImWchar = null) -> *ImFont #cpp_method #foreign imgui "?AddFontFromMemoryCompressedTTF@ImFontAtlas@@QEAAPEAUImFont@@PEBXHMPEBUImFontConfig@@PEBG@Z"; + AddFontFromMemoryCompressedBase85TTF :: (this: *ImFontAtlas, compressed_font_data_base85: *u8, size_pixels: float = 0.0, font_cfg: *ImFontConfig = null, glyph_ranges: *ImWchar = null) -> *ImFont #cpp_method #foreign imgui "?AddFontFromMemoryCompressedBase85TTF@ImFontAtlas@@QEAAPEAUImFont@@PEBDMPEBUImFontConfig@@PEBG@Z"; + RemoveFont :: (this: *ImFontAtlas, font: *ImFont) -> void #cpp_method #foreign imgui "?RemoveFont@ImFontAtlas@@QEAAXPEAUImFont@@@Z"; + + Clear :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "?Clear@ImFontAtlas@@QEAAXXZ"; + CompactCache :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "?CompactCache@ImFontAtlas@@QEAAXXZ"; + SetFontLoader :: (this: *ImFontAtlas, font_loader: *ImFontLoader) -> void #cpp_method #foreign imgui "?SetFontLoader@ImFontAtlas@@QEAAXPEBUImFontLoader@@@Z"; + + // As we are transitioning toward a new font system, we expect to obsolete those soon: + ClearInputData :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "?ClearInputData@ImFontAtlas@@QEAAXXZ"; + ClearFonts :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "?ClearFonts@ImFontAtlas@@QEAAXXZ"; + ClearTexData :: (this: *ImFontAtlas) -> void #cpp_method #foreign imgui "?ClearTexData@ImFontAtlas@@QEAAXXZ"; + + // Legacy path for build atlas + retrieving pixel data. + // - User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // - The pitch is always = Width * BytesPerPixels (1 or 4) + // - Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste). + // - From 1.92 with backends supporting ImGuiBackendFlags_RendererHasTextures: + // - Calling Build(), GetTexDataAsAlpha8(), GetTexDataAsRGBA32() is not needed. + // - In backend: replace calls to ImFontAtlas::SetTexID() with calls to ImTextureData::SetTexID() after honoring texture creation. + Build :: (this: *ImFontAtlas) -> bool #cpp_method #foreign imgui "?Build@ImFontAtlas@@QEAA_NXZ"; + GetTexDataAsAlpha8 :: (this: *ImFontAtlas, out_pixels: **u8, out_width: *s32, out_height: *s32, out_bytes_per_pixel: *s32 = null) -> void #cpp_method #foreign imgui "?GetTexDataAsAlpha8@ImFontAtlas@@QEAAXPEAPEAEPEAH11@Z"; + GetTexDataAsRGBA32 :: (this: *ImFontAtlas, out_pixels: **u8, out_width: *s32, out_height: *s32, out_bytes_per_pixel: *s32 = null) -> void #cpp_method #foreign imgui "?GetTexDataAsRGBA32@ImFontAtlas@@QEAAXPEAPEAEPEAH11@Z"; + + // Since 1.92: specifying glyph ranges is only useful/necessary if your backend doesn't support ImGuiBackendFlags_RendererHasTextures! + GetGlyphRangesDefault :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesDefault@ImFontAtlas@@QEAAPEBGXZ"; + + // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) + // NB: Make sure that your string are UTF-8 and NOT in your local code page. + // Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details. + // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. + GetGlyphRangesGreek :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesGreek@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesKorean :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesKorean@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesJapanese :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesJapanese@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesChineseFull :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesChineseFull@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesChineseSimplifiedCommon :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesChineseSimplifiedCommon@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesCyrillic :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesCyrillic@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesThai :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesThai@ImFontAtlas@@QEAAPEBGXZ"; + GetGlyphRangesVietnamese :: (this: *ImFontAtlas) -> *ImWchar #cpp_method #foreign imgui "?GetGlyphRangesVietnamese@ImFontAtlas@@QEAAPEBGXZ"; + + // Register and retrieve custom rectangles + // - You can request arbitrary rectangles to be packed into the atlas, for your own purpose. + // - Since 1.92.0, packing is done immediately in the function call (previously packing was done during the Build call) + // - You can render your pixels into the texture right after calling the AddCustomRect() functions. + // - VERY IMPORTANT: + // - Texture may be created/resized at any time when calling ImGui or ImFontAtlas functions. + // - IT WILL INVALIDATE RECTANGLE DATA SUCH AS UV COORDINATES. Always use latest values from GetCustomRect(). + // - UV coordinates are associated to the current texture identifier aka 'atlas->TexRef'. Both TexRef and UV coordinates are typically changed at the same time. + // - If you render colored output into your custom rectangles: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. + // - Read docs/FONTS.md for more details about using colorful icons. + // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI settings. + // - (Pre-1.92 names) ------------> (1.92 names) + // - GetCustomRectByIndex() --> Use GetCustomRect() + // - CalcCustomRectUV() --> Use GetCustomRect() and read uv0, uv1 fields. + // - AddCustomRectRegular() --> Renamed to AddCustomRect() + // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig + // - ImFontAtlasCustomRect --> Renamed to ImFontAtlasRect + AddCustomRect :: (this: *ImFontAtlas, width: s32, height: s32, out_r: *ImFontAtlasRect = null) -> ImFontAtlasRectId #cpp_method #foreign imgui "?AddCustomRect@ImFontAtlas@@QEAAHHHPEAUImFontAtlasRect@@@Z"; + RemoveCustomRect :: (this: *ImFontAtlas, id: ImFontAtlasRectId) -> void #cpp_method #foreign imgui "?RemoveCustomRect@ImFontAtlas@@QEAAXH@Z"; + GetCustomRect :: (this: *ImFontAtlas, id: ImFontAtlasRectId, out_r: *ImFontAtlasRect) -> bool #cpp_method #foreign imgui "?GetCustomRect@ImFontAtlas@@QEBA_NHPEAUImFontAtlasRect@@@Z"; + + Flags: ImFontAtlasFlags; // Build flags (see ImFontAtlasFlags_) + TexDesiredFormat: ImTextureFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8). + TexGlyphPadding: s32; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + TexMinWidth: s32; // Minimum desired texture width. Must be a power of two. Default to 512. + TexMinHeight: s32; // Minimum desired texture height. Must be a power of two. Default to 128. + TexMaxWidth: s32; // Maximum desired texture width. Must be a power of two. Default to 8192. + TexMaxHeight: s32; // Maximum desired texture height. Must be a power of two. Default to 8192. + UserData: *void; // Store your own atlas related user-data (if e.g. you have multiple font atlas). + + union { + TexRef: ImTextureRef; // Latest texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.0. + TexID: ImTextureRef; // Latest texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.0. + } + + TexData: *ImTextureData; // Latest texture. + + TexList: ImVector(*ImTextureData); // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! + Locked: bool; // Marked as locked during ImGui::NewFrame()..EndFrame() scope if TexUpdates are not supported. Any attempt to modify the atlas will assert. + RendererHasTextures: bool; // Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. + TexIsBuilt: bool; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. + TexPixelsUseColors: bool; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. + TexUvScale: ImVec2; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight). May change as new texture gets created. + TexUvWhitePixel: ImVec2; // Texture coordinates to a white pixel. May change as new texture gets created. + Fonts: ImVector(*ImFont); // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + Sources: ImVector(ImFontConfig); // Source/configuration data + TexUvLines: [33] ImVec4; // UVs for baked anti-aliased lines + TexNextUniqueID: s32; // Next value to be stored in TexData->UniqueID + FontNextUniqueID: s32; // Next value to be stored in ImFont->FontID + DrawListSharedDatas: ImVector(*ImDrawListSharedData); // List of users for this atlas. Typically one per Dear ImGui context. + Builder: *ImFontAtlasBuilder; // Opaque interface to our data that doesn't need to be public and may be discarded when rebuilding. + FontLoader: *ImFontLoader; // Font loader opaque interface (default to use FreeType when IMGUI_ENABLE_FREETYPE is defined, otherwise default to use stb_truetype). Use SetFontLoader() to change this at runtime. + FontLoaderName: *u8; // Font loader name (for display e.g. in About box) == FontLoader->Name + FontLoaderData: *void; // Font backend opaque storage + FontLoaderFlags: u32; // Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. Per-font override is also available in ImFontConfig). + RefCount: s32; // Number of contexts using this atlas + OwnerContext: *ImGuiContext; // Context which own the atlas will be in charge of updating and destroying it. + + TempRect: ImFontAtlasRect; // For old GetCustomRectByIndex() API + + AddCustomRectFontGlyph :: (this: *ImFontAtlas, font: *ImFont, codepoint: ImWchar, w: s32, h: s32, advance_x: float, offset: *ImVec2) -> ImFontAtlasRectId #cpp_method #foreign imgui "?AddCustomRectFontGlyph@ImFontAtlas@@QEAAHPEAUImFont@@GHHMAEBUImVec2@@@Z"; + AddCustomRectFontGlyph :: (this: *ImFontAtlas, font: *ImFont, codepoint: ImWchar, w: s32, h: s32, advance_x: float, offset: ImVec2 = ImVec2.{0, 0}) -> ImFontAtlasRectId #no_context { + return AddCustomRectFontGlyph(this, font, codepoint, w, h, advance_x, *offset); + } + AddCustomRectFontGlyphForSize :: (this: *ImFontAtlas, font: *ImFont, font_size: float, codepoint: ImWchar, w: s32, h: s32, advance_x: float, offset: *ImVec2) -> ImFontAtlasRectId #cpp_method #foreign imgui "?AddCustomRectFontGlyphForSize@ImFontAtlas@@QEAAHPEAUImFont@@MGHHMAEBUImVec2@@@Z"; + AddCustomRectFontGlyphForSize :: (this: *ImFontAtlas, font: *ImFont, font_size: float, codepoint: ImWchar, w: s32, h: s32, advance_x: float, offset: ImVec2 = ImVec2.{0, 0}) -> ImFontAtlasRectId #no_context { + return AddCustomRectFontGlyphForSize(this, font, font_size, codepoint, w, h, advance_x, *offset); + } +} + +// Font runtime data for a given size +// Important: pointers to ImFontBaked are only valid for the current frame. +ImFontBaked :: struct { + IndexAdvanceX: ImVector(float); // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). + FallbackAdvanceX: float; // 4 // out // FindGlyph(FallbackChar)->AdvanceX + Size: float; // 4 // in // Height of characters/line, set during loading (doesn't change after loading) + RasterizerDensity: float; // 4 // in // Density this is baked at + + IndexLookup: ImVector(ImU16); // 12-16 // out // Sparse. Index glyphs by Unicode code-point. + Glyphs: ImVector(ImFontGlyph); // 12-16 // out // All glyphs. + FallbackGlyphIndex: s32; // 4 // out // Index of FontFallbackChar + + Ascent: float; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + Descent: float; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + __bitfield: u32; + /* + MetricsTotalSurface: u32; /* 26 bits */ // 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + WantDestroy: u32; /* 1 bits */ // 0 // // Queued for destroy + LoadNoFallback: u32; /* 1 bits */ // 0 // // Disable loading fallback in lower-level calls. + LoadNoRenderOnLayout: u32; /* 1 bits */ // 0 // // Enable a two-steps mode where CalcTextSize() calls will load AdvanceX *without* rendering/packing glyphs. Only advantageous if you know that the glyph is unlikely to actually be rendered, otherwise it is slower because we'd do one query on the first CalcTextSize and one query on the first Draw.; + */ + + LastUsedFrame: s32; // 4 // // Record of that time this was bounds + BakedId: ID; // 4 // // Unique ID for this baked storage + OwnerFont: *ImFont; // 4-8 // in // Parent font + FontLoaderDatas: *void; // 4-8 // // Font loader opaque storage (per baked font * sources): single contiguous buffer allocated by imgui, passed to loader. + + // Functions + Constructor :: (this: *ImFontBaked) -> void #cpp_method #foreign imgui "??0ImFontBaked@@QEAA@XZ"; + ClearOutputData :: (this: *ImFontBaked) -> void #cpp_method #foreign imgui "?ClearOutputData@ImFontBaked@@QEAAXXZ"; + FindGlyph :: (this: *ImFontBaked, c: ImWchar) -> *ImFontGlyph #cpp_method #foreign imgui "?FindGlyph@ImFontBaked@@QEAAPEAUImFontGlyph@@G@Z"; + FindGlyphNoFallback :: (this: *ImFontBaked, c: ImWchar) -> *ImFontGlyph #cpp_method #foreign imgui "?FindGlyphNoFallback@ImFontBaked@@QEAAPEAUImFontGlyph@@G@Z"; + GetCharAdvance :: (this: *ImFontBaked, c: ImWchar) -> float #cpp_method #foreign imgui "?GetCharAdvance@ImFontBaked@@QEAAMG@Z"; + IsGlyphLoaded :: (this: *ImFontBaked, c: ImWchar) -> bool #cpp_method #foreign imgui "?IsGlyphLoaded@ImFontBaked@@QEAA_NG@Z"; +} + +set_MetricsTotalSurface :: (fields: *ImFontBaked, value: u32) { + MASK0: u32 : 0b11_1111_1111_1111_1111_1111_1111; + fields.__bitfield = (fields.__bitfield & ~MASK0) | (value & MASK0); +} +get_MetricsTotalSurface :: (fields: ImFontBaked) -> u32 { + return (fields.__bitfield & 0b11_1111_1111_1111_1111_1111_1111); +} + +set_WantDestroy :: (fields: *ImFontBaked, value: bool) { + if value fields.__bitfield |= 1 << 26; + else fields.__bitfield &= ~cast(u32)(1 << 26); +} +get_WantDestroy :: (fields: ImFontBaked) -> bool { + return (fields.__bitfield & (1 << 26)) != 0; +} + +set_LoadNoFallback :: (fields: *ImFontBaked, value: bool) { + if value fields.__bitfield |= 1 << 27; + else fields.__bitfield &= ~cast(u32)(1 << 27); +} +get_LoadNoFallback :: (fields: ImFontBaked) -> bool { + return (fields.__bitfield & (1 << 27)) != 0; +} + +set_LoadNoRenderOnLayout :: (fields: *ImFontBaked, value: bool) { + if value fields.__bitfield |= 1 << 28; + else fields.__bitfield &= ~cast(u32)(1 << 28); +} +get_LoadNoRenderOnLayout :: (fields: ImFontBaked) -> bool { + return (fields.__bitfield & (1 << 28)) != 0; +} + + +// Font flags +// (in future versions as we redesign font loading API, this will become more important and better documented. for now please consider this as internal/advanced use) +ImFontFlags :: enum_flags s32 { + None :: 0x0; + NoLoadError :: 0x2; + NoLoadGlyphs :: 0x4; + LockBakedSizes :: 0x8; + + ImFontFlags_None :: None; + ImFontFlags_NoLoadError :: NoLoadError; + ImFontFlags_NoLoadGlyphs :: NoLoadGlyphs; + ImFontFlags_LockBakedSizes :: LockBakedSizes; +} + +// Font runtime data and rendering +// - ImFontAtlas automatically loads a default embedded font for you if you didn't load one manually. +// - Since 1.92.0 a font may be rendered as any size! Therefore a font doesn't have one specific size. +// - Use 'font->GetFontBaked(size)' to retrieve the ImFontBaked* corresponding to a given size. +// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetFontBaked(g.FontSize). +ImFont :: struct { + LastBaked: *ImFontBaked; // 4-8 // Cache last bound baked. NEVER USE DIRECTLY. Use GetFontBaked(). + OwnerAtlas: *ImFontAtlas; // 4-8 // What we have been loaded into. + Flags: ImFontFlags; // 4 // Font flags. + CurrentRasterizerDensity: float; // Current rasterizer density. This is a varying state of the font. + + FontId: ID; // Unique identifier for the font + LegacySize: float; // 4 // in // Font size passed to AddFont(). Use for old code calling PushFont() expecting to use that size. (use ImGui::GetFontBaked() to get font baked at current bound size). + Sources: ImVector(*ImFontConfig); // 16 // in // List of sources. Pointers within OwnerAtlas->Sources[] + EllipsisChar: ImWchar; // 2-4 // out // Character used for ellipsis rendering ('...'). If you ever want to temporarily swap this for an alternative/dummy char, make sure to clear EllipsisAutoBake. + FallbackChar: ImWchar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') + Used8kPagesMap: [1] ImU8; // 1 bytes if ImWchar=ImWchar16, 17 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 8K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + EllipsisAutoBake: bool; // 1 // // Mark when the "..." glyph (== EllipsisChar) needs to be generated by combining multiple '.'. + RemapPairs: Storage; // 16 // // Remapping pairs when using AddRemapChar(), otherwise empty. + + Scale: float; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + + // Methods + Constructor :: (this: *ImFont) -> void #cpp_method #foreign imgui "??0ImFont@@QEAA@XZ"; + Destructor :: (this: *ImFont) -> void #cpp_method #foreign imgui "??1ImFont@@QEAA@XZ"; + IsGlyphInFont :: (this: *ImFont, c: ImWchar) -> bool #cpp_method #foreign imgui "?IsGlyphInFont@ImFont@@QEAA_NG@Z"; + + // [Internal] Don't use! + // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. + // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. + GetFontBaked :: (this: *ImFont, font_size: float, density: float = -1.0) -> *ImFontBaked #cpp_method #foreign imgui "?GetFontBaked@ImFont@@QEAAPEAUImFontBaked@@MM@Z"; + CalcTextSizeA :: (this: *ImFont, size: float, max_width: float, wrap_width: float, text_begin: *u8, text_end: *u8 = null, out_remaining: **u8 = null) -> ImVec2 #cpp_method #cpp_return_type_is_non_pod #foreign imgui "?CalcTextSizeA@ImFont@@QEAA?AUImVec2@@MMMPEBD0PEAPEBD@Z"; + CalcTextSizeA :: (this: *ImFont, size: float, max_width: float, wrap_width: float, text: string, out_remaining: **u8 = null) -> ImVec2 #no_context { + return CalcTextSizeA(this, size, max_width, wrap_width, text.data, text.data + text.count, out_remaining); + } + CalcWordWrapPosition :: (this: *ImFont, size: float, text: *u8, text_end: *u8, wrap_width: float) -> *u8 #cpp_method #foreign imgui "?CalcWordWrapPosition@ImFont@@QEAAPEBDMPEBD0M@Z"; + CalcWordWrapPosition :: (this: *ImFont, size: float, text: string, wrap_width: float) -> *u8 #no_context { + return CalcWordWrapPosition(this, size, text.data, text.data + text.count, wrap_width); + } + RenderChar :: (this: *ImFont, draw_list: *ImDrawList, size: float, pos: *ImVec2, col: ImU32, c: ImWchar, cpu_fine_clip: *ImVec4 = null) -> void #cpp_method #foreign imgui "?RenderChar@ImFont@@QEAAXPEAUImDrawList@@MAEBUImVec2@@IGPEBUImVec4@@@Z"; + RenderChar :: (this: *ImFont, draw_list: *ImDrawList, size: float, pos: ImVec2, col: ImU32, c: ImWchar, cpu_fine_clip: *ImVec4 = null) #no_context { + RenderChar(this, draw_list, size, *pos, col, c, cpu_fine_clip); + } + RenderText :: (this: *ImFont, draw_list: *ImDrawList, size: float, pos: *ImVec2, col: ImU32, clip_rect: *ImVec4, text_begin: *u8, text_end: *u8, wrap_width: float = 0.0, flags: ImDrawTextFlags = 0) -> void #cpp_method #foreign imgui "?RenderText@ImFont@@QEAAXPEAUImDrawList@@MAEBUImVec2@@IAEBUImVec4@@PEBD3MH@Z"; + RenderText :: (this: *ImFont, draw_list: *ImDrawList, size: float, pos: ImVec2, col: ImU32, clip_rect: ImVec4, text: string, wrap_width: float = 0.0, flags: ImDrawTextFlags = 0) #no_context { + RenderText(this, draw_list, size, *pos, col, *clip_rect, text.data, text.data + text.count, wrap_width, flags); + } + + // [Internal] Don't use! + ClearOutputData :: (this: *ImFont) -> void #cpp_method #foreign imgui "?ClearOutputData@ImFont@@QEAAXXZ"; + AddRemapChar :: (this: *ImFont, from_codepoint: ImWchar, to_codepoint: ImWchar) -> void #cpp_method #foreign imgui "?AddRemapChar@ImFont@@QEAAXGG@Z"; + IsGlyphRangeUnused :: (this: *ImFont, c_begin: u32, c_last: u32) -> bool #cpp_method #foreign imgui "?IsGlyphRangeUnused@ImFont@@QEAA_NII@Z"; +} + +// Flags stored in ImGuiViewport::Flags, giving indications to the platform backends. +ViewportFlags :: enum_flags s32 { + None :: 0x0; + IsPlatformWindow :: 0x1; + IsPlatformMonitor :: 0x2; + OwnedByApp :: 0x4; + NoDecoration :: 0x8; + NoTaskBarIcon :: 0x10; + NoFocusOnAppearing :: 0x20; + NoFocusOnClick :: 0x40; + NoInputs :: 0x80; + NoRendererClear :: 0x100; + NoAutoMerge :: 0x200; + TopMost :: 0x400; + CanHostOtherWindows :: 0x800; + + IsMinimized :: 0x1000; + IsFocused :: 0x2000; + + ImGuiViewportFlags_None :: None; + ImGuiViewportFlags_IsPlatformWindow :: IsPlatformWindow; + ImGuiViewportFlags_IsPlatformMonitor :: IsPlatformMonitor; + ImGuiViewportFlags_OwnedByApp :: OwnedByApp; + ImGuiViewportFlags_NoDecoration :: NoDecoration; + ImGuiViewportFlags_NoTaskBarIcon :: NoTaskBarIcon; + ImGuiViewportFlags_NoFocusOnAppearing :: NoFocusOnAppearing; + ImGuiViewportFlags_NoFocusOnClick :: NoFocusOnClick; + ImGuiViewportFlags_NoInputs :: NoInputs; + ImGuiViewportFlags_NoRendererClear :: NoRendererClear; + ImGuiViewportFlags_NoAutoMerge :: NoAutoMerge; + ImGuiViewportFlags_TopMost :: TopMost; + ImGuiViewportFlags_CanHostOtherWindows :: CanHostOtherWindows; + + ImGuiViewportFlags_IsMinimized :: IsMinimized; + ImGuiViewportFlags_IsFocused :: IsFocused; +} + +// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. +// - With multi-viewport enabled, we extend this concept to have multiple active viewports. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. +// - About Main Area vs Work Area: +// - Main Area = entire viewport. +// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor). +// - Windows are generally trying to stay within the Work Area of their host viewport. +Viewport :: struct { + ID_: ID; // Unique identifier for the viewport + Flags: ViewportFlags; // See ImGuiViewportFlags_ + Pos: ImVec2; // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) + Size: ImVec2; // Main Area: Size of the viewport. + FramebufferScale: ImVec2; // Density of the viewport for Retina display (always 1,1 on Windows, may be 2,2 etc on macOS/iOS). This will affect font rasterizer density. + WorkPos: ImVec2; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) + WorkSize: ImVec2; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) + DpiScale: float; // 1.0f = 96 DPI = No extra scale. + ParentViewportId: ID; // (Advanced) 0: no parent. Instruct the platform backend to setup a parent/child relationship between platform windows. + ParentViewport: *Viewport; // (Advanced) Direct shortcut to ImGui::FindViewportByID(ParentViewportId). NULL: no parent. + DrawData: *ImDrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame(). + + RendererUserData: *void; // void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function. + PlatformUserData: *void; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function. + PlatformHandle: *void; // void* to hold higher-level, platform window handle (e.g. HWND for Win32 backend, Uint32 WindowID for SDL, GLFWWindow* for GLFW), for FindViewportByPlatformHandle(). + PlatformHandleRaw: *void; // void* to hold lower-level, platform-native window handle (always HWND on Win32 platform, unused for other platforms). + PlatformWindowCreated: bool; // Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created. + PlatformRequestMove: bool; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position) + PlatformRequestResize: bool; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size) + PlatformRequestClose: bool; // Platform window requested closure (e.g. window was moved by the OS / host window manager, e.g. pressing ALT-F4) +} + +// Access via ImGui::GetPlatformIO() +PlatformIO :: struct { + Constructor :: (this: *PlatformIO) -> void #cpp_method #foreign imgui "??0ImGuiPlatformIO@@QEAA@XZ"; + + Platform_GetClipboardTextFn: #type (ctx: *ImGuiContext) -> *u8 #c_call; // Should return NULL on failure (e.g. clipboard data is not text). + Platform_SetClipboardTextFn: #type (ctx: *ImGuiContext, text: *u8) -> void #c_call; + Platform_ClipboardUserData: *void; + + // Optional: Open link/folder/file in OS Shell + // (default to use ShellExecuteW() on Windows, system() on Linux/Mac. expected to return false on failure, but some platforms may always return true) + Platform_OpenInShellFn: #type (ctx: *ImGuiContext, path: *u8) -> bool #c_call; + Platform_OpenInShellUserData: *void; + + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) + // (default to use native imm32 api on Windows) + Platform_SetImeDataFn: #type (ctx: *ImGuiContext, viewport: *Viewport, data: *PlatformImeData) -> void #c_call; + Platform_ImeUserData: *void; + + Platform_LocaleDecimalPoint: ImWchar; // '.' + + // Optional: Maximum texture size supported by renderer (used to adjust how we size textures). 0 if not known. + Renderer_TextureMaxWidth: s32; + Renderer_TextureMaxHeight: s32; + + // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. + Renderer_RenderState: *void; + + Platform_CreateWindow: #type (vp: *Viewport) -> void #c_call; // . . U . . // Create a new platform window for the given viewport + Platform_DestroyWindow: #type (vp: *Viewport) -> void #c_call; // N . U . D // + Platform_ShowWindow: #type (vp: *Viewport) -> void #c_call; // . . U . . // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them before showing the window + Platform_SetWindowPos: #type (vp: *Viewport, pos: ImVec2) -> void #c_call; // . . U . . // Set platform window position (given the upper-left corner of client area) + Platform_GetWindowPos: #type (vp: *Viewport) -> ImVec2 #c_call #cpp_return_type_is_non_pod; // N . . . . // + Platform_SetWindowSize: #type (vp: *Viewport, size: ImVec2) -> void #c_call; // . . U . . // Set platform window client area size (ignoring OS decorations such as OS title bar etc.) + Platform_GetWindowSize: #type (vp: *Viewport) -> ImVec2 #c_call #cpp_return_type_is_non_pod; // N . . . . // Get platform window client area size + Platform_GetWindowFramebufferScale: #type (vp: *Viewport) -> ImVec2 #c_call #cpp_return_type_is_non_pod; // N . . . . // Return viewport density. Always 1,1 on Windows, often 2,2 on Retina display on macOS/iOS. MUST BE INTEGER VALUES. + Platform_SetWindowFocus: #type (vp: *Viewport) -> void #c_call; // N . . . . // Move window to front and set input focus + Platform_GetWindowFocus: #type (vp: *Viewport) -> bool #c_call; // . . U . . // + Platform_GetWindowMinimized: #type (vp: *Viewport) -> bool #c_call; // N . . . . // Get platform window minimized state. When minimized, we generally won't attempt to get/set size and contents will be culled more easily + Platform_SetWindowTitle: #type (vp: *Viewport, str: *u8) -> void #c_call; // . . U . . // Set platform window title (given an UTF-8 string) + Platform_SetWindowAlpha: #type (vp: *Viewport, alpha: float) -> void #c_call; // . . U . . // (Optional) Setup global transparency (not per-pixel transparency) + Platform_UpdateWindow: #type (vp: *Viewport) -> void #c_call; // . . U . . // (Optional) Called by UpdatePlatformWindows(). Optional hook to allow the platform backend from doing general book-keeping every frame. + Platform_RenderWindow: #type (vp: *Viewport, render_arg: *void) -> void #c_call; // . . . R . // (Optional) Main rendering (platform side! This is often unused, or just setting a "current" context for OpenGL bindings). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + Platform_SwapBuffers: #type (vp: *Viewport, render_arg: *void) -> void #c_call; // . . . R . // (Optional) Call Present/SwapBuffers (platform side! This is often unused!). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + Platform_GetWindowDpiScale: #type (vp: *Viewport) -> float #c_call; // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. + Platform_OnChangedViewport: #type (vp: *Viewport) -> void #c_call; // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style. + Platform_GetWindowWorkAreaInsets: #type (vp: *Viewport) -> ImVec4 #c_call #cpp_return_type_is_non_pod; // N . . . . // (Optional) [BETA] Get initial work area inset for the viewport (won't be covered by main menu bar, dockspace over viewport etc.). Default to (0,0),(0,0). 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land. + Platform_CreateVkSurface: #type (vp: *Viewport, vk_inst: ImU64, vk_allocators: *void, out_vk_surface: *ImU64) -> s32 #c_call; // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both). + + Renderer_CreateWindow: #type (vp: *Viewport) -> void #c_call; // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow) + Renderer_DestroyWindow: #type (vp: *Viewport) -> void #c_call; // N . U . D // Destroy swap chain, frame buffers etc. (called before Platform_DestroyWindow) + Renderer_SetWindowSize: #type (vp: *Viewport, size: ImVec2) -> void #c_call; // . . U . . // Resize swap chain, frame buffers etc. (called after Platform_SetWindowSize) + Renderer_RenderWindow: #type (vp: *Viewport, render_arg: *void) -> void #c_call; // . . . R . // (Optional) Clear framebuffer, setup render target, then render the viewport->DrawData. 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + Renderer_SwapBuffers: #type (vp: *Viewport, render_arg: *void) -> void #c_call; // . . . R . // (Optional) Call Present/SwapBuffers. 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + + // (Optional) Monitor list + // - Updated by: app/backend. Update every frame to dynamically support changing monitor or DPI configuration. + // - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors. + Monitors: ImVector(PlatformMonitor); + + Textures: ImVector(*ImTextureData); // List of textures used by Dear ImGui (most often 1) + contents of external texture list is automatically appended into this. + + Viewports: ImVector(*Viewport); // Main viewports, followed by all secondary viewports. + + //------------------------------------------------------------------ + // Functions + //------------------------------------------------------------------ + ClearPlatformHandlers :: (this: *PlatformIO) -> void #cpp_method #foreign imgui "?ClearPlatformHandlers@ImGuiPlatformIO@@QEAAXXZ"; + ClearRendererHandlers :: (this: *PlatformIO) -> void #cpp_method #foreign imgui "?ClearRendererHandlers@ImGuiPlatformIO@@QEAAXXZ"; +} + +// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI. +// We use this information for multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors. +PlatformMonitor :: struct { + MainPos: ImVec2; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) + MainSize: ImVec2; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) + WorkPos: ImVec2; // Coordinates without task bars / side bars / menu bars. Used to avoid positioning popups/tooltips inside this region. If you don't have this info, please copy the value for MainPos/MainSize. + WorkSize: ImVec2; // Coordinates without task bars / side bars / menu bars. Used to avoid positioning popups/tooltips inside this region. If you don't have this info, please copy the value for MainPos/MainSize. + DpiScale: float; // 1.0f = 96 DPI + PlatformHandle: *void; // Backend dependant data (e.g. HMONITOR, GLFWmonitor*, SDL Display Index, NSScreen*) +} + +// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). +PlatformImeData :: struct { + WantVisible: bool; // A widget wants the IME to be visible. + WantTextInput: bool; // A widget wants text input, not necessarily IME to be visible. This is automatically set to the upcoming value of io.WantTextInput. + InputPos: ImVec2; // Position of input cursor (for IME). + InputLineHeight: float; // Line height (for IME). + ViewportId: ID; // ID of platform window/viewport. +} + +//-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect +// - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y +// - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h +// - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() +// We could make ImTextureRect an union to use old names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. +ImFontAtlasCustomRect :: ImFontAtlasRect; + diff --git a/nob.c b/nob.c deleted file mode 100644 index db9f051..0000000 --- a/nob.c +++ /dev/null @@ -1,72 +0,0 @@ -// Bootstrap: cl /nologo nob.c -// After that, just run: nob.exe - -#define NOB_IMPLEMENTATION -#include "nob.h" - -#define BUILD_DIR "build" - -static const char *src_files[] = { - "src/main.cpp", - "src/platform/platform_win32.cpp", - "src/renderer/renderer_dx12.cpp", -}; - -static const char *imgui_files[] = { - "vendor/imgui/imgui.cpp", - "vendor/imgui/imgui_draw.cpp", - "vendor/imgui/imgui_tables.cpp", - "vendor/imgui/imgui_widgets.cpp", - "vendor/imgui/imgui_demo.cpp", - "vendor/imgui/backends/imgui_impl_win32.cpp", - "vendor/imgui/backends/imgui_impl_dx12.cpp", -}; - -static const char *link_libs[] = { - "d3d12.lib", - "dxgi.lib", - "d3dcompiler.lib", - "user32.lib", - "gdi32.lib", - "shell32.lib", - "ole32.lib", - "dwmapi.lib", -}; - -int main(int argc, char **argv) -{ - NOB_GO_REBUILD_URSELF(argc, argv); - - if (!nob_mkdir_if_not_exists(BUILD_DIR)) return 1; - - Nob_Cmd cmd = {0}; - - nob_cmd_append(&cmd, "cl.exe"); - nob_cmd_append(&cmd, "/nologo", "/std:c++17", "/EHsc", "/W3"); - nob_cmd_append(&cmd, "/Isrc", "/Ivendor/imgui", "/Ivendor/imgui/backends"); - -#ifdef _DEBUG - nob_cmd_append(&cmd, "/Zi", "/Od", "/D_DEBUG"); -#else - nob_cmd_append(&cmd, "/O2", "/DNDEBUG"); -#endif - - nob_cmd_append(&cmd, nob_temp_sprintf("/Fe:%s/autosample.exe", BUILD_DIR)); - nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", BUILD_DIR)); - nob_cmd_append(&cmd, nob_temp_sprintf("/Fd:%s/", BUILD_DIR)); - - for (size_t i = 0; i < NOB_ARRAY_LEN(src_files); i++) - nob_cmd_append(&cmd, src_files[i]); - for (size_t i = 0; i < NOB_ARRAY_LEN(imgui_files); i++) - nob_cmd_append(&cmd, imgui_files[i]); - - nob_cmd_append(&cmd, "/link"); - nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE"); - for (size_t i = 0; i < NOB_ARRAY_LEN(link_libs); i++) - nob_cmd_append(&cmd, link_libs[i]); - - if (!nob_cmd_run(&cmd)) return 1; - - nob_log(NOB_INFO, "Build complete: %s/autosample.exe", BUILD_DIR); - return 0; -} diff --git a/nob.h b/nob.h deleted file mode 100644 index 2bdb18e..0000000 --- a/nob.h +++ /dev/null @@ -1,3156 +0,0 @@ -/* nob - v3.2.2 - Public Domain - https://github.com/tsoding/nob.h - - This library is the next generation of the [NoBuild](https://github.com/tsoding/nobuild) idea. - - # Quick Example - - ```c - // nob.c - #define NOB_IMPLEMENTATION - #include "nob.h" - - int main(int argc, char **argv) - { - NOB_GO_REBUILD_URSELF(argc, argv); - Nob_Cmd cmd = {0}; - nob_cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c"); - if (!nob_cmd_run(&cmd)) return 1; - return 0; - } - ``` - - ```console - $ cc -o nob nob.c - $ ./nob - ``` - - The `nob` automatically rebuilds itself if `nob.c` is modified thanks to - the `NOB_GO_REBUILD_URSELF` macro (don't forget to check out how it works below) - - # Stripping off `nob_` Prefixes - - Since Pure C does not have any namespaces we prefix each name of the API with the `nob_` to avoid any - potential conflicts with any other names in your code. But sometimes it is very annoying and makes - the code noisy. Because of that you can drop the `nob_` prefix. - - ```c - // nob.c - #define NOB_IMPLEMENTATION - #include "nob.h" - - int main(int argc, char **argv) - { - GO_REBUILD_URSELF(argc, argv); - Cmd cmd = {0}; - cmd_append(&cmd, "cc", "-Wall", "-Wextra", "-o", "main", "main.c"); - if (!cmd_run(&cmd)) return 1; - return 0; - } - ``` - - If the lack of prefixes causes any problems you can disable the prefix stripping by defining - `NOB_UNSTRIP_PREFIX` feature macro before including "nob.h". - - Not all the names have strippable prefixes. All the redefinable names like `NOB_REBUILD_URSELF` - for instance will retain their prefix always. Notable exception is the nob_log() function. Stripping - away the prefix results in log() which was historically always referring to the natural logarithmic - function that is already defined in math.h. So there is no reason to strip off the prefix for nob_log(). - Another exception is nob_rename() which collides with the widely known POSIX function rename(2) if you - strip the prefix off. - - The prefixes are stripped off only on the level of the preprocessor. The names of the functions in the - compiled object file will still retain the `nob_` prefix. Keep that in mind when you FFI with nob.h - from other languages (for whatever reason). - - If only few specific names create conflicts for you, you can just #undef those names after the - `#include ` without enabling `NOB_UNSTRIP_PREFIX` since they are macros anyway. - - # Macro Interface - - All these macros are `#define`d by the user before including nob.h - - ## Flags - - Enable or disable certain aspects of nob.h - - - NOB_IMPLEMENTATION - Enable definitions of the functions. By default only declarations are included. - See https://github.com/nothings/stb/blob/f58f558c120e9b32c217290b80bad1a0729fbb2c/docs/stb_howto.txt - for more info. - - NOB_WARN_DEPRECATED - Warn about the usage of deprecated function. We rarely actually remove deprecated functions, - but if you want to know what is discouraged you may want to enable this flag. - - NOB_EXPERIMENTAL_DELETE_OLD - Experimental feature that automatically removes `nob.old` files. It's unclear how well - it works on Windows, so it's experimental for now. - - NOB_UNSTRIP_PREFIX - do not strip the `nob_` prefixes from non-redefinable names. - - NOB_NO_ECHO - do not echo the actions various nob functions are doing (like nob_cmd_run(), nob_mkdir_if_not_exists(), etc). - - ## Redefinable Macros - - Redefine default behaviors of nob.h. - - - NOBDEF - Appends additional things to function declarations. You can do something like `#define NOBDEF static inline`. - - NOB_ASSERT(condition) - Redefine which assert() nob.h shall use. - - NOB_REALLOC(oldptr, size) - Redefine which realloc() nob.h shall use. - - NOB_FREE(ptr) - Redefine which free() nob.h shall use. - - NOB_DEPRECATED(message) - Redefine how nob.h shall mark functions as deprecated. - - NOB_DA_INIT_CAP - Redefine initial capacity of Dynamic Arrays. - - NOB_TEMP_CAPACITY - Redefine the capacity of the temporary storate. - - NOB_REBUILD_URSELF(binary_path, source_path) - redefine how nob.h shall rebuild itself. - - NOB_WIN32_ERR_MSG_SIZE - Redefine the capacity of the buffer for error message on Windows. -*/ - -#ifndef NOB_H_ -#define NOB_H_ -#ifdef _WIN32 -# ifndef _CRT_SECURE_NO_WARNINGS -# define _CRT_SECURE_NO_WARNINGS (1) -# endif // _CRT_SECURE_NO_WARNINGS -#endif // _WIN32 - -#ifndef NOBDEF -/* - Goes before declarations and definitions of the nob functions. Useful to `#define NOBDEF static inline` - if your source code is a single file and you want the compiler to remove unused functions. -*/ -#define NOBDEF -#endif /* NOBDEF */ - -#ifndef NOB_ASSERT -#include -#define NOB_ASSERT assert -#endif /* NOB_ASSERT */ - -#ifndef NOB_REALLOC -#include -#define NOB_REALLOC realloc -#endif /* NOB_REALLOC */ - -#ifndef NOB_FREE -#include -#define NOB_FREE free -#endif /* NOB_FREE */ - -#ifdef NOB_WARN_DEPRECATED -# ifndef NOB_DEPRECATED -# if defined(__GNUC__) || defined(__clang__) -# define NOB_DEPRECATED(message) __attribute__((deprecated(message))) -# elif defined(_MSC_VER) -# define NOB_DEPRECATED(message) __declspec(deprecated(message)) -# else -# define NOB_DEPRECATED(...) -# endif -# endif /* NOB_DEPRECATED */ -#else -# define NOB_DEPRECATED(...) -#endif /* NOB_WARN_DEPRECATED */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# define _WINUSER_ -# define _WINGDI_ -# define _IMM_ -# define _WINCON_ -# include -# include -# include -# include -#else -# ifdef __APPLE__ -# include -# endif -# ifdef __FreeBSD__ -# include -# endif -# include -# include -# include -# include -# include -# include -#endif - -#ifdef __HAIKU__ -# include -#endif - -#ifdef _WIN32 -# define NOB_LINE_END "\r\n" -#else -# define NOB_LINE_END "\n" -#endif - -#if defined(__GNUC__) || defined(__clang__) -// https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html -# ifdef __MINGW_PRINTF_FORMAT -# define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (__MINGW_PRINTF_FORMAT, STRING_INDEX, FIRST_TO_CHECK))) -# else -# define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (printf, STRING_INDEX, FIRST_TO_CHECK))) -# endif // __MINGW_PRINTF_FORMAT -#else -// TODO: implement NOB_PRINTF_FORMAT for MSVC -# define NOB_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) -#endif - -#define NOB_UNUSED(value) (void)(value) -#define NOB_TODO(message) do { fprintf(stderr, "%s:%d: TODO: %s\n", __FILE__, __LINE__, message); abort(); } while(0) -#define NOB_UNREACHABLE(message) do { fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); abort(); } while(0) - -#define NOB_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0])) -#define NOB_ARRAY_GET(array, index) \ - (NOB_ASSERT((size_t)index < NOB_ARRAY_LEN(array)), array[(size_t)index]) - -typedef enum { - NOB_INFO, - NOB_WARNING, - NOB_ERROR, - NOB_NO_LOGS, -} Nob_Log_Level; - -// Any messages with the level below nob_minimal_log_level are going to be suppressed. -extern Nob_Log_Level nob_minimal_log_level; - -typedef void (nob_log_handler)(Nob_Log_Level level, const char *fmt, va_list args); - -NOBDEF void nob_set_log_handler(nob_log_handler *handler); -NOBDEF nob_log_handler *nob_get_log_handler(void); - -NOBDEF nob_log_handler nob_default_log_handler; -NOBDEF nob_log_handler nob_cancer_log_handler; - -NOBDEF void nob_log(Nob_Log_Level level, const char *fmt, ...) NOB_PRINTF_FORMAT(2, 3); - -// It is an equivalent of shift command from bash (do `help shift` in bash). It basically -// pops an element from the beginning of a sized array. -#define nob_shift(xs, xs_sz) (NOB_ASSERT((xs_sz) > 0), (xs_sz)--, *(xs)++) -// NOTE: nob_shift_args() is an alias for an old variant of nob_shift that only worked with -// the command line arguments passed to the main() function. nob_shift() is more generic. -// So nob_shift_args() is semi-deprecated, but I don't see much reason to urgently -// remove it. This alias does not hurt anybody. -#define nob_shift_args(argc, argv) nob_shift(*argv, *argc) - -typedef struct { - const char **items; - size_t count; - size_t capacity; -} Nob_File_Paths; - -typedef enum { - NOB_FILE_REGULAR = 0, - NOB_FILE_DIRECTORY, - NOB_FILE_SYMLINK, - NOB_FILE_OTHER, -} Nob_File_Type; - -NOBDEF bool nob_mkdir_if_not_exists(const char *path); -NOBDEF bool nob_copy_file(const char *src_path, const char *dst_path); -NOBDEF bool nob_copy_directory_recursively(const char *src_path, const char *dst_path); -NOBDEF bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children); -NOBDEF bool nob_write_entire_file(const char *path, const void *data, size_t size); -NOBDEF Nob_File_Type nob_get_file_type(const char *path); -NOBDEF bool nob_delete_file(const char *path); - -typedef enum { - // If the current file is a directory go inside of it. - NOB_WALK_CONT, - // If the current file is a directory do not go inside of it. - NOB_WALK_SKIP, - // Stop the recursive traversal process entirely. - NOB_WALK_STOP, -} Nob_Walk_Action; - -typedef struct { - // The path to the visited file - const char *path; - // The type of the visited file - Nob_File_Type type; - // How nested we currently are in the directory tree - size_t level; - // User data supplied in Nob_Walk_Dir_Opt.data - void *data; - // The action nob_walk_dir_opt() must perform after the Nob_Walk_Func has returned. - // Default is NOB_WALK_CONT. - Nob_Walk_Action *action; -} Nob_Walk_Entry; - -// A function that is called by nob_walk_dir_opt() on each visited file. -// Nob_Walk_Entry provides the details about the visited file and also -// expects you to modify the `action` in case you want to alter the -// usual behavior of the recursive walking algorithm. -// -// If the function returns `false`, an error is assumed which causes the entire -// recursive walking process to exit and nob_walk_dir_opt() return `false`. -typedef bool (*Nob_Walk_Func)(Nob_Walk_Entry entry); - -typedef struct { - // User data passed to Nob_Walk_Entry.data - void *data; - // Walk the directory in post-order visiting the leaf files first. - bool post_order; -} Nob_Walk_Dir_Opt; - -NOBDEF bool nob_walk_dir_opt(const char *root, Nob_Walk_Func func, Nob_Walk_Dir_Opt); - -#define nob_walk_dir(root, func, ...) nob_walk_dir_opt((root), (func), (Nob_Walk_Dir_Opt){__VA_ARGS__}) - -typedef struct { - char *name; - bool error; - - struct { -#ifdef _WIN32 - WIN32_FIND_DATA win32_data; - HANDLE win32_hFind; - bool win32_init; -#else - DIR *posix_dir; - struct dirent *posix_ent; -#endif // _WIN32 - } nob__private; // TODO: we don't have solid conventions regarding private struct fields -} Nob_Dir_Entry; - -// nob_dir_entry_open() - open the directory entry for iteration. -// RETURN: -// true - Sucess. -// false - Error. I will be logged automatically with nob_log(). -NOBDEF bool nob_dir_entry_open(const char *dir_path, Nob_Dir_Entry *dir); -// nob_dir_entry_next() - acquire the next file in the directory. -// RETURN: -// true - Successfully acquired the next file. -// false - Either failure or no more files to iterate. In case of failure dir->error is set to true. -NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir); -NOBDEF void nob_dir_entry_close(Nob_Dir_Entry dir); - -#define nob_return_defer(value) do { result = (value); goto defer; } while(0) - -// Initial capacity of a dynamic array -#ifndef NOB_DA_INIT_CAP -#define NOB_DA_INIT_CAP 256 -#endif - -#ifdef __cplusplus -#define NOB_DECLTYPE_CAST(T) (decltype(T)) -#else -#define NOB_DECLTYPE_CAST(T) -#endif // __cplusplus - -#define nob_da_reserve(da, expected_capacity) \ - do { \ - if ((expected_capacity) > (da)->capacity) { \ - if ((da)->capacity == 0) { \ - (da)->capacity = NOB_DA_INIT_CAP; \ - } \ - while ((expected_capacity) > (da)->capacity) { \ - (da)->capacity *= 2; \ - } \ - (da)->items = NOB_DECLTYPE_CAST((da)->items)NOB_REALLOC((da)->items, (da)->capacity * sizeof(*(da)->items)); \ - NOB_ASSERT((da)->items != NULL && "Buy more RAM lol"); \ - } \ - } while (0) - -// Append an item to a dynamic array -#define nob_da_append(da, item) \ - do { \ - nob_da_reserve((da), (da)->count + 1); \ - (da)->items[(da)->count++] = (item); \ - } while (0) - -#define nob_da_free(da) NOB_FREE((da).items) - -// Append several items to a dynamic array -#define nob_da_append_many(da, new_items, new_items_count) \ - do { \ - nob_da_reserve((da), (da)->count + (new_items_count)); \ - memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \ - (da)->count += (new_items_count); \ - } while (0) - -#define nob_da_resize(da, new_size) \ - do { \ - nob_da_reserve((da), new_size); \ - (da)->count = (new_size); \ - } while (0) - -#define nob_da_last(da) (da)->items[(NOB_ASSERT((da)->count > 0), (da)->count-1)] -#define nob_da_remove_unordered(da, i) \ - do { \ - size_t j = (i); \ - NOB_ASSERT(j < (da)->count); \ - (da)->items[j] = (da)->items[--(da)->count]; \ - } while(0) - -// Foreach over Dynamic Arrays. Example: -// ```c -// typedef struct { -// int *items; -// size_t count; -// size_t capacity; -// } Numbers; -// -// Numbers xs = {0}; -// -// nob_da_append(&xs, 69); -// nob_da_append(&xs, 420); -// nob_da_append(&xs, 1337); -// -// nob_da_foreach(int, x, &xs) { -// // `x` here is a pointer to the current element. You can get its index by taking a difference -// // between `x` and the start of the array which is `x.items`. -// size_t index = x - xs.items; -// nob_log(INFO, "%zu: %d", index, *x); -// } -// ``` -#define nob_da_foreach(Type, it, da) for (Type *it = (da)->items; it < (da)->items + (da)->count; ++it) - -// The Fixed Array append. `items` fields must be a fixed size array. Its size determines the capacity. -#define nob_fa_append(fa, item) \ - (NOB_ASSERT((fa)->count < NOB_ARRAY_LEN((fa)->items)), \ - (fa)->items[(fa)->count++] = (item)) - -typedef struct { - char *items; - size_t count; - size_t capacity; -} Nob_String_Builder; - -#define nob_swap(T, a, b) do { T t = a; a = b; b = t; } while (0) - -NOBDEF bool nob_read_entire_file(const char *path, Nob_String_Builder *sb); -NOBDEF int nob_sb_appendf(Nob_String_Builder *sb, const char *fmt, ...) NOB_PRINTF_FORMAT(2, 3); -// Pads the String_Builder (sb) to the desired word size boundary with 0s. -// Imagine we have sb that contains 5 `a`-s: -// -// aaaa|a -// -// If we pad align it by size 4 it will look like this: -// -// aaaa|a000| <- padded with 0s to the next size 4 boundary -// -// Useful when you are building some sort of binary format using String_Builder. -NOBDEF void nob_sb_pad_align(Nob_String_Builder *sb, size_t size); - -// Append a sized buffer to a string builder -#define nob_sb_append_buf(sb, buf, size) nob_da_append_many(sb, buf, size) - -// Append a NULL-terminated string to a string builder -#define nob_sb_append_cstr(sb, cstr) \ - do { \ - const char *s = (cstr); \ - size_t n = strlen(s); \ - nob_da_append_many(sb, s, n); \ - } while (0) - -// Append a single NULL character at the end of a string builder. So then you can -// use it a NULL-terminated C string -#define nob_sb_append_null(sb) nob_da_append_many(sb, "", 1) - -#define nob_sb_append nob_da_append - -// Free the memory allocated by a string builder -#define nob_sb_free(sb) NOB_FREE((sb).items) - -// Process handle -#ifdef _WIN32 -typedef HANDLE Nob_Proc; -#define NOB_INVALID_PROC INVALID_HANDLE_VALUE -typedef HANDLE Nob_Fd; -#define NOB_INVALID_FD INVALID_HANDLE_VALUE -#else -typedef int Nob_Proc; -#define NOB_INVALID_PROC (-1) -typedef int Nob_Fd; -#define NOB_INVALID_FD (-1) -#endif // _WIN32 - -NOBDEF Nob_Fd nob_fd_open_for_read(const char *path); -NOBDEF Nob_Fd nob_fd_open_for_write(const char *path); -NOBDEF void nob_fd_close(Nob_Fd fd); - -typedef struct { - Nob_Fd read; - Nob_Fd write; -} Nob_Pipe; - -NOBDEF bool nob_pipe_create(Nob_Pipe *pp); - -typedef struct { - Nob_Proc *items; - size_t count; - size_t capacity; -} Nob_Procs; - -// Wait until the process has finished -NOBDEF bool nob_proc_wait(Nob_Proc proc); - -// Wait until all the processes have finished -NOBDEF bool nob_procs_wait(Nob_Procs procs); - -// Wait until all the processes have finished and empty the procs array. -NOBDEF bool nob_procs_flush(Nob_Procs *procs); - -// Alias to nob_procs_flush -NOB_DEPRECATED("Use `nob_procs_flush(&procs)` instead.") -NOBDEF bool nob_procs_wait_and_reset(Nob_Procs *procs); - -// Append a new process to procs array and if procs.count reaches max_procs_count call nob_procs_wait_and_reset() on it -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, .async = &procs, .max_procs = )` instead") -NOBDEF bool nob_procs_append_with_flush(Nob_Procs *procs, Nob_Proc proc, size_t max_procs_count); - -// A command - the main workhorse of Nob. Nob is all about building commands and running them -typedef struct { - const char **items; - size_t count; - size_t capacity; -} Nob_Cmd; - -// Options for nob_cmd_run_opt() function. -typedef struct { - // Run the command asynchronously appending its Nob_Proc to the provided Nob_Procs array - Nob_Procs *async; - // Maximum processes allowed in the .async list. Zero implies nob_nprocs(). - size_t max_procs; - // Do not reset the command after execution. - bool dont_reset; - // Redirect stdin to file - const char *stdin_path; - // Redirect stdout to file - const char *stdout_path; - // Redirect stderr to file - const char *stderr_path; -} Nob_Cmd_Opt; - -// Run the command with options. -NOBDEF bool nob_cmd_run_opt(Nob_Cmd *cmd, Nob_Cmd_Opt opt); - -// Command Chains (in Shell Scripting they are know as Pipes) -// -// Usage: -// ```c -// Nob_Cmd cmd = {0}; -// Nob_Chain chain = {0}; -// if (!nob_chain_begin(&chain)) return 1; -// { -// nob_cmd_append(&cmd, "echo", "Hello, World"); -// if (!nob_chain_cmd(&chain, &cmd)) return 1; -// -// nob_cmd_append(&cmd, "rev"); -// if (!nob_chain_cmd(&chain, &cmd)) return 1; -// -// nob_cmd_append(&cmd, "xxd"); -// if (!nob_chain_cmd(&chain, &cmd)) return 1; -// } -// if (!nob_chain_end(&chain)) return 1; -// ``` -// -// The above is equivalent to a shell command: -// -// ```sh -// echo "Hello, World" | rev | xxd -// ``` -// -// After nob_chain_end() the Nob_Chain struct can be reused again. -// -// The fields of the Nob_Chain struct contain the intermediate state of the Command -// Chain that is being built with the nob_chain_cmd() calls and generally have no -// particular use for the user. -// -// The only memory dynamically allocated within Nob_Chain belongs to the .cmd field. -// So if you want to clean it all up you can just do free(chain.cmd.items). -typedef struct { - // The file descriptor of the output of the previous command. Will be used as the input for the next command. - Nob_Fd fdin; - // The command from the last nob_chain_cmd() call. - Nob_Cmd cmd; - // The value of the optional .err2out parameter from the last nob_chain_cmd() call. - bool err2out; -} Nob_Chain; - -typedef struct { - const char *stdin_path; -} Nob_Chain_Begin_Opt; -#define nob_chain_begin(chain, ...) nob_chain_begin_opt((chain), (Nob_Chain_Begin_Opt) { __VA_ARGS__ }) -NOBDEF bool nob_chain_begin_opt(Nob_Chain *chain, Nob_Chain_Begin_Opt opt); - -typedef struct { - bool err2out; - bool dont_reset; -} Nob_Chain_Cmd_Opt; -#define nob_chain_cmd(chain, cmd, ...) nob_chain_cmd_opt((chain), (cmd), (Nob_Chain_Cmd_Opt) { __VA_ARGS__ }) -NOBDEF bool nob_chain_cmd_opt(Nob_Chain *chain, Nob_Cmd *cmd, Nob_Chain_Cmd_Opt opt); - -typedef struct { - Nob_Procs *async; - size_t max_procs; - const char *stdout_path; - const char *stderr_path; -} Nob_Chain_End_Opt; -#define nob_chain_end(chain, ...) nob_chain_end_opt((chain), (Nob_Chain_End_Opt) { __VA_ARGS__ }) -NOBDEF bool nob_chain_end_opt(Nob_Chain *chain, Nob_Chain_End_Opt opt); - -// Get amount of processors on the machine. -NOBDEF int nob_nprocs(void); - -#define NOB_NANOS_PER_SEC (1000*1000*1000) - -// The maximum time span representable is 584 years. -NOBDEF uint64_t nob_nanos_since_unspecified_epoch(void); - -// Same as nob_cmd_run_opt but using cool variadic macro to set the default options. -// See https://x.com/vkrajacic/status/1749816169736073295 for more info on how to use such macros. -#define nob_cmd_run(cmd, ...) nob_cmd_run_opt((cmd), (Nob_Cmd_Opt){__VA_ARGS__}) - -// DEPRECATED: -// -// You were suppose to use this structure like this: -// -// ```c -// Nob_Fd fdin = nob_fd_open_for_read("input.txt"); -// if (fdin == NOB_INVALID_FD) fail(); -// Nob_Fd fdout = nob_fd_open_for_write("output.txt"); -// if (fdout == NOB_INVALID_FD) fail(); -// Nob_Cmd cmd = {0}; -// nob_cmd_append(&cmd, "cat"); -// if (!nob_cmd_run_sync_redirect_and_reset(&cmd, (Nob_Cmd_Redirect) { -// .fdin = &fdin, -// .fdout = &fdout -// })) fail(); -// ``` -// -// But these days you should do: -// -// ```c -// Nob_Cmd cmd = {0}; -// nob_cmd_append(&cmd, "cat"); -// if (!nob_cmd_run(&cmd, .stdin_path = "input.txt", .stdout_path = "output.txt")) fail(); -// ``` -typedef struct { - Nob_Fd *fdin; - Nob_Fd *fdout; - Nob_Fd *fderr; -} Nob_Cmd_Redirect; - -// Render a string representation of a command into a string builder. Keep in mind the the -// string builder is not NULL-terminated by default. Use nob_sb_append_null if you plan to -// use it as a C string. -NOBDEF void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render); - -NOBDEF void nob__cmd_append(Nob_Cmd *cmd, size_t n, ...); -#define nob_cmd_append(cmd, ...) \ - nob__cmd_append(cmd, (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*)), __VA_ARGS__) - -// TODO: nob_cmd_extend() evaluates other_cmd twice -// It can be fixed by turning nob_cmd_extend() call into a statement. -// But that may break backward compatibility of the API. -#define nob_cmd_extend(cmd, other_cmd) \ - nob_da_append_many(cmd, (other_cmd)->items, (other_cmd)->count) - -// Free all the memory allocated by command arguments -#define nob_cmd_free(cmd) NOB_FREE(cmd.items) - -// Run command asynchronously -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, .async = &procs, .dont_reset = true)`.") -NOBDEF Nob_Proc nob_cmd_run_async(Nob_Cmd cmd); - -// nob_cmd_run_async_and_reset() is just like nob_cmd_run_async() except it also resets cmd.count to 0 -// so the Nob_Cmd instance can be seamlessly used several times in a row -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, .async = &procs)` intead.") -NOBDEF Nob_Proc nob_cmd_run_async_and_reset(Nob_Cmd *cmd); - -// Run redirected command asynchronously -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, " - ".async = &procs, " - ".stdin_path = \"path/to/stdin\", " - ".stdout_path = \"path/to/stdout\", " - ".stderr_path = \"path/to/stderr\", " - ".dont_reset = true" - ")` instead.") -NOBDEF Nob_Proc nob_cmd_run_async_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect); - -// Run redirected command asynchronously and set cmd.count to 0 and close all the opened files -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, " - ".async = &procs, " - ".stdin_path = \"path/to/stdin\", " - ".stdout_path = \"path/to/stdout\", " - ".stderr_path = \"path/to/stderr\")` instead.") -NOBDEF Nob_Proc nob_cmd_run_async_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect); - -// Run command synchronously -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, .dont_reset = true)` instead.") -NOBDEF bool nob_cmd_run_sync(Nob_Cmd cmd); - -// NOTE: nob_cmd_run_sync_and_reset() is just like nob_cmd_run_sync() except it also resets cmd.count to 0 -// so the Nob_Cmd instance can be seamlessly used several times in a row -NOB_DEPRECATED("Use `nob_cmd_run(&cmd)` instead.") -NOBDEF bool nob_cmd_run_sync_and_reset(Nob_Cmd *cmd); - -// Run redirected command synchronously -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, " - ".stdin_path = \"path/to/stdin\", " - ".stdout_path = \"path/to/stdout\", " - ".stderr_path = \"path/to/stderr\", " - ".dont_reset = true" - ")` instead.") -NOBDEF bool nob_cmd_run_sync_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect); - -// Run redirected command synchronously and set cmd.count to 0 and close all the opened files -NOB_DEPRECATED("Use `nob_cmd_run(&cmd, " - ".stdin_path = \"path/to/stdin\", " - ".stdout_path = \"path/to/stdout\", " - ".stderr_path = \"path/to/stderr\")` instead.") -NOBDEF bool nob_cmd_run_sync_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect); - -#ifndef NOB_TEMP_CAPACITY -#define NOB_TEMP_CAPACITY (8*1024*1024) -#endif // NOB_TEMP_CAPACITY -NOBDEF char *nob_temp_strdup(const char *cstr); -NOBDEF char *nob_temp_strndup(const char *cstr, size_t size); -NOBDEF void *nob_temp_alloc(size_t size); -NOBDEF char *nob_temp_sprintf(const char *format, ...) NOB_PRINTF_FORMAT(1, 2); -NOBDEF char *nob_temp_vsprintf(const char *format, va_list ap); -// nob_temp_reset() - Resets the entire temporary storage to 0. -// -// It is generally not recommended to call this function ever. What you usually want to do is let's say you have a loop, -// that allocates some temporary objects and cleans them up at the end of each iteration. You should use -// nob_temp_save() and nob_temp_rewind() to organize such loop like this: -// -// ```c -// char *message = nob_temp_sprintf("This message is still valid after the loop below"); -// while (!quit) { -// size_t mark = nob_temp_save(); -// nob_temp_alloc(69); -// nob_temp_alloc(420); -// nob_temp_alloc(1337); -// nob_temp_rewind(mark); -// } -// printf("%s\n", message); -// ``` -// -// That way all the temporary allocations created before the loop are still valid even after the loop. -// Such save/rewind blocks define lifetime boundaries of the temporary objects which also could be nested. -// This turns the temporary storage into kind of a second stack with a more manual management. -NOBDEF void nob_temp_reset(void); -NOBDEF size_t nob_temp_save(void); -NOBDEF void nob_temp_rewind(size_t checkpoint); - -// Given any path returns the last part of that path. -// "/path/to/a/file.c" -> "file.c"; "/path/to/a/directory" -> "directory" -NOBDEF const char *nob_path_name(const char *path); -NOBDEF bool nob_rename(const char *old_path, const char *new_path); -NOBDEF int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count); -NOBDEF int nob_needs_rebuild1(const char *output_path, const char *input_path); -NOBDEF int nob_file_exists(const char *file_path); -NOBDEF const char *nob_get_current_dir_temp(void); -NOBDEF bool nob_set_current_dir(const char *path); -// Returns you the directory part of the path allocated on the temporary storage. -NOBDEF char *nob_temp_dir_name(const char *path); -NOBDEF char *nob_temp_file_name(const char *path); -NOBDEF char *nob_temp_file_ext(const char *path); -NOBDEF char *nob_temp_running_executable_path(void); - -// TODO: we should probably document somewhere all the compilers we support - -// The nob_cc_* macros try to abstract away the specific compiler. -// They are verify basic and not particularly flexible, but you can redefine them if you need to -// or not use them at all and create your own abstraction on top of Nob_Cmd. - -#ifndef nob_cc -# if _WIN32 -# if defined(__GNUC__) -# define nob_cc(cmd) nob_cmd_append(cmd, "cc") -# elif defined(__clang__) -# define nob_cc(cmd) nob_cmd_append(cmd, "clang") -# elif defined(_MSC_VER) -# define nob_cc(cmd) nob_cmd_append(cmd, "cl.exe") -# elif defined(__TINYC__) -# define nob_cc(cmd) nob_cmd_append(cmd, "tcc") -# endif -# else -# define nob_cc(cmd) nob_cmd_append(cmd, "cc") -# endif -#endif // nob_cc - -#ifndef nob_cc_flags -# if defined(_MSC_VER) && !defined(__clang__) -# define nob_cc_flags(cmd) nob_cmd_append(cmd, "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS") -# else -# define nob_cc_flags(cmd) nob_cmd_append(cmd, "-Wall", "-Wextra") -# endif -#endif // nob_cc_flags - -#ifndef nob_cc_output -# if defined(_MSC_VER) && !defined(__clang__) -# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, nob_temp_sprintf("/Fe:%s", (output_path)), nob_temp_sprintf("/Fo:%s", (output_path))) -# else -# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, "-o", (output_path)) -# endif -#endif // nob_cc_output - -#ifndef nob_cc_inputs -# define nob_cc_inputs(cmd, ...) nob_cmd_append(cmd, __VA_ARGS__) -#endif // nob_cc_inputs - -// TODO: add MinGW support for Go Rebuild Urself™ Technology and all the nob_cc_* macros above -// Musializer contributors came up with a pretty interesting idea of an optional prefix macro which could be useful for -// MinGW support: -// https://github.com/tsoding/musializer/blob/b7578cc76b9ecb573d239acc9ccf5a04d3aba2c9/src_build/nob_win64_mingw.c#L3-L9 -// TODO: Maybe instead NOB_REBUILD_URSELF macro, the Go Rebuild Urself™ Technology should use the -// user defined nob_cc_* macros instead? -#ifndef NOB_REBUILD_URSELF -# if defined(_WIN32) -# if defined(__clang__) -# if defined(__cplusplus) -# define NOB_REBUILD_URSELF(binary_path, source_path) "clang", "-x", "c++", "-o", binary_path, source_path -# else -# define NOB_REBUILD_URSELF(binary_path, source_path) "clang", "-x", "c", "-o", binary_path, source_path -# endif -# elif defined(__GNUC__) -# if defined(__cplusplus) -# define NOB_REBUILD_URSELF(binary_path, source_path) "gcc", "-x", "c++", "-o", binary_path, source_path -# else -# define NOB_REBUILD_URSELF(binary_path, source_path) "gcc", "-x", "c", "-o", binary_path, source_path -# endif -# elif defined(_MSC_VER) -# define NOB_REBUILD_URSELF(binary_path, source_path) "cl.exe", nob_temp_sprintf("/Fe:%s", (binary_path)), source_path -# elif defined(__TINYC__) -# define NOB_REBUILD_URSELF(binary_path, source_path) "tcc", "-o", binary_path, source_path -# endif -# else -# if defined(__cplusplus) -# define NOB_REBUILD_URSELF(binary_path, source_path) "cc", "-x", "c++", "-o", binary_path, source_path -# else -# define NOB_REBUILD_URSELF(binary_path, source_path) "cc", "-x", "c", "-o", binary_path, source_path -# endif -# endif -#endif - -// Go Rebuild Urself™ Technology -// -// How to use it: -// int main(int argc, char** argv) { -// NOB_GO_REBUILD_URSELF(argc, argv); -// // actual work -// return 0; -// } -// -// After you added this macro every time you run ./nob it will detect -// that you modified its original source code and will try to rebuild itself -// before doing any actual work. So you only need to bootstrap your build system -// once. -// -// The modification is detected by comparing the last modified times of the executable -// and its source code. The same way the make utility usually does it. -// -// The rebuilding is done by using the NOB_REBUILD_URSELF macro which you can redefine -// if you need a special way of bootstraping your build system. (which I personally -// do not recommend since the whole idea of NoBuild is to keep the process of bootstrapping -// as simple as possible and doing all of the actual work inside of ./nob) -// -NOBDEF void nob__go_rebuild_urself(int argc, char **argv, const char *source_path, ...); -#define NOB_GO_REBUILD_URSELF(argc, argv) nob__go_rebuild_urself(argc, argv, __FILE__, NULL) -// Sometimes your nob.c includes additional files, so you want the Go Rebuild Urself™ Technology to check -// if they also were modified and rebuild nob.c accordingly. For that we have NOB_GO_REBUILD_URSELF_PLUS(): -// ```c -// #define NOB_IMPLEMENTATION -// #include "nob.h" -// -// #include "foo.c" -// #include "bar.c" -// -// int main(int argc, char **argv) -// { -// NOB_GO_REBUILD_URSELF_PLUS(argc, argv, "foo.c", "bar.c"); -// // ... -// return 0; -// } -#define NOB_GO_REBUILD_URSELF_PLUS(argc, argv, ...) nob__go_rebuild_urself(argc, argv, __FILE__, __VA_ARGS__, NULL); - -typedef struct { - size_t count; - const char *data; -} Nob_String_View; - -NOBDEF const char *nob_temp_sv_to_cstr(Nob_String_View sv); - -NOBDEF Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim); -NOBDEF Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n); -NOBDEF Nob_String_View nob_sv_trim(Nob_String_View sv); -NOBDEF Nob_String_View nob_sv_trim_left(Nob_String_View sv); -NOBDEF Nob_String_View nob_sv_trim_right(Nob_String_View sv); -NOBDEF bool nob_sv_eq(Nob_String_View a, Nob_String_View b); -NOBDEF bool nob_sv_end_with(Nob_String_View sv, const char *cstr); -NOBDEF bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix); -NOBDEF Nob_String_View nob_sv_from_cstr(const char *cstr); -NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count); -// nob_sb_to_sv() enables you to just view Nob_String_Builder as Nob_String_View -#define nob_sb_to_sv(sb) nob_sv_from_parts((sb).items, (sb).count) - -// printf macros for String_View -#ifndef SV_Fmt -#define SV_Fmt "%.*s" -#endif // SV_Fmt -#ifndef SV_Arg -#define SV_Arg(sv) (int) (sv).count, (sv).data -#endif // SV_Arg -// USAGE: -// String_View name = ...; -// printf("Name: "SV_Fmt"\n", SV_Arg(name)); - -#ifdef _WIN32 - -NOBDEF char *nob_win32_error_message(DWORD err); - -#endif // _WIN32 - -#endif // NOB_H_ - -#ifdef NOB_IMPLEMENTATION - -// This is like nob_proc_wait() but waits asynchronously. Depending on the platform ms means different thing. -// On Windows it means timeout. On POSIX it means for how long to sleep after checking if the process exited, -// so to not peg the core too much. Since this API is kinda of weird, the function is private for now. -static int nob__proc_wait_async(Nob_Proc proc, int ms); - -// Starts the process for the command. Its main purpose is to be the base for nob_cmd_run() and nob_cmd_run_opt(). -static Nob_Proc nob__cmd_start_process(Nob_Cmd cmd, Nob_Fd *fdin, Nob_Fd *fdout, Nob_Fd *fderr); - -// Any messages with the level below nob_minimal_log_level are going to be suppressed. -Nob_Log_Level nob_minimal_log_level = NOB_INFO; - -NOBDEF void nob__cmd_append(Nob_Cmd *cmd, size_t n, ...) -{ - va_list args; - va_start(args, n); - for (size_t i = 0; i < n; ++i) { - const char *arg = va_arg(args, const char *); - nob_da_append(cmd, arg); - } - va_end(args); -} - -#ifdef _WIN32 - -// Base on https://stackoverflow.com/a/75644008 -// > .NET Core uses 4096 * sizeof(WCHAR) buffer on stack for FormatMessageW call. And...thats it. -// > -// > https://github.com/dotnet/runtime/blob/3b63eb1346f1ddbc921374a5108d025662fb5ffd/src/coreclr/utilcode/posterror.cpp#L264-L265 -#ifndef NOB_WIN32_ERR_MSG_SIZE -#define NOB_WIN32_ERR_MSG_SIZE (4 * 1024) -#endif // NOB_WIN32_ERR_MSG_SIZE - -NOBDEF char *nob_win32_error_message(DWORD err) { - static char win32ErrMsg[NOB_WIN32_ERR_MSG_SIZE] = {0}; - DWORD errMsgSize = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, LANG_USER_DEFAULT, win32ErrMsg, - NOB_WIN32_ERR_MSG_SIZE, NULL); - - if (errMsgSize == 0) { - if (GetLastError() != ERROR_MR_MID_NOT_FOUND) { - if (sprintf(win32ErrMsg, "Could not get error message for 0x%lX", err) > 0) { - return (char *)&win32ErrMsg; - } else { - return NULL; - } - } else { - if (sprintf(win32ErrMsg, "Invalid Windows Error code (0x%lX)", err) > 0) { - return (char *)&win32ErrMsg; - } else { - return NULL; - } - } - } - - while (errMsgSize > 1 && isspace(win32ErrMsg[errMsgSize - 1])) { - win32ErrMsg[--errMsgSize] = '\0'; - } - - return win32ErrMsg; -} - -#endif // _WIN32 - -// The implementation idea is stolen from https://github.com/zhiayang/nabs -NOBDEF void nob__go_rebuild_urself(int argc, char **argv, const char *source_path, ...) -{ - const char *binary_path = nob_shift(argv, argc); -#ifdef _WIN32 - // On Windows executables almost always invoked without extension, so - // it's ./nob, not ./nob.exe. For renaming the extension is a must. - if (!nob_sv_end_with(nob_sv_from_cstr(binary_path), ".exe")) { - binary_path = nob_temp_sprintf("%s.exe", binary_path); - } -#endif - - Nob_File_Paths source_paths = {0}; - nob_da_append(&source_paths, source_path); - va_list args; - va_start(args, source_path); - for (;;) { - const char *path = va_arg(args, const char*); - if (path == NULL) break; - nob_da_append(&source_paths, path); - } - va_end(args); - - int rebuild_is_needed = nob_needs_rebuild(binary_path, source_paths.items, source_paths.count); - if (rebuild_is_needed < 0) exit(1); // error - if (!rebuild_is_needed) { // no rebuild is needed - NOB_FREE(source_paths.items); - return; - } - - Nob_Cmd cmd = {0}; - - const char *old_binary_path = nob_temp_sprintf("%s.old", binary_path); - - if (!nob_rename(binary_path, old_binary_path)) exit(1); - nob_cmd_append(&cmd, NOB_REBUILD_URSELF(binary_path, source_path)); - Nob_Cmd_Opt opt = {0}; - if (!nob_cmd_run_opt(&cmd, opt)) { - nob_rename(old_binary_path, binary_path); - exit(1); - } -#ifdef NOB_EXPERIMENTAL_DELETE_OLD - // TODO: this is an experimental behavior behind a compilation flag. - // Once it is confirmed that it does not cause much problems on both POSIX and Windows - // we may turn it on by default. - nob_delete_file(old_binary_path); -#endif // NOB_EXPERIMENTAL_DELETE_OLD - - nob_cmd_append(&cmd, binary_path); - nob_da_append_many(&cmd, argv, argc); - if (!nob_cmd_run_opt(&cmd, opt)) exit(1); - exit(0); -} - -static size_t nob_temp_size = 0; -static char nob_temp[NOB_TEMP_CAPACITY] = {0}; - -NOBDEF bool nob_mkdir_if_not_exists(const char *path) -{ -#ifdef _WIN32 - int result = _mkdir(path); -#else - int result = mkdir(path, 0755); -#endif - if (result < 0) { - if (errno == EEXIST) { -#ifndef NOB_NO_ECHO - nob_log(NOB_INFO, "directory `%s` already exists", path); -#endif // NOB_NO_ECHO - return true; - } - nob_log(NOB_ERROR, "could not create directory `%s`: %s", path, strerror(errno)); - return false; - } - -#ifndef NOB_NO_ECHO - nob_log(NOB_INFO, "created directory `%s`", path); -#endif // NOB_NO_ECHO - return true; -} - -NOBDEF bool nob_copy_file(const char *src_path, const char *dst_path) -{ -#ifndef NOB_NO_ECHO - nob_log(NOB_INFO, "copying %s -> %s", src_path, dst_path); -#endif // NOB_NO_ECHO -#ifdef _WIN32 - if (!CopyFile(src_path, dst_path, FALSE)) { - nob_log(NOB_ERROR, "Could not copy file: %s", nob_win32_error_message(GetLastError())); - return false; - } - return true; -#else - int src_fd = -1; - int dst_fd = -1; - size_t buf_size = 32*1024; - char *buf = (char*)NOB_REALLOC(NULL, buf_size); - NOB_ASSERT(buf != NULL && "Buy more RAM lol!!"); - bool result = true; - - src_fd = open(src_path, O_RDONLY); - if (src_fd < 0) { - nob_log(NOB_ERROR, "Could not open file %s: %s", src_path, strerror(errno)); - nob_return_defer(false); - } - - struct stat src_stat; - if (fstat(src_fd, &src_stat) < 0) { - nob_log(NOB_ERROR, "Could not get mode of file %s: %s", src_path, strerror(errno)); - nob_return_defer(false); - } - - dst_fd = open(dst_path, O_CREAT | O_TRUNC | O_WRONLY, src_stat.st_mode); - if (dst_fd < 0) { - nob_log(NOB_ERROR, "Could not create file %s: %s", dst_path, strerror(errno)); - nob_return_defer(false); - } - - for (;;) { - ssize_t n = read(src_fd, buf, buf_size); - if (n == 0) break; - if (n < 0) { - nob_log(NOB_ERROR, "Could not read from file %s: %s", src_path, strerror(errno)); - nob_return_defer(false); - } - char *buf2 = buf; - while (n > 0) { - ssize_t m = write(dst_fd, buf2, n); - if (m < 0) { - nob_log(NOB_ERROR, "Could not write to file %s: %s", dst_path, strerror(errno)); - nob_return_defer(false); - } - n -= m; - buf2 += m; - } - } - -defer: - NOB_FREE(buf); - close(src_fd); - close(dst_fd); - return result; -#endif -} - -NOBDEF void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render) -{ - for (size_t i = 0; i < cmd.count; ++i) { - const char *arg = cmd.items[i]; - if (arg == NULL) break; - if (i > 0) nob_sb_append_cstr(render, " "); - if (!strchr(arg, ' ')) { - nob_sb_append_cstr(render, arg); - } else { - nob_da_append(render, '\''); - nob_sb_append_cstr(render, arg); - nob_da_append(render, '\''); - } - } -} - -#ifdef _WIN32 -// https://learn.microsoft.com/en-gb/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way -static void nob__win32_cmd_quote(Nob_Cmd cmd, Nob_String_Builder *quoted) -{ - for (size_t i = 0; i < cmd.count; ++i) { - const char *arg = cmd.items[i]; - if (arg == NULL) break; - size_t len = strlen(arg); - if (i > 0) nob_da_append(quoted, ' '); - if (len != 0 && NULL == strpbrk(arg, " \t\n\v\"")) { - // no need to quote - nob_da_append_many(quoted, arg, len); - } else { - // we need to escape: - // 1. double quotes in the original arg - // 2. consequent backslashes before a double quote - size_t backslashes = 0; - nob_da_append(quoted, '\"'); - for (size_t j = 0; j < len; ++j) { - char x = arg[j]; - if (x == '\\') { - backslashes += 1; - } else { - if (x == '\"') { - // escape backslashes (if any) and the double quote - for (size_t k = 0; k < 1+backslashes; ++k) { - nob_da_append(quoted, '\\'); - } - } - backslashes = 0; - } - nob_da_append(quoted, x); - } - // escape backslashes (if any) - for (size_t k = 0; k < backslashes; ++k) { - nob_da_append(quoted, '\\'); - } - nob_da_append(quoted, '\"'); - } - } -} -#endif - -NOBDEF int nob_nprocs(void) -{ -#ifdef _WIN32 - SYSTEM_INFO siSysInfo; - GetSystemInfo(&siSysInfo); - return siSysInfo.dwNumberOfProcessors; -#else - return sysconf(_SC_NPROCESSORS_ONLN); -#endif -} - -NOBDEF bool nob_cmd_run_opt(Nob_Cmd *cmd, Nob_Cmd_Opt opt) -{ - bool result = true; - Nob_Fd fdin = NOB_INVALID_FD; - Nob_Fd fdout = NOB_INVALID_FD; - Nob_Fd fderr = NOB_INVALID_FD; - Nob_Fd *opt_fdin = NULL; - Nob_Fd *opt_fdout = NULL; - Nob_Fd *opt_fderr = NULL; - Nob_Proc proc = NOB_INVALID_PROC; - - size_t max_procs = opt.max_procs > 0 ? opt.max_procs : (size_t) nob_nprocs() + 1; - - if (opt.async && max_procs > 0) { - while (opt.async->count >= max_procs) { - for (size_t i = 0; i < opt.async->count; ++i) { - int ret = nob__proc_wait_async(opt.async->items[i], 1); - if (ret < 0) nob_return_defer(false); - if (ret) { - nob_da_remove_unordered(opt.async, i); - break; - } - } - } - } - - if (opt.stdin_path) { - fdin = nob_fd_open_for_read(opt.stdin_path); - if (fdin == NOB_INVALID_FD) nob_return_defer(false); - opt_fdin = &fdin; - } - if (opt.stdout_path) { - fdout = nob_fd_open_for_write(opt.stdout_path); - if (fdout == NOB_INVALID_FD) nob_return_defer(false); - opt_fdout = &fdout; - } - if (opt.stderr_path) { - fderr = nob_fd_open_for_write(opt.stderr_path); - if (fderr == NOB_INVALID_FD) nob_return_defer(false); - opt_fderr = &fderr; - } - proc = nob__cmd_start_process(*cmd, opt_fdin, opt_fdout, opt_fderr); - - if (opt.async) { - if (proc == NOB_INVALID_PROC) nob_return_defer(false); - nob_da_append(opt.async, proc); - } else { - if (!nob_proc_wait(proc)) nob_return_defer(false); - } - -defer: - if (opt_fdin) nob_fd_close(*opt_fdin); - if (opt_fdout) nob_fd_close(*opt_fdout); - if (opt_fderr) nob_fd_close(*opt_fderr); - if (!opt.dont_reset) cmd->count = 0; - return result; -} - -NOBDEF bool nob_chain_begin_opt(Nob_Chain *chain, Nob_Chain_Begin_Opt opt) -{ - chain->cmd.count = 0; - chain->err2out = false; - chain->fdin = NOB_INVALID_FD; - if (opt.stdin_path) { - chain->fdin = nob_fd_open_for_read(opt.stdin_path); - if (chain->fdin == NOB_INVALID_FD) return false; - } - return true; -} - -NOBDEF bool nob_chain_cmd_opt(Nob_Chain *chain, Nob_Cmd *cmd, Nob_Chain_Cmd_Opt opt) -{ - bool result = true; - Nob_Pipe pp = {0}; - struct { - Nob_Fd items[5]; // should be no more than 3, but we allocate 5 just in case - size_t count; - } fds = {0}; - - NOB_ASSERT(cmd->count > 0); - - if (chain->cmd.count != 0) { // not first cmd in the chain - Nob_Fd *pfdin = NULL; - if (chain->fdin != NOB_INVALID_FD) { - nob_fa_append(&fds, chain->fdin); - pfdin = &chain->fdin; - } - if (!nob_pipe_create(&pp)) nob_return_defer(false); - nob_fa_append(&fds, pp.write); - Nob_Fd *pfdout = &pp.write; - Nob_Fd *pfderr = chain->err2out ? pfdout : NULL; - - Nob_Proc proc = nob__cmd_start_process(chain->cmd, pfdin, pfdout, pfderr); - chain->cmd.count = 0; - if (proc == NOB_INVALID_PROC) { - nob_fa_append(&fds, pp.read); - nob_return_defer(false); - } - chain->fdin = pp.read; - } - - nob_da_append_many(&chain->cmd, cmd->items, cmd->count); - chain->err2out = opt.err2out; - -defer: - for (size_t i = 0; i < fds.count; ++i) { - nob_fd_close(fds.items[i]); - } - if (!opt.dont_reset) cmd->count = 0; - return result; -} - -static Nob_Fd nob__fd_stdout(void) -{ -#ifdef _WIN32 - return GetStdHandle(STD_OUTPUT_HANDLE); -#else - return STDOUT_FILENO; -#endif // _WIN32 -} - -NOBDEF bool nob_chain_end_opt(Nob_Chain *chain, Nob_Chain_End_Opt opt) -{ - bool result = true; - - Nob_Fd *pfdin = NULL; - struct { - Nob_Fd items[5]; // should be no more than 3, but we allocate 5 just in case - size_t count; - } fds = {0}; - - if (chain->fdin != NOB_INVALID_FD) { - nob_fa_append(&fds, chain->fdin); - pfdin = &chain->fdin; - } - - if (chain->cmd.count != 0) { // Non-empty chain case - size_t max_procs = opt.max_procs > 0 ? opt.max_procs : (size_t) nob_nprocs() + 1; - - if (opt.async && max_procs > 0) { - while (opt.async->count >= max_procs) { - for (size_t i = 0; i < opt.async->count; ++i) { - int ret = nob__proc_wait_async(opt.async->items[i], 1); - if (ret < 0) nob_return_defer(false); - if (ret) { - nob_da_remove_unordered(opt.async, i); - break; - } - } - } - } - - Nob_Fd fdout = nob__fd_stdout(); - if (opt.stdout_path) { - fdout = nob_fd_open_for_write(opt.stdout_path); - if (fdout == NOB_INVALID_FD) nob_return_defer(false); - nob_fa_append(&fds, fdout); - } - - Nob_Fd fderr = 0; - Nob_Fd *pfderr = NULL; - if (chain->err2out) pfderr = &fdout; - if (opt.stderr_path) { - if (pfderr == NULL) { - fderr = nob_fd_open_for_write(opt.stderr_path); - if (fderr == NOB_INVALID_FD) nob_return_defer(false); - nob_fa_append(&fds, fderr); - pfderr = &fderr; - } else { - // There was err2out set for the last command. - // All the stderr will go to stdout. - // So the stderr file is going to be empty. - NOB_ASSERT(chain->err2out); - if (!nob_write_entire_file(opt.stderr_path, NULL, 0)) nob_return_defer(false); - } - } - - Nob_Proc proc = nob__cmd_start_process(chain->cmd, pfdin, &fdout, pfderr); - chain->cmd.count = 0; - - if (opt.async) { - if (proc == NOB_INVALID_PROC) nob_return_defer(false); - nob_da_append(opt.async, proc); - } else { - if (!nob_proc_wait(proc)) nob_return_defer(false); - } - } - -defer: - for (size_t i = 0; i < fds.count; ++i) { - nob_fd_close(fds.items[i]); - } - return result; -} - -// The maximum time span representable is 584 years. -NOBDEF uint64_t nob_nanos_since_unspecified_epoch(void) -{ -#ifdef _WIN32 - LARGE_INTEGER Time; - QueryPerformanceCounter(&Time); - - static LARGE_INTEGER Frequency = {0}; - if (Frequency.QuadPart == 0) { - QueryPerformanceFrequency(&Frequency); - } - - uint64_t Secs = Time.QuadPart / Frequency.QuadPart; - uint64_t Nanos = Time.QuadPart % Frequency.QuadPart * NOB_NANOS_PER_SEC / Frequency.QuadPart; - return NOB_NANOS_PER_SEC * Secs + Nanos; -#else - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - - return NOB_NANOS_PER_SEC * ts.tv_sec + ts.tv_nsec; -#endif // _WIN32 -} - -NOBDEF Nob_Proc nob_cmd_run_async_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect) -{ - return nob__cmd_start_process(cmd, redirect.fdin, redirect.fdout, redirect.fderr); -} - -static Nob_Proc nob__cmd_start_process(Nob_Cmd cmd, Nob_Fd *fdin, Nob_Fd *fdout, Nob_Fd *fderr) -{ - if (cmd.count < 1) { - nob_log(NOB_ERROR, "Could not run empty command"); - return NOB_INVALID_PROC; - } - -#ifndef NOB_NO_ECHO - Nob_String_Builder sb = {0}; - nob_cmd_render(cmd, &sb); - nob_sb_append_null(&sb); - nob_log(NOB_INFO, "CMD: %s", sb.items); - nob_sb_free(sb); - memset(&sb, 0, sizeof(sb)); -#endif // NOB_NO_ECHO - -#ifdef _WIN32 - // https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output - - STARTUPINFO siStartInfo; - ZeroMemory(&siStartInfo, sizeof(siStartInfo)); - siStartInfo.cb = sizeof(STARTUPINFO); - // NOTE: theoretically setting NULL to std handles should not be a problem - // https://docs.microsoft.com/en-us/windows/console/getstdhandle?redirectedfrom=MSDN#attachdetach-behavior - // TODO: check for errors in GetStdHandle - siStartInfo.hStdError = fderr ? *fderr : GetStdHandle(STD_ERROR_HANDLE); - siStartInfo.hStdOutput = fdout ? *fdout : GetStdHandle(STD_OUTPUT_HANDLE); - siStartInfo.hStdInput = fdin ? *fdin : GetStdHandle(STD_INPUT_HANDLE); - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - PROCESS_INFORMATION piProcInfo; - ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); - - Nob_String_Builder quoted = {0}; - nob__win32_cmd_quote(cmd, "ed); - nob_sb_append_null("ed); - BOOL bSuccess = CreateProcessA(NULL, quoted.items, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo); - nob_sb_free(quoted); - - if (!bSuccess) { - nob_log(NOB_ERROR, "Could not create child process for %s: %s", cmd.items[0], nob_win32_error_message(GetLastError())); - return NOB_INVALID_PROC; - } - - CloseHandle(piProcInfo.hThread); - - return piProcInfo.hProcess; -#else - pid_t cpid = fork(); - if (cpid < 0) { - nob_log(NOB_ERROR, "Could not fork child process: %s", strerror(errno)); - return NOB_INVALID_PROC; - } - - if (cpid == 0) { - if (fdin) { - if (dup2(*fdin, STDIN_FILENO) < 0) { - nob_log(NOB_ERROR, "Could not setup stdin for child process: %s", strerror(errno)); - exit(1); - } - } - - if (fdout) { - if (dup2(*fdout, STDOUT_FILENO) < 0) { - nob_log(NOB_ERROR, "Could not setup stdout for child process: %s", strerror(errno)); - exit(1); - } - } - - if (fderr) { - if (dup2(*fderr, STDERR_FILENO) < 0) { - nob_log(NOB_ERROR, "Could not setup stderr for child process: %s", strerror(errno)); - exit(1); - } - } - - // NOTE: This leaks a bit of memory in the child process. - // But do we actually care? It's a one off leak anyway... - Nob_Cmd cmd_null = {0}; - nob_da_append_many(&cmd_null, cmd.items, cmd.count); - nob_cmd_append(&cmd_null, NULL); - - if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) { - nob_log(NOB_ERROR, "Could not exec child process for %s: %s", cmd.items[0], strerror(errno)); - exit(1); - } - NOB_UNREACHABLE("nob_cmd_run_async_redirect"); - } - - return cpid; -#endif -} - -NOBDEF Nob_Proc nob_cmd_run_async(Nob_Cmd cmd) -{ - return nob__cmd_start_process(cmd, NULL, NULL, NULL); -} - -NOBDEF Nob_Proc nob_cmd_run_async_and_reset(Nob_Cmd *cmd) -{ - Nob_Proc proc = nob__cmd_start_process(*cmd, NULL, NULL, NULL); - cmd->count = 0; - return proc; -} - -NOBDEF Nob_Proc nob_cmd_run_async_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect) -{ - Nob_Proc proc = nob__cmd_start_process(*cmd, redirect.fdin, redirect.fdout, redirect.fderr); - cmd->count = 0; - if (redirect.fdin) { - nob_fd_close(*redirect.fdin); - *redirect.fdin = NOB_INVALID_FD; - } - if (redirect.fdout) { - nob_fd_close(*redirect.fdout); - *redirect.fdout = NOB_INVALID_FD; - } - if (redirect.fderr) { - nob_fd_close(*redirect.fderr); - *redirect.fderr = NOB_INVALID_FD; - } - return proc; -} - -NOBDEF Nob_Fd nob_fd_open_for_read(const char *path) -{ -#ifndef _WIN32 - Nob_Fd result = open(path, O_RDONLY); - if (result < 0) { - nob_log(NOB_ERROR, "Could not open file %s: %s", path, strerror(errno)); - return NOB_INVALID_FD; - } - return result; -#else - // https://docs.microsoft.com/en-us/windows/win32/fileio/opening-a-file-for-reading-or-writing - SECURITY_ATTRIBUTES saAttr = {0}; - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - - Nob_Fd result = CreateFile( - path, - GENERIC_READ, - 0, - &saAttr, - OPEN_EXISTING, - FILE_ATTRIBUTE_READONLY, - NULL); - - if (result == INVALID_HANDLE_VALUE) { - nob_log(NOB_ERROR, "Could not open file %s: %s", path, nob_win32_error_message(GetLastError())); - return NOB_INVALID_FD; - } - - return result; -#endif // _WIN32 -} - -NOBDEF Nob_Fd nob_fd_open_for_write(const char *path) -{ -#ifndef _WIN32 - Nob_Fd result = open(path, - O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (result < 0) { - nob_log(NOB_ERROR, "could not open file %s: %s", path, strerror(errno)); - return NOB_INVALID_FD; - } - return result; -#else - SECURITY_ATTRIBUTES saAttr = {0}; - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - - Nob_Fd result = CreateFile( - path, // name of the write - GENERIC_WRITE, // open for writing - 0, // do not share - &saAttr, // default security - CREATE_ALWAYS, // create always - FILE_ATTRIBUTE_NORMAL, // normal file - NULL // no attr. template - ); - - if (result == INVALID_HANDLE_VALUE) { - nob_log(NOB_ERROR, "Could not open file %s: %s", path, nob_win32_error_message(GetLastError())); - return NOB_INVALID_FD; - } - - return result; -#endif // _WIN32 -} - -NOBDEF void nob_fd_close(Nob_Fd fd) -{ -#ifdef _WIN32 - CloseHandle(fd); -#else - close(fd); -#endif // _WIN32 -} - -NOBDEF bool nob_pipe_create(Nob_Pipe *pp) -{ -#ifdef _WIN32 - // https://docs.microsoft.com/en-us/windows/win32/ProcThread/creating-a-child-process-with-redirected-input-and-output - - SECURITY_ATTRIBUTES saAttr = {0}; - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - - if (!CreatePipe(&pp->read, &pp->write, &saAttr, 0)) { - nob_log(NOB_ERROR, "Could not create pipe: %s", nob_win32_error_message(GetLastError())); - return false; - } - - return true; -#else - int pipefd[2]; - if (pipe(pipefd) < 0) { - nob_log(NOB_ERROR, "Could not create pipe: %s\n", strerror(errno)); - return false; - } - - pp->read = pipefd[0]; - pp->write = pipefd[1]; - - return true; -#endif // _WIN32 -} - -NOBDEF bool nob_procs_wait(Nob_Procs procs) -{ - bool success = true; - for (size_t i = 0; i < procs.count; ++i) { - success = nob_proc_wait(procs.items[i]) && success; - } - return success; -} - -NOBDEF bool nob_procs_flush(Nob_Procs *procs) -{ - bool success = nob_procs_wait(*procs); - procs->count = 0; - return success; -} - -NOBDEF bool nob_procs_wait_and_reset(Nob_Procs *procs) -{ - return nob_procs_flush(procs); -} - -NOBDEF bool nob_proc_wait(Nob_Proc proc) -{ - if (proc == NOB_INVALID_PROC) return false; - -#ifdef _WIN32 - DWORD result = WaitForSingleObject( - proc, // HANDLE hHandle, - INFINITE // DWORD dwMilliseconds - ); - - if (result == WAIT_FAILED) { - nob_log(NOB_ERROR, "could not wait on child process: %s", nob_win32_error_message(GetLastError())); - return false; - } - - DWORD exit_status; - if (!GetExitCodeProcess(proc, &exit_status)) { - nob_log(NOB_ERROR, "could not get process exit code: %s", nob_win32_error_message(GetLastError())); - return false; - } - - if (exit_status != 0) { - nob_log(NOB_ERROR, "command exited with exit code %lu", exit_status); - return false; - } - - CloseHandle(proc); - - return true; -#else - for (;;) { - int wstatus = 0; - if (waitpid(proc, &wstatus, 0) < 0) { - nob_log(NOB_ERROR, "could not wait on command (pid %d): %s", proc, strerror(errno)); - return false; - } - - if (WIFEXITED(wstatus)) { - int exit_status = WEXITSTATUS(wstatus); - if (exit_status != 0) { - nob_log(NOB_ERROR, "command exited with exit code %d", exit_status); - return false; - } - - break; - } - - if (WIFSIGNALED(wstatus)) { - nob_log(NOB_ERROR, "command process was terminated by signal %d", WTERMSIG(wstatus)); - return false; - } - } - - return true; -#endif -} - -static int nob__proc_wait_async(Nob_Proc proc, int ms) -{ - if (proc == NOB_INVALID_PROC) return false; - -#ifdef _WIN32 - DWORD result = WaitForSingleObject( - proc, // HANDLE hHandle, - ms // DWORD dwMilliseconds - ); - - if (result == WAIT_TIMEOUT) { - return 0; - } - - if (result == WAIT_FAILED) { - nob_log(NOB_ERROR, "could not wait on child process: %s", nob_win32_error_message(GetLastError())); - return -1; - } - - DWORD exit_status; - if (!GetExitCodeProcess(proc, &exit_status)) { - nob_log(NOB_ERROR, "could not get process exit code: %s", nob_win32_error_message(GetLastError())); - return -1; - } - - if (exit_status != 0) { - nob_log(NOB_ERROR, "command exited with exit code %lu", exit_status); - return -1; - } - - CloseHandle(proc); - - return 1; -#else - long ns = ms*1000*1000; - struct timespec duration = { - .tv_sec = ns/(1000*1000*1000), - .tv_nsec = ns%(1000*1000*1000), - }; - - int wstatus = 0; - pid_t pid = waitpid(proc, &wstatus, WNOHANG); - if (pid < 0) { - nob_log(NOB_ERROR, "could not wait on command (pid %d): %s", proc, strerror(errno)); - return -1; - } - - if (pid == 0) { - nanosleep(&duration, NULL); - return 0; - } - - if (WIFEXITED(wstatus)) { - int exit_status = WEXITSTATUS(wstatus); - if (exit_status != 0) { - nob_log(NOB_ERROR, "command exited with exit code %d", exit_status); - return -1; - } - - return 1; - } - - if (WIFSIGNALED(wstatus)) { - nob_log(NOB_ERROR, "command process was terminated by signal %d", WTERMSIG(wstatus)); - return -1; - } - - nanosleep(&duration, NULL); - return 0; -#endif -} - -NOBDEF bool nob_procs_append_with_flush(Nob_Procs *procs, Nob_Proc proc, size_t max_procs_count) -{ - nob_da_append(procs, proc); - - if (procs->count >= max_procs_count) { - if (!nob_procs_flush(procs)) return false; - } - - return true; -} - -NOBDEF bool nob_cmd_run_sync_redirect(Nob_Cmd cmd, Nob_Cmd_Redirect redirect) -{ - Nob_Proc p = nob__cmd_start_process(cmd, redirect.fdin, redirect.fdout, redirect.fderr); - return nob_proc_wait(p); -} - -NOBDEF bool nob_cmd_run_sync(Nob_Cmd cmd) -{ - Nob_Proc p = nob__cmd_start_process(cmd, NULL, NULL, NULL); - return nob_proc_wait(p); -} - -NOBDEF bool nob_cmd_run_sync_and_reset(Nob_Cmd *cmd) -{ - Nob_Proc p = nob__cmd_start_process(*cmd, NULL, NULL, NULL); - cmd->count = 0; - return nob_proc_wait(p); -} - -NOBDEF bool nob_cmd_run_sync_redirect_and_reset(Nob_Cmd *cmd, Nob_Cmd_Redirect redirect) -{ - Nob_Proc p = nob__cmd_start_process(*cmd, redirect.fdin, redirect.fdout, redirect.fderr); - cmd->count = 0; - if (redirect.fdin) { - nob_fd_close(*redirect.fdin); - *redirect.fdin = NOB_INVALID_FD; - } - if (redirect.fdout) { - nob_fd_close(*redirect.fdout); - *redirect.fdout = NOB_INVALID_FD; - } - if (redirect.fderr) { - nob_fd_close(*redirect.fderr); - *redirect.fderr = NOB_INVALID_FD; - } - return nob_proc_wait(p); -} - -static nob_log_handler *nob__log_handler = &nob_default_log_handler; - -NOBDEF void nob_set_log_handler(nob_log_handler *handler) -{ - nob__log_handler = handler; -} - -NOBDEF nob_log_handler *nob_get_log_handler(void) -{ - return nob__log_handler; -} - -NOBDEF void nob_default_log_handler(Nob_Log_Level level, const char *fmt, va_list args) -{ - if (level < nob_minimal_log_level) return; - - switch (level) { - case NOB_INFO: - fprintf(stderr, "[INFO] "); - break; - case NOB_WARNING: - fprintf(stderr, "[WARNING] "); - break; - case NOB_ERROR: - fprintf(stderr, "[ERROR] "); - break; - case NOB_NO_LOGS: return; - default: - NOB_UNREACHABLE("Nob_Log_Level"); - } - - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); -} - -NOBDEF void nob_cancer_log_handler(Nob_Log_Level level, const char *fmt, va_list args) -{ - switch (level) { - case NOB_INFO: - fprintf(stderr, "ℹ️ \x1b[36m[INFO]\x1b[0m "); - break; - case NOB_WARNING: - fprintf(stderr, "⚠️ \x1b[33m[WARNING]\x1b[0m "); - break; - case NOB_ERROR: - fprintf(stderr, "🚨 \x1b[31m[ERROR]\x1b[0m "); - break; - case NOB_NO_LOGS: return; - default: - NOB_UNREACHABLE("Nob_Log_Level"); - } - - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); -} - -NOBDEF void nob_log(Nob_Log_Level level, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - nob__log_handler(level, fmt, args); - va_end(args); -} - -NOBDEF bool nob_dir_entry_open(const char *dir_path, Nob_Dir_Entry *dir) -{ - memset(dir, 0, sizeof(*dir)); -#ifdef _WIN32 - size_t temp_mark = nob_temp_save(); - char *buffer = nob_temp_sprintf("%s\\*", dir_path); - dir->nob__private.win32_hFind = FindFirstFile(buffer, &dir->nob__private.win32_data); - nob_temp_rewind(temp_mark); - - if (dir->nob__private.win32_hFind == INVALID_HANDLE_VALUE) { - nob_log(NOB_ERROR, "Could not open directory %s: %s", dir_path, nob_win32_error_message(GetLastError())); - dir->error = true; - return false; - } -#else - dir->nob__private.posix_dir = opendir(dir_path); - if (dir->nob__private.posix_dir == NULL) { - nob_log(NOB_ERROR, "Could not open directory %s: %s", dir_path, strerror(errno)); - dir->error = true; - return false; - } -#endif // _WIN32 - return true; -} - -NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir) -{ -#ifdef _WIN32 - if (!dir->nob__private.win32_init) { - dir->nob__private.win32_init = true; - dir->name = dir->nob__private.win32_data.cFileName; - return true; - } - - if (!FindNextFile(dir->nob__private.win32_hFind, &dir->nob__private.win32_data)) { - if (GetLastError() == ERROR_NO_MORE_FILES) return false; - nob_log(NOB_ERROR, "Could not read next directory entry: %s", nob_win32_error_message(GetLastError())); - dir->error = true; - return false; - } - dir->name = dir->nob__private.win32_data.cFileName; -#else - errno = 0; - dir->nob__private.posix_ent = readdir(dir->nob__private.posix_dir); - if (dir->nob__private.posix_ent == NULL) { - if (errno == 0) return false; - nob_log(NOB_ERROR, "Could not read next directory entry: %s", strerror(errno)); - dir->error = true; - return false; - } - dir->name = dir->nob__private.posix_ent->d_name; -#endif // _WIN32 - return true; -} - -NOBDEF void nob_dir_entry_close(Nob_Dir_Entry dir) -{ -#ifdef _WIN32 - FindClose(dir.nob__private.win32_hFind); -#else - if (dir.nob__private.posix_dir) closedir(dir.nob__private.posix_dir); -#endif -} - -// On the moment of entering `nob__walk_dir_opt_impl()`, the `file_path` Nob_String_Builder is expected to be NULL-terminated. -// So you can freely pass `file_path->items` to functions that expect NULL-terminated file path. -// On existing `nob__walk_dir_opt_impl()` is expected to restore the original content of `file_path` -bool nob__walk_dir_opt_impl(Nob_String_Builder *file_path, Nob_Walk_Func func, size_t level, bool *stop, Nob_Walk_Dir_Opt opt) -{ - NOB_ASSERT(file_path->count > 0 && "file_path was probably not properly NULL-terminated"); - bool result = true; - - Nob_Dir_Entry dir = {0}; - size_t saved_file_path_count = file_path->count; - Nob_Walk_Action action = NOB_WALK_CONT; - - Nob_File_Type file_type = nob_get_file_type(file_path->items); - if (file_type < 0) nob_return_defer(false); - - // Pre-order walking - if (!opt.post_order) { - if (!func((Nob_Walk_Entry) { - .path = file_path->items, - .type = file_type, - .level = level, - .data = opt.data, - .action = &action, - })) nob_return_defer(false); - switch (action) { - case NOB_WALK_CONT: break; - case NOB_WALK_STOP: *stop = true; // fallthrough - case NOB_WALK_SKIP: nob_return_defer(true); - default: NOB_UNREACHABLE("Nob_Walk_Action"); - } - } - - if (file_type == NOB_FILE_DIRECTORY) { - if (!nob_dir_entry_open(file_path->items, &dir)) nob_return_defer(false); - for (;;) { - // Next entry - if (!nob_dir_entry_next(&dir)) { - if (!dir.error) break; - nob_return_defer(false); - } - - // Ignore . and .. - if (strcmp(dir.name, ".") == 0) continue; - if (strcmp(dir.name, "..") == 0) continue; - - // Prepare the new file_path - file_path->count = saved_file_path_count - 1; -#ifdef _WIN32 - nob_sb_appendf(file_path, "\\%s", dir.name); -#else - nob_sb_appendf(file_path, "/%s", dir.name); -#endif // _WIN32 - nob_sb_append_null(file_path); - - // Recurse - if (!nob__walk_dir_opt_impl(file_path, func, level+1, stop, opt)) nob_return_defer(false); - if (*stop) nob_return_defer(true); - } - file_path->count = saved_file_path_count; - nob_da_last(file_path) = '\0'; - } - - // Post-order walking - if (opt.post_order) { - if (!func((Nob_Walk_Entry) { - .path = file_path->items, - .type = file_type, - .level = level, - .data = opt.data, - .action = &action, - })) nob_return_defer(false); - switch (action) { - case NOB_WALK_CONT: break; - case NOB_WALK_STOP: *stop = true; // fallthrough - case NOB_WALK_SKIP: nob_return_defer(true); - default: NOB_UNREACHABLE("Nob_Walk_Action"); - } - } - -defer: - // Always reset the file_path back to what it was - file_path->count = saved_file_path_count; - nob_da_last(file_path) = '\0'; - - nob_dir_entry_close(dir); - return result; -} - -NOBDEF bool nob_walk_dir_opt(const char *root, Nob_Walk_Func func, Nob_Walk_Dir_Opt opt) -{ - Nob_String_Builder file_path = {0}; - - nob_sb_appendf(&file_path, "%s", root); - nob_sb_append_null(&file_path); - - bool stop = false; - bool ok = nob__walk_dir_opt_impl(&file_path, func, 0, &stop, opt); - free(file_path.items); - return ok; -} - -NOBDEF bool nob_read_entire_dir(const char *parent, Nob_File_Paths *children) -{ - if (strlen(parent) == 0) { - nob_log(NOB_ERROR, "Cannot read empty path"); - return false; - } - bool result = true; - Nob_Dir_Entry dir = {0}; - if (!nob_dir_entry_open(parent, &dir)) nob_return_defer(false); - while (nob_dir_entry_next(&dir)) nob_da_append(children, nob_temp_strdup(dir.name)); - if (dir.error) nob_return_defer(false); -defer: - nob_dir_entry_close(dir); - return result; -} - -NOBDEF bool nob_write_entire_file(const char *path, const void *data, size_t size) -{ - bool result = true; - - const char *buf = NULL; - FILE *f = fopen(path, "wb"); - if (f == NULL) { - nob_log(NOB_ERROR, "Could not open file %s for writing: %s\n", path, strerror(errno)); - nob_return_defer(false); - } - - // len - // v - // aaaaaaaaaa - // ^ - // data - - buf = (const char*)data; - while (size > 0) { - size_t n = fwrite(buf, 1, size, f); - if (ferror(f)) { - nob_log(NOB_ERROR, "Could not write into file %s: %s\n", path, strerror(errno)); - nob_return_defer(false); - } - size -= n; - buf += n; - } - -defer: - if (f) fclose(f); - return result; -} - -NOBDEF Nob_File_Type nob_get_file_type(const char *path) -{ -#ifdef _WIN32 - DWORD attr = GetFileAttributesA(path); - if (attr == INVALID_FILE_ATTRIBUTES) { - nob_log(NOB_ERROR, "Could not get file attributes of %s: %s", path, nob_win32_error_message(GetLastError())); - return -1; - } - - if (attr & FILE_ATTRIBUTE_DIRECTORY) return NOB_FILE_DIRECTORY; - // TODO: detect symlinks on Windows (whatever that means on Windows anyway) - return NOB_FILE_REGULAR; -#else // _WIN32 - struct stat statbuf; - if (lstat(path, &statbuf) < 0) { - nob_log(NOB_ERROR, "Could not get stat of %s: %s", path, strerror(errno)); - return (Nob_File_Type)(-1); - } - - if (S_ISREG(statbuf.st_mode)) return NOB_FILE_REGULAR; - if (S_ISDIR(statbuf.st_mode)) return NOB_FILE_DIRECTORY; - if (S_ISLNK(statbuf.st_mode)) return NOB_FILE_SYMLINK; - return NOB_FILE_OTHER; -#endif // _WIN32 -} - -NOBDEF bool nob_delete_file(const char *path) -{ -#ifndef NOB_NO_ECHO - nob_log(NOB_INFO, "deleting %s", path); -#endif // NOB_NO_ECHO -#ifdef _WIN32 - Nob_File_Type type = nob_get_file_type(path); - switch (type) { - case NOB_FILE_DIRECTORY: - if (!RemoveDirectoryA(path)) { - nob_log(NOB_ERROR, "Could not delete directory %s: %s", path, nob_win32_error_message(GetLastError())); - return false; - } - break; - case NOB_FILE_REGULAR: - case NOB_FILE_SYMLINK: - case NOB_FILE_OTHER: - if (!DeleteFileA(path)) { - nob_log(NOB_ERROR, "Could not delete file %s: %s", path, nob_win32_error_message(GetLastError())); - return false; - } - break; - default: NOB_UNREACHABLE("Nob_File_Type"); - } - return true; -#else - if (remove(path) < 0) { - nob_log(NOB_ERROR, "Could not delete file %s: %s", path, strerror(errno)); - return false; - } - return true; -#endif // _WIN32 -} - -NOBDEF bool nob_copy_directory_recursively(const char *src_path, const char *dst_path) -{ - bool result = true; - Nob_File_Paths children = {0}; - Nob_String_Builder src_sb = {0}; - Nob_String_Builder dst_sb = {0}; - size_t temp_checkpoint = nob_temp_save(); - - Nob_File_Type type = nob_get_file_type(src_path); - if (type < 0) return false; - - switch (type) { - case NOB_FILE_DIRECTORY: { - if (!nob_mkdir_if_not_exists(dst_path)) nob_return_defer(false); - if (!nob_read_entire_dir(src_path, &children)) nob_return_defer(false); - - for (size_t i = 0; i < children.count; ++i) { - if (strcmp(children.items[i], ".") == 0) continue; - if (strcmp(children.items[i], "..") == 0) continue; - - src_sb.count = 0; - nob_sb_append_cstr(&src_sb, src_path); - nob_sb_append_cstr(&src_sb, "/"); - nob_sb_append_cstr(&src_sb, children.items[i]); - nob_sb_append_null(&src_sb); - - dst_sb.count = 0; - nob_sb_append_cstr(&dst_sb, dst_path); - nob_sb_append_cstr(&dst_sb, "/"); - nob_sb_append_cstr(&dst_sb, children.items[i]); - nob_sb_append_null(&dst_sb); - - if (!nob_copy_directory_recursively(src_sb.items, dst_sb.items)) { - nob_return_defer(false); - } - } - } break; - - case NOB_FILE_REGULAR: { - if (!nob_copy_file(src_path, dst_path)) { - nob_return_defer(false); - } - } break; - - case NOB_FILE_SYMLINK: { - nob_log(NOB_WARNING, "TODO: Copying symlinks is not supported yet"); - } break; - - case NOB_FILE_OTHER: { - nob_log(NOB_ERROR, "Unsupported type of file %s", src_path); - nob_return_defer(false); - } break; - - default: NOB_UNREACHABLE("nob_copy_directory_recursively"); - } - -defer: - nob_temp_rewind(temp_checkpoint); - nob_da_free(src_sb); - nob_da_free(dst_sb); - nob_da_free(children); - return result; -} - -NOBDEF char *nob_temp_strdup(const char *cstr) -{ - size_t n = strlen(cstr); - char *result = (char*)nob_temp_alloc(n + 1); - NOB_ASSERT(result != NULL && "Increase NOB_TEMP_CAPACITY"); - memcpy(result, cstr, n); - result[n] = '\0'; - return result; -} - -NOBDEF char *nob_temp_strndup(const char *s, size_t n) -{ - char *r = (char*)nob_temp_alloc(n + 1); - NOB_ASSERT(r != NULL && "Extend the size of the temporary allocator"); - memcpy(r, s, n); - r[n] = '\0'; - return r; -} - -NOBDEF void *nob_temp_alloc(size_t requested_size) -{ - size_t word_size = sizeof(uintptr_t); - size_t size = (requested_size + word_size - 1)/word_size*word_size; - if (nob_temp_size + size > NOB_TEMP_CAPACITY) return NULL; - void *result = &nob_temp[nob_temp_size]; - nob_temp_size += size; - return result; -} - -NOBDEF char *nob_temp_vsprintf(const char *format, va_list ap) -{ - va_list args; - va_copy(args, ap); - int n = vsnprintf(NULL, 0, format, args); - va_end(args); - - NOB_ASSERT(n >= 0); - char *result = (char*)nob_temp_alloc(n + 1); - NOB_ASSERT(result != NULL && "Extend the size of the temporary allocator"); - // TODO: use proper arenas for the temporary allocator; - va_copy(args, ap); - vsnprintf(result, n + 1, format, args); - va_end(args); - - return result; -} - -NOBDEF char *nob_temp_sprintf(const char *format, ...) -{ - va_list args; - va_start(args, format); - char *result = nob_temp_vsprintf(format, args); - va_end(args); - return result; -} - -NOBDEF void nob_temp_reset(void) -{ - nob_temp_size = 0; -} - -NOBDEF size_t nob_temp_save(void) -{ - return nob_temp_size; -} - -NOBDEF void nob_temp_rewind(size_t checkpoint) -{ - nob_temp_size = checkpoint; -} - -NOBDEF const char *nob_temp_sv_to_cstr(Nob_String_View sv) -{ - return nob_temp_strndup(sv.data, sv.count); -} - -NOBDEF int nob_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count) -{ -#ifdef _WIN32 - BOOL bSuccess; - - HANDLE output_path_fd = CreateFile(output_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (output_path_fd == INVALID_HANDLE_VALUE) { - // NOTE: if output does not exist it 100% must be rebuilt - if (GetLastError() == ERROR_FILE_NOT_FOUND) return 1; - nob_log(NOB_ERROR, "Could not open file %s: %s", output_path, nob_win32_error_message(GetLastError())); - return -1; - } - FILETIME output_path_time; - bSuccess = GetFileTime(output_path_fd, NULL, NULL, &output_path_time); - CloseHandle(output_path_fd); - if (!bSuccess) { - nob_log(NOB_ERROR, "Could not get time of %s: %s", output_path, nob_win32_error_message(GetLastError())); - return -1; - } - - for (size_t i = 0; i < input_paths_count; ++i) { - const char *input_path = input_paths[i]; - HANDLE input_path_fd = CreateFile(input_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (input_path_fd == INVALID_HANDLE_VALUE) { - // NOTE: non-existing input is an error cause it is needed for building in the first place - nob_log(NOB_ERROR, "Could not open file %s: %s", input_path, nob_win32_error_message(GetLastError())); - return -1; - } - FILETIME input_path_time; - bSuccess = GetFileTime(input_path_fd, NULL, NULL, &input_path_time); - CloseHandle(input_path_fd); - if (!bSuccess) { - nob_log(NOB_ERROR, "Could not get time of %s: %s", input_path, nob_win32_error_message(GetLastError())); - return -1; - } - - // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild - if (CompareFileTime(&input_path_time, &output_path_time) == 1) return 1; - } - - return 0; -#else - struct stat statbuf = {0}; - - if (stat(output_path, &statbuf) < 0) { - // NOTE: if output does not exist it 100% must be rebuilt - if (errno == ENOENT) return 1; - nob_log(NOB_ERROR, "could not stat %s: %s", output_path, strerror(errno)); - return -1; - } - time_t output_path_time = statbuf.st_mtime; - - for (size_t i = 0; i < input_paths_count; ++i) { - const char *input_path = input_paths[i]; - if (stat(input_path, &statbuf) < 0) { - // NOTE: non-existing input is an error cause it is needed for building in the first place - nob_log(NOB_ERROR, "could not stat %s: %s", input_path, strerror(errno)); - return -1; - } - time_t input_path_time = statbuf.st_mtime; - // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild - if (input_path_time > output_path_time) return 1; - } - - return 0; -#endif -} - -NOBDEF int nob_needs_rebuild1(const char *output_path, const char *input_path) -{ - return nob_needs_rebuild(output_path, &input_path, 1); -} - -NOBDEF const char *nob_path_name(const char *path) -{ -#ifdef _WIN32 - const char *p1 = strrchr(path, '/'); - const char *p2 = strrchr(path, '\\'); - const char *p = (p1 > p2)? p1 : p2; // NULL is ignored if the other search is successful - return p ? p + 1 : path; -#else - const char *p = strrchr(path, '/'); - return p ? p + 1 : path; -#endif // _WIN32 -} - -NOBDEF bool nob_rename(const char *old_path, const char *new_path) -{ -#ifndef NOB_NO_ECHO - nob_log(NOB_INFO, "renaming %s -> %s", old_path, new_path); -#endif // NOB_NO_ECHO -#ifdef _WIN32 - if (!MoveFileEx(old_path, new_path, MOVEFILE_REPLACE_EXISTING)) { - nob_log(NOB_ERROR, "could not rename %s to %s: %s", old_path, new_path, nob_win32_error_message(GetLastError())); - return false; - } -#else - if (rename(old_path, new_path) < 0) { - nob_log(NOB_ERROR, "could not rename %s to %s: %s", old_path, new_path, strerror(errno)); - return false; - } -#endif // _WIN32 - return true; -} - -NOBDEF bool nob_read_entire_file(const char *path, Nob_String_Builder *sb) -{ - bool result = true; - - FILE *f = fopen(path, "rb"); - size_t new_count = 0; - long long m = 0; - if (f == NULL) nob_return_defer(false); - if (fseek(f, 0, SEEK_END) < 0) nob_return_defer(false); -#ifndef _WIN32 - m = ftell(f); -#else - m = _telli64(_fileno(f)); -#endif - if (m < 0) nob_return_defer(false); - if (fseek(f, 0, SEEK_SET) < 0) nob_return_defer(false); - - new_count = sb->count + m; - if (new_count > sb->capacity) { - sb->items = NOB_DECLTYPE_CAST(sb->items)NOB_REALLOC(sb->items, new_count); - NOB_ASSERT(sb->items != NULL && "Buy more RAM lool!!"); - sb->capacity = new_count; - } - - fread(sb->items + sb->count, m, 1, f); - if (ferror(f)) { - // TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case. - nob_return_defer(false); - } - sb->count = new_count; - -defer: - if (!result) nob_log(NOB_ERROR, "Could not read file %s: %s", path, strerror(errno)); - if (f) fclose(f); - return result; -} - -NOBDEF int nob_sb_appendf(Nob_String_Builder *sb, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - int n = vsnprintf(NULL, 0, fmt, args); - va_end(args); - - // NOTE: the new_capacity needs to be +1 because of the null terminator. - // However, further below we increase sb->count by n, not n + 1. - // This is because we don't want the sb to include the null terminator. The user can always sb_append_null() if they want it - nob_da_reserve(sb, sb->count + n + 1); - char *dest = sb->items + sb->count; - va_start(args, fmt); - vsnprintf(dest, n+1, fmt, args); - va_end(args); - - sb->count += n; - - return n; -} - -NOBDEF void nob_sb_pad_align(Nob_String_Builder *sb, size_t size) -{ - size_t rem = sb->count%size; - if (rem == 0) return; - for (size_t i = 0; i < size - rem; ++i) { - nob_da_append(sb, 0); - } -} - -NOBDEF Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim) -{ - size_t i = 0; - while (i < sv->count && sv->data[i] != delim) { - i += 1; - } - - Nob_String_View result = nob_sv_from_parts(sv->data, i); - - if (i < sv->count) { - sv->count -= i + 1; - sv->data += i + 1; - } else { - sv->count -= i; - sv->data += i; - } - - return result; -} - -NOBDEF Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n) -{ - if (n > sv->count) { - n = sv->count; - } - - Nob_String_View result = nob_sv_from_parts(sv->data, n); - - sv->data += n; - sv->count -= n; - - return result; -} - -NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count) -{ - Nob_String_View sv; - sv.count = count; - sv.data = data; - return sv; -} - -NOBDEF Nob_String_View nob_sv_trim_left(Nob_String_View sv) -{ - size_t i = 0; - while (i < sv.count && isspace(sv.data[i])) { - i += 1; - } - - return nob_sv_from_parts(sv.data + i, sv.count - i); -} - -NOBDEF Nob_String_View nob_sv_trim_right(Nob_String_View sv) -{ - size_t i = 0; - while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) { - i += 1; - } - - return nob_sv_from_parts(sv.data, sv.count - i); -} - -NOBDEF Nob_String_View nob_sv_trim(Nob_String_View sv) -{ - return nob_sv_trim_right(nob_sv_trim_left(sv)); -} - -NOBDEF Nob_String_View nob_sv_from_cstr(const char *cstr) -{ - return nob_sv_from_parts(cstr, strlen(cstr)); -} - -NOBDEF bool nob_sv_eq(Nob_String_View a, Nob_String_View b) -{ - if (a.count != b.count) { - return false; - } else { - return memcmp(a.data, b.data, a.count) == 0; - } -} - -NOBDEF bool nob_sv_end_with(Nob_String_View sv, const char *cstr) -{ - size_t cstr_count = strlen(cstr); - if (sv.count >= cstr_count) { - size_t ending_start = sv.count - cstr_count; - Nob_String_View sv_ending = nob_sv_from_parts(sv.data + ending_start, cstr_count); - return nob_sv_eq(sv_ending, nob_sv_from_cstr(cstr)); - } - return false; -} - - -NOBDEF bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix) -{ - if (expected_prefix.count <= sv.count) { - Nob_String_View actual_prefix = nob_sv_from_parts(sv.data, expected_prefix.count); - return nob_sv_eq(expected_prefix, actual_prefix); - } - - return false; -} - -// RETURNS: -// 0 - file does not exists -// 1 - file exists -NOBDEF int nob_file_exists(const char *file_path) -{ -#if _WIN32 - return GetFileAttributesA(file_path) != INVALID_FILE_ATTRIBUTES; -#else - return access(file_path, F_OK) == 0; -#endif -} - -NOBDEF const char *nob_get_current_dir_temp(void) -{ -#ifdef _WIN32 - DWORD nBufferLength = GetCurrentDirectory(0, NULL); - if (nBufferLength == 0) { - nob_log(NOB_ERROR, "could not get current directory: %s", nob_win32_error_message(GetLastError())); - return NULL; - } - - char *buffer = (char*) nob_temp_alloc(nBufferLength); - if (GetCurrentDirectory(nBufferLength, buffer) == 0) { - nob_log(NOB_ERROR, "could not get current directory: %s", nob_win32_error_message(GetLastError())); - return NULL; - } - - return buffer; -#else - char *buffer = (char*) nob_temp_alloc(PATH_MAX); - if (getcwd(buffer, PATH_MAX) == NULL) { - nob_log(NOB_ERROR, "could not get current directory: %s", strerror(errno)); - return NULL; - } - - return buffer; -#endif // _WIN32 -} - -NOBDEF bool nob_set_current_dir(const char *path) -{ -#ifdef _WIN32 - if (!SetCurrentDirectory(path)) { - nob_log(NOB_ERROR, "could not set current directory to %s: %s", path, nob_win32_error_message(GetLastError())); - return false; - } - return true; -#else - if (chdir(path) < 0) { - nob_log(NOB_ERROR, "could not set current directory to %s: %s", path, strerror(errno)); - return false; - } - return true; -#endif // _WIN32 -} - -NOBDEF char *nob_temp_dir_name(const char *path) -{ -#ifndef _WIN32 - // Stolen from the musl's implementation of dirname. - // We are implementing our own one because libc vendors cannot agree on whether dirname(3) - // modifies the path or not. - if (!path || !*path) return nob_temp_strdup("."); - size_t i = strlen(path) - 1; - for (; path[i] == '/'; i--) if (!i) return nob_temp_strdup("/"); - for (; path[i] != '/'; i--) if (!i) return nob_temp_strdup("."); - for (; path[i] == '/'; i--) if (!i) return nob_temp_strdup("/"); - return nob_temp_strndup(path, i + 1); -#else - if (!path) path = ""; // Treating NULL as empty. - char *drive = nob_temp_alloc(_MAX_DRIVE); - char *dir = nob_temp_alloc(_MAX_DIR); - // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/8e46eyt7(v=vs.100) - errno_t ret = _splitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); - NOB_ASSERT(ret == 0); - return nob_temp_sprintf("%s%s", drive, dir); -#endif // _WIN32 -} - -NOBDEF char *nob_temp_file_name(const char *path) -{ -#ifndef _WIN32 - // Stolen from the musl's implementation of dirname. - // We are implementing our own one because libc vendors cannot agree on whether basename(3) - // modifies the path or not. - if (!path || !*path) return nob_temp_strdup("."); - char *s = nob_temp_strdup(path); - size_t i = strlen(s)-1; - for (; i&&s[i]=='/'; i--) s[i] = 0; - for (; i&&s[i-1]!='/'; i--); - return s+i; -#else - if (!path) path = ""; // Treating NULL as empty. - char *fname = nob_temp_alloc(_MAX_FNAME); - char *ext = nob_temp_alloc(_MAX_EXT); - // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/8e46eyt7(v=vs.100) - errno_t ret = _splitpath_s(path, NULL, 0, NULL, 0, fname, _MAX_FNAME, ext, _MAX_EXT); - NOB_ASSERT(ret == 0); - return nob_temp_sprintf("%s%s", fname, ext); -#endif // _WIN32 -} - -NOBDEF char *nob_temp_file_ext(const char *path) -{ -#ifndef _WIN32 - return strrchr(nob_temp_file_name(path), '.'); -#else - if (!path) path = ""; // Treating NULL as empty. - char *ext = nob_temp_alloc(_MAX_EXT); - // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/8e46eyt7(v=vs.100) - errno_t ret = _splitpath_s(path, NULL, 0, NULL, 0, NULL, 0, ext, _MAX_EXT); - NOB_ASSERT(ret == 0); - return ext; -#endif // _WIN32 -} - -NOBDEF char *nob_temp_running_executable_path(void) -{ -#if defined(__linux__) - char buf[4096]; - int length = readlink("/proc/self/exe", buf, NOB_ARRAY_LEN(buf)); - if (length < 0) return nob_temp_strdup(""); - return nob_temp_strndup(buf, length); -#elif defined(_WIN32) - char buf[MAX_PATH]; - int length = GetModuleFileNameA(NULL, buf, MAX_PATH); - return nob_temp_strndup(buf, length); -#elif defined(__APPLE__) - char buf[4096]; - uint32_t size = NOB_ARRAY_LEN(buf); - if (_NSGetExecutablePath(buf, &size) != 0) return nob_temp_strdup(""); - int length = strlen(buf); - return nob_temp_strndup(buf, length); -#elif defined(__FreeBSD__) - char buf[4096]; - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - size_t length = sizeof(buf); - if (sysctl(mib, 4, buf, &length, NULL, 0) < 0) return nob_temp_strdup(""); - return nob_temp_strndup(buf, length); -#elif defined(__HAIKU__) - int cookie = 0; - image_info info; - while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) - if (info.type == B_APP_IMAGE) - break; - return nob_temp_strndup(info.name, strlen(info.name)); -#else - fprintf(stderr, "%s:%d: TODO: nob_temp_running_executable_path is not implemented for this platform\n", __FILE__, __LINE__); - return nob_temp_strdup(""); -#endif -} - -#endif // NOB_IMPLEMENTATION - -#ifndef NOB_STRIP_PREFIX_GUARD_ -#define NOB_STRIP_PREFIX_GUARD_ - // NOTE: The name stripping should be part of the header so it's not accidentally included - // several times. At the same time, it should be at the end of the file so to not create any - // potential conflicts in the NOB_IMPLEMENTATION. The header obviously cannot be at the end - // of the file because NOB_IMPLEMENTATION needs the forward declarations from there. So the - // solution is to split the header into two parts where the name stripping part is at the - // end of the file after the NOB_IMPLEMENTATION. - #ifndef NOB_UNSTRIP_PREFIX - #define TODO NOB_TODO - #define UNREACHABLE NOB_UNREACHABLE - #define UNUSED NOB_UNUSED - #define ARRAY_LEN NOB_ARRAY_LEN - #define ARRAY_GET NOB_ARRAY_GET - #define INFO NOB_INFO - #define WARNING NOB_WARNING - #define ERROR NOB_ERROR - #define NO_LOGS NOB_NO_LOGS - #define Log_Level Nob_Log_Level - #define minimal_log_level nob_minimal_log_level - #define log_handler nob_log_handler - #define set_log_handler nob_set_log_handler - #define get_log_handler nob_get_log_handler - #define default_log_handler nob_default_log_handler - #define cancer_log_handler nob_cancer_log_handler - // NOTE: Name log is already defined in math.h and historically always was the natural logarithmic function. - // So there should be no reason to strip the `nob_` prefix in this specific case. - // #define log nob_log - #define shift nob_shift - #define shift_args nob_shift_args - #define GO_REBUILD_URSELF NOB_GO_REBUILD_URSELF - #define GO_REBUILD_URSELF_PLUS NOB_GO_REBUILD_URSELF_PLUS - #define File_Paths Nob_File_Paths - #define FILE_REGULAR NOB_FILE_REGULAR - #define FILE_DIRECTORY NOB_FILE_DIRECTORY - #define FILE_SYMLINK NOB_FILE_SYMLINK - #define FILE_OTHER NOB_FILE_OTHER - #define File_Type Nob_File_Type - #define mkdir_if_not_exists nob_mkdir_if_not_exists - #define copy_file nob_copy_file - #define copy_directory_recursively nob_copy_directory_recursively - #define read_entire_dir nob_read_entire_dir - #define WALK_CONT NOB_WALK_CONT - #define WALK_SKIP NOB_WALK_SKIP - #define WALK_STOP NOB_WALK_STOP - #define Walk_Action Nob_Walk_Action - #define Walk_Entry Nob_Walk_Entry - #define Walk_Func Nob_Walk_Func - #define Walk_Dir_Opt Nob_Walk_Dir_Opt - #define walk_dir nob_walk_dir - #define walk_dir_opt nob_walk_dir_opt - #define write_entire_file nob_write_entire_file - #define get_file_type nob_get_file_type - #define delete_file nob_delete_file - #define Dir_Entry Nob_Dir_Entry - #define dir_entry_open nob_dir_entry_open - #define dir_entry_next nob_dir_entry_next - #define dir_entry_close nob_dir_entry_close - #define return_defer nob_return_defer - #define da_append nob_da_append - #define da_free nob_da_free - #define da_append_many nob_da_append_many - #define da_resize nob_da_resize - #define da_reserve nob_da_reserve - #define da_last nob_da_last - #define da_remove_unordered nob_da_remove_unordered - #define da_foreach nob_da_foreach - #define fa_append nob_fa_append - #define swap nob_swap - #define String_Builder Nob_String_Builder - #define read_entire_file nob_read_entire_file - #define sb_appendf nob_sb_appendf - #define sb_append_buf nob_sb_append_buf - #define sb_append_cstr nob_sb_append_cstr - #define sb_append_null nob_sb_append_null - #define sb_append nob_sb_append - #define sb_pad_align nob_sb_pad_align - #define sb_free nob_sb_free - #define Proc Nob_Proc - #define INVALID_PROC NOB_INVALID_PROC - #define Fd Nob_Fd - #define Pipe Nob_Pipe - #define pipe_create nob_pipe_create - #define Chain Nob_Chain - #define Chain_Begin_Opt Nob_Chain_Begin_Opt - #define chain_begin nob_chain_begin - #define chain_begin_opt nob_chain_begin_opt - #define Chain_Cmd_Opt Nob_Chain_Cmd_Opt - #define chain_cmd nob_chain_cmd - #define chain_cmd_opt nob_chain_cmd_opt - #define Chain_End_Opt Nob_Chain_End_Opt - #define chain_end nob_chain_end - #define chain_end_opt nob_chain_end_opt - #define INVALID_FD NOB_INVALID_FD - #define fd_open_for_read nob_fd_open_for_read - #define fd_open_for_write nob_fd_open_for_write - #define fd_close nob_fd_close - #define Procs Nob_Procs - #define proc_wait nob_proc_wait - #define procs_wait nob_procs_wait - #define procs_wait_and_reset nob_procs_wait_and_reset - #define procs_append_with_flush nob_procs_append_with_flush - #define procs_flush nob_procs_flush - #define Cmd Nob_Cmd - #define Cmd_Redirect Nob_Cmd_Redirect - #define Cmd_Opt Nob_Cmd_Opt - #define cmd_run_opt nob_cmd_run_opt - #define cmd_run nob_cmd_run - #define cmd_render nob_cmd_render - #define cmd_append nob_cmd_append - #define cmd_extend nob_cmd_extend - #define cmd_free nob_cmd_free - #define cmd_run_async nob_cmd_run_async - #define cmd_run_async_and_reset nob_cmd_run_async_and_reset - #define cmd_run_async_redirect nob_cmd_run_async_redirect - #define cmd_run_async_redirect_and_reset nob_cmd_run_async_redirect_and_reset - #define cmd_run_sync nob_cmd_run_sync - #define cmd_run_sync_and_reset nob_cmd_run_sync_and_reset - #define cmd_run_sync_redirect nob_cmd_run_sync_redirect - #define cmd_run_sync_redirect_and_reset nob_cmd_run_sync_redirect_and_reset - #define temp_strdup nob_temp_strdup - #define temp_strndup nob_temp_strndup - #define temp_alloc nob_temp_alloc - #define temp_sprintf nob_temp_sprintf - #define temp_vsprintf nob_temp_vsprintf - #define temp_reset nob_temp_reset - #define temp_save nob_temp_save - #define temp_rewind nob_temp_rewind - #define path_name nob_path_name - // NOTE: rename(2) is widely known POSIX function. We never wanna collide with it. - // #define rename nob_rename - #define needs_rebuild nob_needs_rebuild - #define needs_rebuild1 nob_needs_rebuild1 - #define file_exists nob_file_exists - #define get_current_dir_temp nob_get_current_dir_temp - #define set_current_dir nob_set_current_dir - #define temp_dir_name nob_temp_dir_name - #define temp_file_name nob_temp_file_name - #define temp_file_ext nob_temp_file_ext - #define temp_running_executable_path nob_temp_running_executable_path - #define String_View Nob_String_View - #define temp_sv_to_cstr nob_temp_sv_to_cstr - #define sv_chop_by_delim nob_sv_chop_by_delim - #define sv_chop_left nob_sv_chop_left - #define sv_trim nob_sv_trim - #define sv_trim_left nob_sv_trim_left - #define sv_trim_right nob_sv_trim_right - #define sv_eq nob_sv_eq - #define sv_starts_with nob_sv_starts_with - #define sv_end_with nob_sv_end_with - #define sv_from_cstr nob_sv_from_cstr - #define sv_from_parts nob_sv_from_parts - #define sb_to_sv nob_sb_to_sv - #define win32_error_message nob_win32_error_message - #define nprocs nob_nprocs - #define nanos_since_unspecified_epoch nob_nanos_since_unspecified_epoch - #define NANOS_PER_SEC NOB_NANOS_PER_SEC - #endif // NOB_STRIP_PREFIX -#endif // NOB_STRIP_PREFIX_GUARD_ - -/* - Revision history: - - 3.2.2 (2026-02-06) Fix read_entire_dir crash on empty path (by @ysoftware) - 3.2.1 (2026-01-29) Fix the implicit declaration error when nob is included as a header (by @ysoftware) - 3.2.0 (2026-01-28) Introduce Chain API - - Nob_Chain - - Nob_Chain_Begin_Opt - - nob_chain_begin() - - nob_chain_begin_opt() - - Nob_Chain_Cmd_Opt - - nob_chain_cmd() - - nob_chain_cmd_opt() - - Nob_Chain_End_Opt - - nob_chain_end() - - nob_chain_end_opt() - Introduce some auxiliary things that were used in Chain API implementation, but might be useful outside of it: - - Nob_Pipe - - nob_pipe_create() - - nob_fa_append() - 3.1.0 (2026-01-22) Make nob_delete_file() be able to delete empty dir on Windows (by @rexim) - Introduce Directory Entry API - similar to POSIX dirent but with names that don't collide - - Nob_Dir_Entry - - nob_dir_entry_open() - - nob_dir_entry_next() - - nob_dir_entry_close() - Rewrite Directory Walking API using Directory Entry API - Introduce .post_order parameter to Nob_Walk_Dir_Opt which walks the directories in post order starting from leaf files - Rewrite nob_read_entire_dir() using Directory Entry API - 3.0.0 (2026-01-13) Improve C++ support (by @rexim) - - Fix various C++ compilers warnings and complains throughout the code. - - Reimplement nob_cmd_append() without taking a pointer to temporary array (some C++ compilers don't like that) - - Make default NOB_REBUILD_URSELF() try to recompile with C++ if __cplusplus macro is defined - Strip prefixes by default (by @rexim) - - Ignore NOB_STRIP_PREFIX macro - - Introduce NOB_UNSTRIP_PREFIX macro - BACKWARD INCOMPATIBLE CHANGE!!! If you had code that intentionally didn't enable NOB_STRIP_PREFIX - because all the names from nob.h were causing too many collisions for you, upgrading to 3.0.0 may break it. - In that case you should go and explicitly enable NOB_UNSTRIP_PREFIX where needed after upgrading. - Add nob_sb_append alias to nob_da_append (by @rexim) - 2.0.1 (2026-01-07) Fix Walk_Entry naming (by @Sinha-Ujjawal) - Using single String Builder in nob__walk_dir_opt_impl (by @Sinha-Ujjawal) - Add tcc to nob_cc_*() and NOB_REBUILD_URSELF() macros (by @vylsaz) - Fix building nob_read_entire_file() with tcc on windows (by @vylsaz) - Fix Y2038 in nob_needs_rebuild() (by @lnvitesace) - 2.0.0 (2026-01-06) Remove minirent.h (by @rexim) - BACKWARD INCOMPATIBLE CHANGE!!! If you were using minirent.h from this library - just use it directly from https://github.com/tsoding/minirent - or consider using the New Directory Walking API. - Introduce New Directory Walking API (by @rexim) - - NOB_WALK_CONT - - NOB_WALK_SKIP - - NOB_WALK_STOP - - Nob_Walk_Action - - Nob_Walk_Entry - - Nob_Walk_Func - - Nob_Walk_Dir_Opt - - nob_walk_dir() - - nob_walk_dir_opt() - Add support for Haiku to nob_temp_running_executable_path() (By @Cephon) - Make nob_file_exists() unfailable (By @rexim) - 1.27.0 (2025-12-30) Add .dont_reset option to cmd_run (by @Israel77) - Fix support for FreeBSD (by @cqundefine) - Strip prefixes from NOB_GO_REBUILD_URSELF and NOB_GO_REBUILD_URSELF_PLUS (by @huwwa) - Add /Fo flag to MSVC version of nob_cc_output() (by @ratchetfreak) - 1.26.0 (2025-12-28) Introduce customizable log handlers (by @rexim) - - Add nob_log_handler - - Add nob_set_log_handler - - Add nob_get_log_handler - - Add nob_default_log_handler - - Add nob_cancer_log_handler - Introduce nob_temp_vsprintf (by @rexim) - Fix compilation error on Windows when NOB_NO_ECHO is enabled (by @mlorenc227) - Do not redefine _CRT_SECURE_NO_WARNINGS if it's already defined (by @vylsaz) - 1.25.1 (2025-11-06) Fix forward declaration of _NSGetExecutablePath on MacOS (by @agss0) - 1.25.0 (2025-10-25) - Add nob_sb_pad_align() - - Add nob_swap() - - Add nob_temp_strndup() - - Add nob_temp_dir_name() - - Add nob_temp_file_name() - - Add nob_temp_file_ext() - - Add nob_temp_running_executable_path() - 1.24.0 (2025-10-23) Introduce NOB_NO_ECHO macro flag (@rexim) - 1.23.0 (2025-08-22) Introduce new API for running commands (by @rexim, @programmerlexi, @0x152a) - - Add nob_cmd_run() - - Add nob_cmd_run_opt() - - Add struct Nob_Cmd_Opt - - Add nob_procs_flush() - - Add nob_nprocs() - Deprecate old API for running commands. (by @rexim) - We do not plan to delete this API any time, but we believe that the new one is more convenient. - - Deprecate struct Nob_Cmd_Redirect{} (it's not explicitly marked with NOB_DEPRECATED, but functions that use it are) - - Turn nob_cmd_run_async() into a function (otherwise it's not deprecatable with NOB_DEPRECATED) - - Deprecate nob_cmd_run_async() - - Deprecate nob_cmd_run_async_and_reset() - - Deprecate nob_cmd_run_async_redirect() - - Deprecate nob_cmd_run_async_redirect_and_reset() - - Deprecate nob_cmd_run_sync() - - Deprecate nob_cmd_run_sync_and_reset() - - Deprecate nob_cmd_run_sync_redirect() - - Deprecate nob_cmd_run_sync_redirect_and_reset() - - Deprecate nob_procs_append_with_flush() - - Deprecate nob_procs_wait_and_reset() - Introduce deprecation mechanism (by @yuI4140, @rexim) - By default, deprecation warnings are not reported. You have to #define NOB_WARN_DEPRECATED to enable them. - - Add NOB_DEPRECATED() - - Add NOB_WARN_DEPRECATED - Add NOB_DECLTYPE_CAST() for C++-compatible casting of allocation results (by @rexim) - Introduce basic performance measuring mechanism (By @mikmart) - - Add nob_nanos_since_unspecified_epoch() - - Add NOB_NANOS_PER_SEC - 1.22.0 (2025-08-12) Add NOBDEF macro to the beginning of function declarations (by @minefreak19) - Add more flags to MSVC nob_cc_flags() (by @PieVieRo) - 1.21.0 (2025-08-11) Add NOB_NO_MINIRENT guard for "minirent.h" (by @fietec) - 1.20.9 (2025-08-11) Fix warnings on Windows: Define _CRT_SECURE_NO_WARNINGS, Rename mkdir to _mkdir (by @OetkenPurveyorOfCode) - 1.20.8 (2025-08-11) Fix the bug with nob_get_file_type() not identifying symlinks correctly on POSIX (By @samuellieberman) - 1.20.7 (2025-07-29) Align nob_temp_alloc() allocations by the word size (By @rexim) - 1.20.6 (2025-05-16) Never strip nob_* suffix from nob_rename (By @rexim) - 1.20.5 (2025-05-16) NOB_PRINTF_FORMAT() support for MinGW (By @KillerxDBr) - 1.20.4 (2025-05-16) More reliable rendering of the Windows command (By @vylsaz) - 1.20.3 (2025-05-16) Add check for __clang__ along with _MSC_VER checks (By @nashiora) - 1.20.2 (2025-04-24) Report the program name that failed to start up in nob_cmd_run_async_redirect() (By @rexim) - 1.20.1 (2025-04-16) Use vsnprintf() in nob_sb_appendf() instead of vsprintf() (By @LainLayer) - 1.20.0 (2025-04-16) Introduce nob_cc(), nob_cc_flags(), nob_cc_inputs(), nob_cc_output() macros (By @rexim) - 1.19.0 (2025-03-25) Add nob_procs_append_with_flush() (By @rexim and @anion155) - 1.18.0 (2025-03-24) Add nob_da_foreach() (By @rexim) - Allow file sizes greater than 2GB to be read on windows (By @satchelfrost and @KillerxDBr) - Fix nob_fd_open_for_write behaviour on windows so it truncates the opened files (By @twixuss) - 1.17.0 (2025-03-16) Factor out nob_da_reserve() (By @rexim) - Add nob_sb_appendf() (By @angelcaru) - 1.16.1 (2025-03-16) Make nob_da_resize() exponentially grow capacity similar to no_da_append_many() - 1.16.0 (2025-03-16) Introduce NOB_PRINTF_FORMAT - 1.15.1 (2025-03-16) Make nob.h compilable in gcc/clang with -std=c99 on POSIX. This includes: - not using strsignal() - using S_IS* stat macros instead of S_IF* flags - 1.15.0 (2025-03-03) Add nob_sv_chop_left() - 1.14.1 (2025-03-02) Add NOB_EXPERIMENTAL_DELETE_OLD flag that enables deletion of nob.old in Go Rebuild Urself™ Technology - 1.14.0 (2025-02-17) Add nob_da_last() - Add nob_da_remove_unordered() - 1.13.1 (2025-02-17) Fix segfault in nob_delete_file() (By @SileNce5k) - 1.13.0 (2025-02-11) Add nob_da_resize() (By @satchelfrost) - 1.12.0 (2025-02-04) Add nob_delete_file() - Add nob_sv_start_with() - 1.11.0 (2025-02-04) Add NOB_GO_REBUILD_URSELF_PLUS() (By @rexim) - 1.10.0 (2025-02-04) Make NOB_ASSERT, NOB_REALLOC, and NOB_FREE redefinable (By @OleksiiBulba) - 1.9.1 (2025-02-04) Fix signature of nob_get_current_dir_temp() (By @julianstoerig) - 1.9.0 (2024-11-06) Add Nob_Cmd_Redirect mechanism (By @rexim) - Add nob_path_name() (By @0dminnimda) - 1.8.0 (2024-11-03) Add nob_cmd_extend() (By @0dminnimda) - 1.7.0 (2024-11-03) Add nob_win32_error_message and NOB_WIN32_ERR_MSG_SIZE (By @KillerxDBr) - 1.6.0 (2024-10-27) Add nob_cmd_run_sync_and_reset() - Add nob_sb_to_sv() - Add nob_procs_wait_and_reset() - 1.5.1 (2024-10-25) Include limits.h for Linux musl libc (by @pgalkin) - 1.5.0 (2024-10-23) Add nob_get_current_dir_temp() - Add nob_set_current_dir() - 1.4.0 (2024-10-21) Fix UX issues with NOB_GO_REBUILD_URSELF on Windows when you call nob without the .exe extension (By @pgalkin) - Add nob_sv_end_with (By @pgalkin) - 1.3.2 (2024-10-21) Fix unreachable error in nob_log on passing NOB_NO_LOGS - 1.3.1 (2024-10-21) Fix redeclaration error for minimal_log_level (By @KillerxDBr) - 1.3.0 (2024-10-17) Add NOB_UNREACHABLE - 1.2.2 (2024-10-16) Fix compilation of nob_cmd_run_sync_and_reset on Windows (By @KillerxDBr) - 1.2.1 (2024-10-16) Add a separate include guard for NOB_STRIP_PREFIX. - 1.2.0 (2024-10-15) Make NOB_DA_INIT_CAP redefinable - Add NOB_STRIP_PREFIX which strips off nob_* prefix from all the user facing names - Add NOB_UNUSED macro - Add NOB_TODO macro - Add nob_sv_trim_left and nob_sv_trim_right declarations to the header part - 1.1.1 (2024-10-15) Remove forward declaration for is_path1_modified_after_path2 - 1.1.0 (2024-10-15) nob_minimal_log_level - nob_cmd_run_sync_and_reset - 1.0.0 (2024-10-15) first release based on https://github.com/tsoding/musializer/blob/4ac7cce9874bc19e02d8c160c8c6229de8919401/nob.h -*/ - -/* - Version Conventions: - - We are following https://semver.org/ so the version has a format MAJOR.MINOR.PATCH: - - Modifying comments does not update the version. - - PATCH is incremented in case of a bug fix or refactoring without touching the API. - - MINOR is incremented when new functions and/or types are added in a way that does - not break any existing user code. We want to do this in the majority of the situation. - If we want to delete a certain function or type in favor of another one we should - just add the new function/type and deprecate the old one in a backward compatible way - and let them co-exist for a while. - - MAJOR update should be just a periodic cleanup of the DEPRECATED functions and types - without really modifying any existing functionality. - - Breaking backward compatibility in a MINOR release should be considered a bug and - should be promptly fixed in the next PATCH release. - - API conventions: - - - All the user facing names should be prefixed with `nob_`, `NOB_`, or `Nob_` depending on the case. - - The prefixes of non-redefinable names should be stripped in NOB_STRIP_PREFIX_GUARD_ section, - unless explicitly stated otherwise like in case of nob_log() or nob_rename(). - - Internal (private) names should be prefixed with `nob__` (double underscore). The user code is discouraged - from using such names since they are allowed to be broken in a backward incompatible way even in PATCH - releases. (This is why they are internal) - - If a public macro uses an private function internally such function must be forward declared in the NOB_H_ - section. -*/ - -/* - ------------------------------------------------------------------------------ - This software is available under 2 licenses -- choose whichever you prefer. - ------------------------------------------------------------------------------ - ALTERNATIVE A - MIT License - Copyright (c) 2024 Alexey Kutepov - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - ------------------------------------------------------------------------------ - ALTERNATIVE B - Public Domain (www.unlicense.org) - This is free and unencumbered software released into the public domain. - Anyone is free to copy, modify, publish, use, compile, sell, or distribute this - software, either in source code form or as a compiled binary, for any purpose, - commercial or non-commercial, and by any means. - In jurisdictions that recognize copyright laws, the author or authors of this - software dedicate any and all copyright interest in the software to the public - domain. We make this dedication for the benefit of the public at large and to - the detriment of our heirs and successors. We intend this dedication to be an - overt act of relinquishment in perpetuity of all present and future rights to - this software under copyright law. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------------------------------------------------------------------------------ -*/ diff --git a/src/.build/.added_strings_w2.jai b/src/.build/.added_strings_w2.jai new file mode 100644 index 0000000..ddb6f2d --- /dev/null +++ b/src/.build/.added_strings_w2.jai @@ -0,0 +1,6 @@ +// Workspace: Target Program + +// +// String added via add_build_string() from c:/Users/mta/.vscode-oss/extensions/apparentlystudio.jails-0.2.0-universal/out/metaprogram/jails_diagnostics.jai:19. +// +JAILS_DIAGNOSTICS_BUILD :: true; diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 9083830..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "platform/platform.h" -#include "renderer/renderer.h" -#include "imgui.h" -#include "imgui_internal.h" - -enum MenuCmd { - MENU_NONE = 0, - MENU_FILE_NEW, - MENU_FILE_OPEN, - MENU_FILE_SAVE, - MENU_FILE_SAVE_AS, - MENU_FILE_EXIT, - MENU_IMPORT_AUDIO, - MENU_IMPORT_MIDI, - MENU_VIEW_BROWSER, - MENU_VIEW_PROPERTIES, - MENU_VIEW_LOG, - MENU_VIEW_DEMO, -}; - -static void setup_menus(PlatformWindow *window) -{ - PlatformMenuItem file_items[] = { - { "New", MENU_FILE_NEW }, - { "Open...", MENU_FILE_OPEN }, - { "Save", MENU_FILE_SAVE }, - { "Save As...", MENU_FILE_SAVE_AS }, - { nullptr, 0 }, - { "Exit", MENU_FILE_EXIT }, - }; - - PlatformMenuItem import_items[] = { - { "Audio...", MENU_IMPORT_AUDIO }, - { "MIDI...", MENU_IMPORT_MIDI }, - }; - - PlatformMenuItem view_items[] = { - { "Browser", MENU_VIEW_BROWSER }, - { "Properties", MENU_VIEW_PROPERTIES }, - { "Log", MENU_VIEW_LOG }, - { nullptr, 0 }, - { "Demo", MENU_VIEW_DEMO }, - }; - - PlatformMenu menus[] = { - { "File", file_items, sizeof(file_items) / sizeof(file_items[0]) }, - { "Import", import_items, sizeof(import_items) / sizeof(import_items[0]) }, - { "View", view_items, sizeof(view_items) / sizeof(view_items[0]) }, - }; - - platform_set_menu(window, menus, sizeof(menus) / sizeof(menus[0])); -} - -static void setup_theme() -{ - ImGuiIO &io = ImGui::GetIO(); - - // Load Segoe UI from Windows system fonts - ImFontConfig font_cfg = {}; - font_cfg.OversampleH = 2; - font_cfg.OversampleV = 1; - font_cfg.PixelSnapH = true; - io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 15.0f, &font_cfg); - - // DAW-style dark theme - ImGuiStyle &s = ImGui::GetStyle(); - - // Geometry - s.WindowPadding = ImVec2(8, 8); - s.FramePadding = ImVec2(6, 4); - s.ItemSpacing = ImVec2(8, 4); - s.ItemInnerSpacing = ImVec2(4, 4); - s.ScrollbarSize = 12.0f; - s.GrabMinSize = 8.0f; - s.WindowBorderSize = 1.0f; - s.FrameBorderSize = 0.0f; - s.TabBorderSize = 0.0f; - s.WindowRounding = 2.0f; - s.FrameRounding = 2.0f; - s.GrabRounding = 2.0f; - s.TabRounding = 2.0f; - s.ScrollbarRounding = 2.0f; - - ImVec4 *c = s.Colors; - - // Backgrounds - c[ImGuiCol_WindowBg] = ImVec4(0.12f, 0.12f, 0.13f, 1.00f); - c[ImGuiCol_ChildBg] = ImVec4(0.12f, 0.12f, 0.13f, 1.00f); - c[ImGuiCol_PopupBg] = ImVec4(0.15f, 0.15f, 0.16f, 1.00f); - - // Borders - c[ImGuiCol_Border] = ImVec4(0.22f, 0.22f, 0.24f, 1.00f); - c[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - - // Text - c[ImGuiCol_Text] = ImVec4(0.88f, 0.88f, 0.88f, 1.00f); - c[ImGuiCol_TextDisabled] = ImVec4(0.44f, 0.44f, 0.44f, 1.00f); - - // Headers (collapsing headers, menu bar items) - c[ImGuiCol_Header] = ImVec4(0.20f, 0.20f, 0.22f, 1.00f); - c[ImGuiCol_HeaderHovered] = ImVec4(0.28f, 0.28f, 0.30f, 1.00f); - c[ImGuiCol_HeaderActive] = ImVec4(0.24f, 0.24f, 0.26f, 1.00f); - - // Buttons - c[ImGuiCol_Button] = ImVec4(0.22f, 0.22f, 0.24f, 1.00f); - c[ImGuiCol_ButtonHovered] = ImVec4(0.30f, 0.30f, 0.33f, 1.00f); - c[ImGuiCol_ButtonActive] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); - - // Frame backgrounds (inputs, checkboxes, sliders) - c[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.16f, 0.17f, 1.00f); - c[ImGuiCol_FrameBgHovered] = ImVec4(0.20f, 0.20f, 0.22f, 1.00f); - c[ImGuiCol_FrameBgActive] = ImVec4(0.18f, 0.18f, 0.20f, 1.00f); - - // Tabs - c[ImGuiCol_Tab] = ImVec4(0.16f, 0.16f, 0.17f, 1.00f); - c[ImGuiCol_TabHovered] = ImVec4(0.28f, 0.28f, 0.30f, 1.00f); - c[ImGuiCol_TabSelected] = ImVec4(0.20f, 0.20f, 0.22f, 1.00f); - c[ImGuiCol_TabSelectedOverline] = ImVec4(0.34f, 0.54f, 0.69f, 1.00f); - c[ImGuiCol_TabDimmed] = ImVec4(0.12f, 0.12f, 0.13f, 1.00f); - c[ImGuiCol_TabDimmedSelected] = ImVec4(0.16f, 0.16f, 0.17f, 1.00f); - - // Title bar - c[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.10f, 0.11f, 1.00f); - c[ImGuiCol_TitleBgActive] = ImVec4(0.13f, 0.13f, 0.14f, 1.00f); - c[ImGuiCol_TitleBgCollapsed] = ImVec4(0.10f, 0.10f, 0.11f, 1.00f); - - // Scrollbar - c[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.10f, 0.11f, 1.00f); - c[ImGuiCol_ScrollbarGrab] = ImVec4(0.24f, 0.24f, 0.26f, 1.00f); - c[ImGuiCol_ScrollbarGrabHovered]= ImVec4(0.30f, 0.30f, 0.33f, 1.00f); - c[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.34f, 0.34f, 0.37f, 1.00f); - - // Slider grab - c[ImGuiCol_SliderGrab] = ImVec4(0.34f, 0.54f, 0.69f, 1.00f); - c[ImGuiCol_SliderGrabActive] = ImVec4(0.40f, 0.60f, 0.75f, 1.00f); - - // Checkmark, accent - c[ImGuiCol_CheckMark] = ImVec4(0.34f, 0.54f, 0.69f, 1.00f); - - // Separator - c[ImGuiCol_Separator] = ImVec4(0.22f, 0.22f, 0.24f, 1.00f); - c[ImGuiCol_SeparatorHovered] = ImVec4(0.34f, 0.54f, 0.69f, 1.00f); - c[ImGuiCol_SeparatorActive] = ImVec4(0.34f, 0.54f, 0.69f, 1.00f); - - // Resize grip - c[ImGuiCol_ResizeGrip] = ImVec4(0.22f, 0.22f, 0.24f, 0.50f); - c[ImGuiCol_ResizeGripHovered] = ImVec4(0.34f, 0.54f, 0.69f, 0.67f); - c[ImGuiCol_ResizeGripActive] = ImVec4(0.34f, 0.54f, 0.69f, 0.95f); - - // Docking - c[ImGuiCol_DockingPreview] = ImVec4(0.34f, 0.54f, 0.69f, 0.70f); - c[ImGuiCol_DockingEmptyBg] = ImVec4(0.10f, 0.10f, 0.11f, 1.00f); - - // Menu bar - c[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.15f, 1.00f); -} - -static void build_default_layout(ImGuiID dockspace_id) -{ - ImGui::DockBuilderRemoveNode(dockspace_id); - ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace); - ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->Size); - - ImGuiID center = dockspace_id; - ImGuiID left = ImGui::DockBuilderSplitNode(center, ImGuiDir_Left, 0.15f, nullptr, ¢er); - ImGuiID right = ImGui::DockBuilderSplitNode(center, ImGuiDir_Right, 0.20f, nullptr, ¢er); - ImGuiID bottom = ImGui::DockBuilderSplitNode(center, ImGuiDir_Down, 0.25f, nullptr, ¢er); - - ImGui::DockBuilderDockWindow("Browser", left); - ImGui::DockBuilderDockWindow("Main", center); - ImGui::DockBuilderDockWindow("Properties", right); - ImGui::DockBuilderDockWindow("Log", bottom); - - ImGui::DockBuilderFinish(dockspace_id); -} - -int main(int argc, char **argv) -{ - (void)argc; - (void)argv; - - PlatformWindowDesc window_desc = {}; - PlatformWindow *window = platform_create_window(&window_desc); - if (!window) - return 1; - - int32_t w, h; - platform_get_size(window, &w, &h); - - RendererDesc renderer_desc = {}; - renderer_desc.window_handle = platform_get_native_handle(window); - renderer_desc.width = w; - renderer_desc.height = h; - Renderer *renderer = renderer_create(&renderer_desc); - if (!renderer) { - platform_destroy_window(window); - return 1; - } - - setup_theme(); - setup_menus(window); - - int32_t last_w = w, last_h = h; - bool show_demo = true; - bool show_browser = true; - bool show_props = true; - bool show_log = true; - bool first_frame = true; - - while (platform_poll_events(window)) { - int32_t menu_cmd = platform_poll_menu_command(window); - switch (menu_cmd) { - case MENU_FILE_EXIT: platform_destroy_window(window); return 0; - case MENU_VIEW_BROWSER: show_browser = !show_browser; break; - case MENU_VIEW_PROPERTIES:show_props = !show_props; break; - case MENU_VIEW_LOG: show_log = !show_log; break; - case MENU_VIEW_DEMO: show_demo = !show_demo; break; - default: break; - } - platform_get_size(window, &w, &h); - if (w != last_w || h != last_h) { - renderer_resize(renderer, w, h); - last_w = w; - last_h = h; - } - - if (!renderer_begin_frame(renderer)) - continue; - - // Full-window dockspace - ImGuiID dockspace_id = ImGui::GetID("MainDockSpace"); - ImGui::DockSpaceOverViewport(dockspace_id, ImGui::GetMainViewport()); - - if (first_frame) { - build_default_layout(dockspace_id); - first_frame = false; - } - - // Left panel - if (show_browser) { - ImGui::Begin("Browser", &show_browser); - ImGui::Text("Instruments"); - ImGui::Separator(); - ImGui::End(); - } - - // Main content - ImGui::Begin("Main"); - ImGui::Text("Main content area"); - ImGui::End(); - - // Right panel - if (show_props) { - ImGui::Begin("Properties", &show_props); - ImGui::Text("Details"); - ImGui::Separator(); - ImGui::End(); - } - - // Bottom panel - if (show_log) { - ImGui::Begin("Log", &show_log); - ImGui::Text("Output / Log"); - ImGui::Separator(); - ImGui::End(); - } - - // Demo window - if (show_demo) - ImGui::ShowDemoWindow(&show_demo); - - renderer_end_frame(renderer); - } - - renderer_destroy(renderer); - platform_destroy_window(window); - return 0; -} diff --git a/src/main.jai b/src/main.jai new file mode 100644 index 0000000..ba84775 --- /dev/null +++ b/src/main.jai @@ -0,0 +1,264 @@ +// autosample — Jai + DX12 + ImGui (docking) DAW-style application + +#import "Basic"; +#import "Windows"; +#import "Windows_Utf8"; +#import "d3d12"()(INCLUDE_DEBUG_BINDINGS = true); +dxgi :: #import "dxgi"; + +ImGui :: #import "ImGui"; + +Window :: #import "Window_Creation"; +Input :: #import "Input"; + +#load "platform/platform.jai"; +#load "renderer/renderer.jai"; + +// ------------------------------------------------------------------- +// Menu command IDs +// ------------------------------------------------------------------- +MENU_FILE_NEW :: 1; +MENU_FILE_OPEN :: 2; +MENU_FILE_SAVE :: 3; +MENU_FILE_SAVE_AS :: 4; +MENU_FILE_EXIT :: 5; +MENU_IMPORT_AUDIO :: 6; +MENU_IMPORT_MIDI :: 7; +MENU_VIEW_BROWSER :: 8; +MENU_VIEW_PROPERTIES :: 9; +MENU_VIEW_LOG :: 10; +MENU_VIEW_DEMO :: 11; + +// ------------------------------------------------------------------- +// DAW Theme +// ------------------------------------------------------------------- +setup_theme :: () { + io := ImGui.GetIO(); + ImGui.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 15.0); + + s := ImGui.GetStyle(); + s.WindowPadding = .{8, 8}; + s.FramePadding = .{6, 4}; + s.ItemSpacing = .{8, 4}; + s.ItemInnerSpacing = .{4, 4}; + s.ScrollbarSize = 12.0; + s.GrabMinSize = 8.0; + s.WindowBorderSize = 1.0; + s.FrameBorderSize = 0.0; + s.TabBorderSize = 0.0; + s.WindowRounding = 2.0; + s.FrameRounding = 2.0; + s.GrabRounding = 2.0; + s.TabRounding = 2.0; + s.ScrollbarRounding = 2.0; + + // Backgrounds + s.Colors[ImGui.Col.WindowBg] = .{0.12, 0.12, 0.13, 1.00}; + s.Colors[ImGui.Col.ChildBg] = .{0.12, 0.12, 0.13, 1.00}; + s.Colors[ImGui.Col.PopupBg] = .{0.15, 0.15, 0.16, 1.00}; + + // Borders + s.Colors[ImGui.Col.Border] = .{0.22, 0.22, 0.24, 1.00}; + s.Colors[ImGui.Col.BorderShadow] = .{0.00, 0.00, 0.00, 0.00}; + + // Text + s.Colors[ImGui.Col.Text] = .{0.88, 0.88, 0.88, 1.00}; + s.Colors[ImGui.Col.TextDisabled] = .{0.44, 0.44, 0.44, 1.00}; + + // Headers + s.Colors[ImGui.Col.Header] = .{0.20, 0.20, 0.22, 1.00}; + s.Colors[ImGui.Col.HeaderHovered] = .{0.28, 0.28, 0.30, 1.00}; + s.Colors[ImGui.Col.HeaderActive] = .{0.24, 0.24, 0.26, 1.00}; + + // Buttons + s.Colors[ImGui.Col.Button] = .{0.22, 0.22, 0.24, 1.00}; + s.Colors[ImGui.Col.ButtonHovered] = .{0.30, 0.30, 0.33, 1.00}; + s.Colors[ImGui.Col.ButtonActive] = .{0.26, 0.26, 0.28, 1.00}; + + // Frame backgrounds + s.Colors[ImGui.Col.FrameBg] = .{0.16, 0.16, 0.17, 1.00}; + s.Colors[ImGui.Col.FrameBgHovered] = .{0.20, 0.20, 0.22, 1.00}; + s.Colors[ImGui.Col.FrameBgActive] = .{0.18, 0.18, 0.20, 1.00}; + + // Tabs + s.Colors[ImGui.Col.Tab] = .{0.16, 0.16, 0.17, 1.00}; + s.Colors[ImGui.Col.TabHovered] = .{0.28, 0.28, 0.30, 1.00}; + s.Colors[ImGui.Col.TabSelected] = .{0.20, 0.20, 0.22, 1.00}; + s.Colors[ImGui.Col.TabSelectedOverline] = .{0.34, 0.54, 0.69, 1.00}; + s.Colors[ImGui.Col.TabDimmed] = .{0.12, 0.12, 0.13, 1.00}; + s.Colors[ImGui.Col.TabDimmedSelected] = .{0.16, 0.16, 0.17, 1.00}; + + // Title bar + s.Colors[ImGui.Col.TitleBg] = .{0.10, 0.10, 0.11, 1.00}; + s.Colors[ImGui.Col.TitleBgActive] = .{0.13, 0.13, 0.14, 1.00}; + s.Colors[ImGui.Col.TitleBgCollapsed] = .{0.10, 0.10, 0.11, 1.00}; + + // Scrollbar + s.Colors[ImGui.Col.ScrollbarBg] = .{0.10, 0.10, 0.11, 1.00}; + s.Colors[ImGui.Col.ScrollbarGrab] = .{0.24, 0.24, 0.26, 1.00}; + s.Colors[ImGui.Col.ScrollbarGrabHovered]= .{0.30, 0.30, 0.33, 1.00}; + s.Colors[ImGui.Col.ScrollbarGrabActive] = .{0.34, 0.34, 0.37, 1.00}; + + // Slider grab + s.Colors[ImGui.Col.SliderGrab] = .{0.34, 0.54, 0.69, 1.00}; + s.Colors[ImGui.Col.SliderGrabActive] = .{0.40, 0.60, 0.75, 1.00}; + + // Checkmark + s.Colors[ImGui.Col.CheckMark] = .{0.34, 0.54, 0.69, 1.00}; + + // Separator + s.Colors[ImGui.Col.Separator] = .{0.22, 0.22, 0.24, 1.00}; + s.Colors[ImGui.Col.SeparatorHovered] = .{0.34, 0.54, 0.69, 1.00}; + s.Colors[ImGui.Col.SeparatorActive] = .{0.34, 0.54, 0.69, 1.00}; + + // Resize grip + s.Colors[ImGui.Col.ResizeGrip] = .{0.22, 0.22, 0.24, 0.50}; + s.Colors[ImGui.Col.ResizeGripHovered] = .{0.34, 0.54, 0.69, 0.67}; + s.Colors[ImGui.Col.ResizeGripActive] = .{0.34, 0.54, 0.69, 0.95}; + + // Docking + s.Colors[ImGui.Col.DockingPreview] = .{0.34, 0.54, 0.69, 0.70}; + s.Colors[ImGui.Col.DockingEmptyBg] = .{0.10, 0.10, 0.11, 1.00}; + + // Menu bar + s.Colors[ImGui.Col.MenuBarBg] = .{0.14, 0.14, 0.15, 1.00}; +} + +// ------------------------------------------------------------------- +// Docking Layout +// ------------------------------------------------------------------- +build_default_layout :: (dockspace_id: ImGui.ID) { + viewport := ImGui.GetMainViewport(); + + ImGui.DockBuilderRemoveNode(dockspace_id); + ImGui.DockBuilderAddNode(dockspace_id, xx ImGui.DockNodeFlags.None | xx 1 << 5); // ImGuiDockNodeFlags_DockSpace = 1 << 5 (internal flag) + ImGui.DockBuilderSetNodeSize(dockspace_id, viewport.Size); + + center := dockspace_id; + left: ImGui.ID; + right: ImGui.ID; + bottom: ImGui.ID; + + ImGui.DockBuilderSplitNode(center, xx ImGui.Dir.Left, 0.15, *left, *center); + ImGui.DockBuilderSplitNode(center, xx ImGui.Dir.Right, 0.20, *right, *center); + ImGui.DockBuilderSplitNode(center, xx ImGui.Dir.Down, 0.25, *bottom, *center); + + ImGui.DockBuilderDockWindow("Browser", left); + ImGui.DockBuilderDockWindow("Main", center); + ImGui.DockBuilderDockWindow("Properties", right); + ImGui.DockBuilderDockWindow("Log", bottom); + + ImGui.DockBuilderFinish(dockspace_id); +} + +// ------------------------------------------------------------------- +// Main +// ------------------------------------------------------------------- +main :: () { + if !platform_init() return; + + // Init DX12 + if !create_device() { print("create_device failed\n"); return; } + if !create_command_queue() { print("create_command_queue failed\n"); return; } + if !create_descriptor_heaps() { print("create_descriptor_heaps failed\n"); return; } + if !create_frame_resources() { print("create_frame_resources failed\n"); return; } + if !create_swap_chain() { print("create_swap_chain failed\n"); return; } + create_render_targets(); + + // Init ImGui + init_imgui(); + setup_theme(); + setup_menus(); + + // Application state + show_demo := true; + show_browser := true; + show_props := true; + show_log := true; + first_frame := true; + last_w := w_width; + last_h := w_height; + + // Main loop + quit := false; + while !quit { + msg: MSG; + while PeekMessageW(*msg, null, 0, 0, PM_REMOVE) != 0 { + TranslateMessage(*msg); + DispatchMessageW(*msg); + if msg.message == WM_QUIT then quit = true; + } + if quit break; + + // Handle menu commands + if pending_menu_cmd != 0 { + cmd := pending_menu_cmd; + pending_menu_cmd = 0; + if cmd == { + case MENU_FILE_EXIT; quit = true; + case MENU_VIEW_BROWSER; show_browser = !show_browser; + case MENU_VIEW_PROPERTIES; show_props = !show_props; + case MENU_VIEW_LOG; show_log = !show_log; + case MENU_VIEW_DEMO; show_demo = !show_demo; + } + } + if quit break; + + // Handle resize + if w_width != last_w || w_height != last_h { + resize(w_width, w_height); + last_w = w_width; + last_h = w_height; + } + + if !begin_frame() continue; + + // Full-window dockspace + dockspace_id := ImGui.GetID("MainDockSpace"); + ImGui.DockSpaceOverViewport(dockspace_id, ImGui.GetMainViewport()); + + if first_frame { + build_default_layout(dockspace_id); + first_frame = false; + } + + // Left panel + if show_browser { + ImGui.Begin("Browser", *show_browser); + ImGui.Text("Instruments"); + ImGui.Separator(); + ImGui.End(); + } + + // Main content + ImGui.Begin("Main"); + ImGui.Text("Main content area"); + ImGui.End(); + + // Right panel + if show_props { + ImGui.Begin("Properties", *show_props); + ImGui.Text("Details"); + ImGui.Separator(); + ImGui.End(); + } + + // Bottom panel + if show_log { + ImGui.Begin("Log", *show_log); + ImGui.Text("Output / Log"); + ImGui.Separator(); + ImGui.End(); + } + + // Demo window + if show_demo { + ImGui.ShowDemoWindow(*show_demo); + } + + end_frame(); + } + + renderer_cleanup(); + platform_shutdown(); +} diff --git a/src/platform/platform.h b/src/platform/platform.h deleted file mode 100644 index 3436e44..0000000 --- a/src/platform/platform.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -struct PlatformWindow; - -struct PlatformWindowDesc { - const char *title = "autosample"; - int32_t width = 1280; - int32_t height = 720; -}; - -struct PlatformMenuItem { - const char *label; // nullptr = separator - int32_t id; // command ID (ignored for separators) -}; - -struct PlatformMenu { - const char *label; - PlatformMenuItem *items; - int32_t item_count; -}; - -PlatformWindow *platform_create_window(PlatformWindowDesc *desc); -void platform_destroy_window(PlatformWindow *window); -bool platform_poll_events(PlatformWindow *window); -void platform_get_size(PlatformWindow *window, int32_t *w, int32_t *h); -void *platform_get_native_handle(PlatformWindow *window); - -void platform_set_menu(PlatformWindow *window, PlatformMenu *menus, int32_t menu_count); -int32_t platform_poll_menu_command(PlatformWindow *window); diff --git a/src/platform/platform.jai b/src/platform/platform.jai new file mode 100644 index 0000000..6e56518 --- /dev/null +++ b/src/platform/platform.jai @@ -0,0 +1,139 @@ +// autosample — Win32 platform layer + +// ------------------------------------------------------------------- +// Missing Win32 declarations +// ------------------------------------------------------------------- +CS_CLASSDC :: 0x0040; + +user32 :: #library,system "user32"; + +CreateMenu :: () -> HMENU #foreign user32; +CreatePopupMenu :: () -> HMENU #foreign user32; +AppendMenuW :: (hMenu: HMENU, uFlags: u32, uIDNewItem: u64, lpNewItem: *u16) -> s32 #foreign user32; +SetMenu :: (hWnd: HWND, hMenu: HMENU) -> s32 #foreign user32; + +MF_STRING :: 0x0000; +MF_SEPARATOR :: 0x0800; +MF_POPUP :: 0x0010; + +// ------------------------------------------------------------------- +// Platform state +// ------------------------------------------------------------------- +hwnd: HWND; +w_width: u32 = 1280; +w_height: u32 = 800; + +pending_menu_cmd: s32; + +// ------------------------------------------------------------------- +// WndProc +// ------------------------------------------------------------------- +my_wndproc :: (window_hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #c_call { + // Forward to ImGui + result := ImGui.ImplWin32_WndProcHandler(window_hwnd, msg, wparam, lparam); + if result return result; + + if msg == { + case WM_SIZE; + if wparam != SIZE_MINIMIZED { + w_width = cast(u32) (lparam & 0xFFFF); + w_height = cast(u32) ((lparam >> 16) & 0xFFFF); + } + return 0; + case WM_COMMAND; + if (wparam >> 16) == 0 // HIWORD == 0 means menu + pending_menu_cmd = cast(s32) (wparam & 0xFFFF); + return 0; + case WM_SYSCOMMAND; + if (wparam & 0xfff0) == SC_KEYMENU return 0; + case WM_DESTROY; + PostQuitMessage(0); + return 0; + } + + return DefWindowProcW(window_hwnd, msg, wparam, lparam); +} + +// ------------------------------------------------------------------- +// Native Win32 Menus +// ------------------------------------------------------------------- +menu_bar_handle: HMENU; + +setup_menus :: () { + menu_bar_handle = CreateMenu(); + + // File menu + file_menu := CreatePopupMenu(); + AppendMenuW(file_menu, MF_STRING, xx MENU_FILE_NEW, utf8_to_wide("New")); + AppendMenuW(file_menu, MF_STRING, xx MENU_FILE_OPEN, utf8_to_wide("Open...")); + AppendMenuW(file_menu, MF_STRING, xx MENU_FILE_SAVE, utf8_to_wide("Save")); + AppendMenuW(file_menu, MF_STRING, xx MENU_FILE_SAVE_AS, utf8_to_wide("Save As...")); + AppendMenuW(file_menu, MF_SEPARATOR, 0, null); + AppendMenuW(file_menu, MF_STRING, xx MENU_FILE_EXIT, utf8_to_wide("Exit")); + AppendMenuW(menu_bar_handle, MF_POPUP, xx file_menu, utf8_to_wide("File")); + + // Import menu + import_menu := CreatePopupMenu(); + AppendMenuW(import_menu, MF_STRING, xx MENU_IMPORT_AUDIO, utf8_to_wide("Audio...")); + AppendMenuW(import_menu, MF_STRING, xx MENU_IMPORT_MIDI, utf8_to_wide("MIDI...")); + AppendMenuW(menu_bar_handle, MF_POPUP, xx import_menu, utf8_to_wide("Import")); + + // View menu + view_menu := CreatePopupMenu(); + AppendMenuW(view_menu, MF_STRING, xx MENU_VIEW_BROWSER, utf8_to_wide("Browser")); + AppendMenuW(view_menu, MF_STRING, xx MENU_VIEW_PROPERTIES, utf8_to_wide("Properties")); + AppendMenuW(view_menu, MF_STRING, xx MENU_VIEW_LOG, utf8_to_wide("Log")); + AppendMenuW(view_menu, MF_SEPARATOR, 0, null); + AppendMenuW(view_menu, MF_STRING, xx MENU_VIEW_DEMO, utf8_to_wide("Demo")); + AppendMenuW(menu_bar_handle, MF_POPUP, xx view_menu, utf8_to_wide("View")); + + SetMenu(hwnd, menu_bar_handle); +} + +// ------------------------------------------------------------------- +// Platform Init / Shutdown +// ------------------------------------------------------------------- +platform_init :: () -> bool { + wc: WNDCLASSEXW; + wc.cbSize = size_of(WNDCLASSEXW); + wc.style = CS_CLASSDC; + wc.lpfnWndProc = xx my_wndproc; + wc.hInstance = GetModuleHandleW(null); + wc.lpszClassName = utf8_to_wide("autosample_wc"); + RegisterClassExW(*wc); + + screen_w := GetSystemMetrics(SM_CXSCREEN); + screen_h := GetSystemMetrics(SM_CYSCREEN); + x := (screen_w - cast(s32) w_width) / 2; + y := (screen_h - cast(s32) w_height) / 2; + + rect: RECT; + rect.right = cast(s32) w_width; + rect.bottom = cast(s32) w_height; + AdjustWindowRect(*rect, WS_OVERLAPPEDWINDOW, 0); + + hwnd = CreateWindowExW( + 0, + wc.lpszClassName, + utf8_to_wide("autosample"), + WS_OVERLAPPEDWINDOW, + x, y, + rect.right - rect.left, + rect.bottom - rect.top, + null, null, wc.hInstance, null + ); + + if !hwnd { + print("CreateWindowExW failed\n"); + return false; + } + + ShowWindow(hwnd, SW_SHOWDEFAULT); + UpdateWindow(hwnd); + return true; +} + +platform_shutdown :: () { + DestroyWindow(hwnd); + UnregisterClassW(utf8_to_wide("autosample_wc"), GetModuleHandleW(null)); +} diff --git a/src/platform/platform_win32.cpp b/src/platform/platform_win32.cpp deleted file mode 100644 index 757e264..0000000 --- a/src/platform/platform_win32.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "platform/platform.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include - -#include "imgui_impl_win32.h" - -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -struct PlatformWindow { - HWND hwnd; - bool should_close; - int32_t width; - int32_t height; - int32_t pending_menu_cmd; -}; - -static PlatformWindow *g_current_window = nullptr; - -static LRESULT CALLBACK win32_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - if (ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam)) - return true; - - switch (msg) { - case WM_SIZE: - if (g_current_window && wparam != SIZE_MINIMIZED) { - g_current_window->width = (int32_t)LOWORD(lparam); - g_current_window->height = (int32_t)HIWORD(lparam); - } - return 0; - case WM_COMMAND: - if (g_current_window && HIWORD(wparam) == 0) - g_current_window->pending_menu_cmd = (int32_t)LOWORD(wparam); - return 0; - case WM_CLOSE: - if (g_current_window) - g_current_window->should_close = true; - return 0; - case WM_DESTROY: - PostQuitMessage(0); - return 0; - case WM_SYSCOMMAND: - if ((wparam & 0xfff0) == SC_KEYMENU) - return 0; - break; - } - return DefWindowProcW(hwnd, msg, wparam, lparam); -} - -PlatformWindow *platform_create_window(PlatformWindowDesc *desc) -{ - WNDCLASSEXW wc = {}; - wc.cbSize = sizeof(wc); - wc.style = CS_CLASSDC; - wc.lpfnWndProc = win32_wndproc; - wc.hInstance = GetModuleHandleW(nullptr); - wc.lpszClassName = L"autosample_wc"; - RegisterClassExW(&wc); - - int screen_w = GetSystemMetrics(SM_CXSCREEN); - int screen_h = GetSystemMetrics(SM_CYSCREEN); - int x = (screen_w - desc->width) / 2; - int y = (screen_h - desc->height) / 2; - - RECT rect = { 0, 0, (LONG)desc->width, (LONG)desc->height }; - AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); - - int wchar_count = MultiByteToWideChar(CP_UTF8, 0, desc->title, -1, nullptr, 0); - wchar_t *wtitle = (wchar_t *)_malloca(wchar_count * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, desc->title, -1, wtitle, wchar_count); - - HWND hwnd = CreateWindowExW( - 0, wc.lpszClassName, wtitle, - WS_OVERLAPPEDWINDOW, - x, y, - rect.right - rect.left, - rect.bottom - rect.top, - nullptr, nullptr, wc.hInstance, nullptr - ); - - _freea(wtitle); - - if (!hwnd) - return nullptr; - - ShowWindow(hwnd, SW_SHOWDEFAULT); - UpdateWindow(hwnd); - - PlatformWindow *window = new PlatformWindow(); - window->hwnd = hwnd; - window->should_close = false; - window->width = desc->width; - window->height = desc->height; - - g_current_window = window; - return window; -} - -void platform_destroy_window(PlatformWindow *window) -{ - if (!window) return; - - if (window->hwnd) { - DestroyWindow(window->hwnd); - UnregisterClassW(L"autosample_wc", GetModuleHandleW(nullptr)); - } - - if (g_current_window == window) - g_current_window = nullptr; - - delete window; -} - -bool platform_poll_events(PlatformWindow *window) -{ - MSG msg; - while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessageW(&msg); - if (msg.message == WM_QUIT) { - window->should_close = true; - } - } - return !window->should_close; -} - -void platform_get_size(PlatformWindow *window, int32_t *w, int32_t *h) -{ - if (w) *w = window->width; - if (h) *h = window->height; -} - -void *platform_get_native_handle(PlatformWindow *window) -{ - return (void *)window->hwnd; -} - -void platform_set_menu(PlatformWindow *window, PlatformMenu *menus, int32_t menu_count) -{ - HMENU menu_bar = CreateMenu(); - - for (int32_t i = 0; i < menu_count; i++) { - HMENU submenu = CreatePopupMenu(); - - for (int32_t j = 0; j < menus[i].item_count; j++) { - PlatformMenuItem *item = &menus[i].items[j]; - if (!item->label) { - AppendMenuW(submenu, MF_SEPARATOR, 0, nullptr); - } else { - int wchar_count = MultiByteToWideChar(CP_UTF8, 0, item->label, -1, nullptr, 0); - wchar_t *wlabel = (wchar_t *)_malloca(wchar_count * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, item->label, -1, wlabel, wchar_count); - AppendMenuW(submenu, MF_STRING, (UINT_PTR)item->id, wlabel); - _freea(wlabel); - } - } - - int wchar_count = MultiByteToWideChar(CP_UTF8, 0, menus[i].label, -1, nullptr, 0); - wchar_t *wlabel = (wchar_t *)_malloca(wchar_count * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, menus[i].label, -1, wlabel, wchar_count); - AppendMenuW(menu_bar, MF_POPUP, (UINT_PTR)submenu, wlabel); - _freea(wlabel); - } - - SetMenu(window->hwnd, menu_bar); -} - -int32_t platform_poll_menu_command(PlatformWindow *window) -{ - int32_t cmd = window->pending_menu_cmd; - window->pending_menu_cmd = 0; - return cmd; -} diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h deleted file mode 100644 index dd26a84..0000000 --- a/src/renderer/renderer.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -struct Renderer; - -struct RendererDesc { - void *window_handle = nullptr; - int32_t width = 1280; - int32_t height = 720; - int32_t frame_count = 2; -}; - -Renderer *renderer_create(RendererDesc *desc); -void renderer_destroy(Renderer *renderer); -bool renderer_begin_frame(Renderer *renderer); -void renderer_end_frame(Renderer *renderer); -void renderer_resize(Renderer *renderer, int32_t width, int32_t height); diff --git a/src/renderer/renderer.jai b/src/renderer/renderer.jai new file mode 100644 index 0000000..6482210 --- /dev/null +++ b/src/renderer/renderer.jai @@ -0,0 +1,366 @@ +// autosample — DX12 renderer + ImGui integration + +// ------------------------------------------------------------------- +// Constants +// ------------------------------------------------------------------- +NUM_BACK_BUFFERS :: 2; +SRV_HEAP_SIZE :: 64; + +// ------------------------------------------------------------------- +// SRV Heap Allocator +// ------------------------------------------------------------------- +SrvHeapAllocator :: struct { + heap: *ID3D12DescriptorHeap; + start_cpu: D3D12_CPU_DESCRIPTOR_HANDLE; + start_gpu: D3D12_GPU_DESCRIPTOR_HANDLE; + increment: u32; + free_indices: [SRV_HEAP_SIZE] s32; + free_count: s32; +} + +srv_alloc_init :: (a: *SrvHeapAllocator, device: *ID3D12Device, heap: *ID3D12DescriptorHeap) { + a.heap = heap; + a.start_cpu = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap); + a.start_gpu = ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap); + a.increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, .CBV_SRV_UAV); + + desc := ID3D12DescriptorHeap_GetDesc(heap); + a.free_count = cast(s32) desc.NumDescriptors; + for i: 0..a.free_count-1 { + a.free_indices[i] = a.free_count - 1 - cast(s32) i; + } +} + +srv_alloc_alloc :: (a: *SrvHeapAllocator, out_cpu: *D3D12_CPU_DESCRIPTOR_HANDLE, out_gpu: *D3D12_GPU_DESCRIPTOR_HANDLE) { + a.free_count -= 1; + idx := a.free_indices[a.free_count]; + out_cpu.ptr = a.start_cpu.ptr + cast(u64)(idx * cast(s32) a.increment); + out_gpu.ptr = a.start_gpu.ptr + cast(u64)(idx * cast(s32) a.increment); +} + +srv_alloc_free :: (a: *SrvHeapAllocator, cpu: D3D12_CPU_DESCRIPTOR_HANDLE, gpu: D3D12_GPU_DESCRIPTOR_HANDLE) { + idx := cast(s32)((cpu.ptr - a.start_cpu.ptr) / cast(u64) a.increment); + a.free_indices[a.free_count] = idx; + a.free_count += 1; +} + +// ------------------------------------------------------------------- +// Frame Context +// ------------------------------------------------------------------- +FrameContext :: struct { + command_allocator: *ID3D12CommandAllocator; + fence_value: u64; +} + +// ------------------------------------------------------------------- +// Renderer state (module-level globals) +// ------------------------------------------------------------------- +device: *ID3D12Device; +command_queue: *ID3D12CommandQueue; +swap_chain: *dxgi.IDXGISwapChain3; +swap_chain_waitable: HANDLE; +swap_chain_occluded: bool; + +rtv_heap: *ID3D12DescriptorHeap; +srv_heap: *ID3D12DescriptorHeap; +srv_alloc: SrvHeapAllocator; + +frames: [NUM_BACK_BUFFERS] FrameContext; +render_targets: [NUM_BACK_BUFFERS] *ID3D12Resource; +rtv_descriptors: [NUM_BACK_BUFFERS] D3D12_CPU_DESCRIPTOR_HANDLE; + +command_list: *ID3D12GraphicsCommandList; +fence: *ID3D12Fence; +fence_event: HANDLE; +fence_last_signaled: u64; + +frame_index: u32; + +// ------------------------------------------------------------------- +// DX12 Setup +// ------------------------------------------------------------------- +create_device :: () -> bool { + hr := D3D12CreateDevice(null, .D3D_FEATURE_LEVEL_11_0, *uid(ID3D12Device_UUID), xx *device); + if hr != S_OK { + print("D3D12CreateDevice failed: %\n", hr); + return false; + } + return true; +} + +create_command_queue :: () -> bool { + desc: D3D12_COMMAND_QUEUE_DESC; + desc.Type = .DIRECT; + desc.Flags = .NONE; + desc.NodeMask = 1; + hr := ID3D12Device_CreateCommandQueue(device, *desc, *uid(ID3D12CommandQueue_UUID), xx *command_queue); + return hr == S_OK; +} + +create_descriptor_heaps :: () -> bool { + // RTV heap + { + desc: D3D12_DESCRIPTOR_HEAP_DESC; + desc.Type = .RTV; + desc.NumDescriptors = NUM_BACK_BUFFERS; + desc.Flags = .NONE; + desc.NodeMask = 1; + hr := ID3D12Device_CreateDescriptorHeap(device, *desc, *uid(ID3D12DescriptorHeap_UUID), xx *rtv_heap); + if hr != S_OK return false; + + rtv_size := ID3D12Device_GetDescriptorHandleIncrementSize(device, .RTV); + handle := ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_heap); + for i: 0..NUM_BACK_BUFFERS-1 { + rtv_descriptors[i] = handle; + handle.ptr += cast(u64) rtv_size; + } + } + + // SRV heap + { + desc: D3D12_DESCRIPTOR_HEAP_DESC; + desc.Type = .CBV_SRV_UAV; + desc.NumDescriptors = SRV_HEAP_SIZE; + desc.Flags = .SHADER_VISIBLE; + desc.NodeMask = 1; + hr := ID3D12Device_CreateDescriptorHeap(device, *desc, *uid(ID3D12DescriptorHeap_UUID), xx *srv_heap); + if hr != S_OK return false; + + srv_alloc_init(*srv_alloc, device, srv_heap); + } + + return true; +} + +create_frame_resources :: () -> bool { + for i: 0..NUM_BACK_BUFFERS-1 { + hr := ID3D12Device_CreateCommandAllocator(device, .DIRECT, *uid(ID3D12CommandAllocator_UUID), xx *frames[i].command_allocator); + if hr != S_OK return false; + frames[i].fence_value = 0; + } + + hr := ID3D12Device_CreateCommandList(device, 0, .DIRECT, frames[0].command_allocator, null, *uid(ID3D12GraphicsCommandList_UUID), xx *command_list); + if hr != S_OK return false; + ID3D12GraphicsCommandList_Close(command_list); + + hr = ID3D12Device_CreateFence(device, 0, .NONE, *uid(ID3D12Fence_UUID), xx *fence); + if hr != S_OK return false; + + fence_event = CreateEventW(null, 0, 0, null); + return fence_event != null; +} + +create_swap_chain :: () -> bool { + sd: dxgi.DXGI_SWAP_CHAIN_DESC1; + sd.BufferCount = NUM_BACK_BUFFERS; + sd.Width = 0; + sd.Height = 0; + sd.Format = .R8G8B8A8_UNORM; + sd.Flags = cast(u32) dxgi.DXGI_SWAP_CHAIN_FLAG.FRAME_LATENCY_WAITABLE_OBJECT; + sd.BufferUsage = .RENDER_TARGET_OUTPUT; + sd.SampleDesc.Count = 1; + sd.SwapEffect = .FLIP_DISCARD; + sd.Scaling = .STRETCH; + + factory: *dxgi.IDXGIFactory4; + hr := dxgi.CreateDXGIFactory1(*uid(dxgi.IDXGIFactory4_UUID), xx *factory); + if hr != S_OK return false; + defer IUnknown_Release(factory); + + swap_chain1: *dxgi.IDXGISwapChain1; + hr = dxgi.IDXGIFactory2_CreateSwapChainForHwnd(factory, xx command_queue, hwnd, *sd, null, null, xx *swap_chain1); + if hr != S_OK return false; + + hr = IUnknown_QueryInterface(swap_chain1, *uid(dxgi.IDXGISwapChain3_UUID), xx *swap_chain); + IUnknown_Release(swap_chain1); + if hr != S_OK return false; + + dxgi.IDXGIFactory_MakeWindowAssociation(factory, hwnd, xx dxgi.DXGI_MWA.NO_ALT_ENTER); + + dxgi.IDXGISwapChain2_SetMaximumFrameLatency(swap_chain, NUM_BACK_BUFFERS); + swap_chain_waitable = dxgi.IDXGISwapChain2_GetFrameLatencyWaitableObject(swap_chain); + + return true; +} + +create_render_targets :: () { + for i: 0..NUM_BACK_BUFFERS-1 { + dxgi.IDXGISwapChain_GetBuffer(swap_chain, cast(u32) i, *uid(ID3D12Resource_UUID), xx *render_targets[i]); + ID3D12Device_CreateRenderTargetView(device, render_targets[i], null, rtv_descriptors[i]); + } +} + +cleanup_render_targets :: () { + for i: 0..NUM_BACK_BUFFERS-1 { + if render_targets[i] { + IUnknown_Release(render_targets[i]); + render_targets[i] = null; + } + } +} + +wait_for_pending :: () { + fence_last_signaled += 1; + ID3D12CommandQueue_Signal(command_queue, fence, fence_last_signaled); + ID3D12Fence_SetEventOnCompletion(fence, fence_last_signaled, fence_event); + WaitForSingleObject(fence_event, 0xffff_ffff); +} + +// ------------------------------------------------------------------- +// ImGui SRV allocator callbacks (C calling convention) +// ------------------------------------------------------------------- +imgui_srv_alloc :: (info: *ImGui.ImplDX12_InitInfo, out_cpu: *D3D12_CPU_DESCRIPTOR_HANDLE, out_gpu: *D3D12_GPU_DESCRIPTOR_HANDLE) #c_call { + a := *srv_alloc; + a.free_count -= 1; + idx := a.free_indices[a.free_count]; + out_cpu.ptr = a.start_cpu.ptr + cast(u64)(idx * cast(s32) a.increment); + out_gpu.ptr = a.start_gpu.ptr + cast(u64)(idx * cast(s32) a.increment); +} + +imgui_srv_free :: (info: *ImGui.ImplDX12_InitInfo, cpu: D3D12_CPU_DESCRIPTOR_HANDLE, gpu: D3D12_GPU_DESCRIPTOR_HANDLE) #c_call { + a := *srv_alloc; + idx := cast(s32)((cpu.ptr - a.start_cpu.ptr) / cast(u64) a.increment); + a.free_indices[a.free_count] = idx; + a.free_count += 1; +} + +// ------------------------------------------------------------------- +// ImGui Init +// ------------------------------------------------------------------- +init_imgui :: () { + ImGui.CreateContext(); + io := ImGui.GetIO(); + io.ConfigFlags_ |= .NavEnableKeyboard; + io.ConfigFlags_ |= .DockingEnable; + + ImGui.StyleColorsDark(); + + ImGui.ImplWin32_Init(hwnd); + + init_info: ImGui.ImplDX12_InitInfo; + init_info.Device = device; + init_info.CommandQueue = command_queue; + init_info.NumFramesInFlight = NUM_BACK_BUFFERS; + init_info.RTVFormat = .R8G8B8A8_UNORM; + init_info.DSVFormat = .UNKNOWN; + init_info.SrvDescriptorHeap = srv_heap; + init_info.SrvDescriptorAllocFn = imgui_srv_alloc; + init_info.SrvDescriptorFreeFn = imgui_srv_free; + ImGui.ImplDX12_Init(*init_info); +} + +// ------------------------------------------------------------------- +// Begin / End Frame +// ------------------------------------------------------------------- +begin_frame :: () -> bool { + if swap_chain_occluded { + hr := dxgi.IDXGISwapChain_Present(xx swap_chain, 0, xx dxgi.DXGI_PRESENT.TEST); + if hr == xx dxgi.DXGI_STATUS_OCCLUDED { + Sleep(10); + return false; + } + swap_chain_occluded = false; + } + + ImGui.ImplDX12_NewFrame(); + ImGui.ImplWin32_NewFrame(); + ImGui.NewFrame(); + return true; +} + +end_frame :: () { + ImGui.Render(); + + // Wait for next frame + fc := *frames[frame_index % NUM_BACK_BUFFERS]; + if ID3D12Fence_GetCompletedValue(fence) < fc.fence_value { + ID3D12Fence_SetEventOnCompletion(fence, fc.fence_value, fence_event); + waitables: [2] HANDLE; + waitables[0] = swap_chain_waitable; + waitables[1] = fence_event; + WaitForMultipleObjects(2, waitables.data, cast(BOOL) 1, 0xffff_ffff); + } else { + WaitForSingleObject(swap_chain_waitable, 0xffff_ffff); + } + + back_buffer_idx := dxgi.IDXGISwapChain3_GetCurrentBackBufferIndex(swap_chain); + + ID3D12CommandAllocator_Reset(fc.command_allocator); + ID3D12GraphicsCommandList_Reset(command_list, fc.command_allocator, null); + + // Transition to render target + barrier: D3D12_RESOURCE_BARRIER; + barrier.Type = .TRANSITION; + barrier.Flags = .NONE; + barrier.Transition.pResource = render_targets[back_buffer_idx]; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = .PRESENT; + barrier.Transition.StateAfter = .RENDER_TARGET; + ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, *barrier); + + clear_color := float.[0.1, 0.1, 0.1, 1.0]; + ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv_descriptors[back_buffer_idx], *clear_color, 0, null); + ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, *rtv_descriptors[back_buffer_idx], .FALSE, null); + ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, *srv_heap); + + ImGui.ImplDX12_RenderDrawData(ImGui.GetDrawData(), command_list); + + // Transition to present + barrier.Transition.StateBefore = .RENDER_TARGET; + barrier.Transition.StateAfter = .PRESENT; + ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, *barrier); + ID3D12GraphicsCommandList_Close(command_list); + + // Submit + ID3D12CommandQueue_ExecuteCommandLists(command_queue, 1, xx *command_list); + fence_last_signaled += 1; + ID3D12CommandQueue_Signal(command_queue, fence, fence_last_signaled); + fc.fence_value = fence_last_signaled; + + // Present + hr := dxgi.IDXGISwapChain_Present(xx swap_chain, 1, 0); + swap_chain_occluded = (hr == xx dxgi.DXGI_STATUS_OCCLUDED); + frame_index += 1; +} + +// ------------------------------------------------------------------- +// Resize +// ------------------------------------------------------------------- +resize :: (width: u32, height: u32) { + if width == 0 || height == 0 return; + + wait_for_pending(); + cleanup_render_targets(); + + desc: dxgi.DXGI_SWAP_CHAIN_DESC1; + dxgi.IDXGISwapChain1_GetDesc1(swap_chain, *desc); + dxgi.IDXGISwapChain_ResizeBuffers(xx swap_chain, 0, width, height, desc.Format, desc.Flags); + + create_render_targets(); +} + +// ------------------------------------------------------------------- +// Cleanup +// ------------------------------------------------------------------- +renderer_cleanup :: () { + wait_for_pending(); + + ImGui.ImplDX12_Shutdown(); + ImGui.ImplWin32_Shutdown(); + ImGui.DestroyContext(); + + cleanup_render_targets(); + + if swap_chain { IUnknown_Release(swap_chain); swap_chain = null; } + if swap_chain_waitable CloseHandle(swap_chain_waitable); + for i: 0..NUM_BACK_BUFFERS-1 { + if frames[i].command_allocator IUnknown_Release(frames[i].command_allocator); + } + if command_queue IUnknown_Release(command_queue); + if command_list IUnknown_Release(command_list); + if rtv_heap IUnknown_Release(rtv_heap); + if srv_heap IUnknown_Release(srv_heap); + if fence IUnknown_Release(fence); + if fence_event CloseHandle(fence_event); + if device IUnknown_Release(device); +} diff --git a/src/renderer/renderer_dx12.cpp b/src/renderer/renderer_dx12.cpp deleted file mode 100644 index 42e2455..0000000 --- a/src/renderer/renderer_dx12.cpp +++ /dev/null @@ -1,436 +0,0 @@ -#include "renderer/renderer.h" - -#include -#include - -#include "imgui.h" -#include "imgui_impl_win32.h" -#include "imgui_impl_dx12.h" - -#ifdef _DEBUG -#define DX12_ENABLE_DEBUG_LAYER -#endif - -#ifdef DX12_ENABLE_DEBUG_LAYER -#include -#pragma comment(lib, "dxguid.lib") -#endif - -#define NUM_BACK_BUFFERS 2 -#define SRV_HEAP_SIZE 64 - -struct FrameContext { - ID3D12CommandAllocator *command_allocator; - UINT64 fence_value; -}; - -struct SrvHeapAllocator { - ID3D12DescriptorHeap *heap; - D3D12_DESCRIPTOR_HEAP_TYPE heap_type; - D3D12_CPU_DESCRIPTOR_HANDLE start_cpu; - D3D12_GPU_DESCRIPTOR_HANDLE start_gpu; - UINT increment; - int free_indices[SRV_HEAP_SIZE]; - int free_count; -}; - -static void srv_alloc_init(SrvHeapAllocator *a, ID3D12Device *device, ID3D12DescriptorHeap *heap) -{ - a->heap = heap; - a->heap_type = heap->GetDesc().Type; - a->start_cpu = heap->GetCPUDescriptorHandleForHeapStart(); - a->start_gpu = heap->GetGPUDescriptorHandleForHeapStart(); - a->increment = device->GetDescriptorHandleIncrementSize(a->heap_type); - - D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc(); - a->free_count = (int)desc.NumDescriptors; - for (int i = 0; i < a->free_count; i++) - a->free_indices[i] = a->free_count - 1 - i; -} - -static void srv_alloc_alloc(SrvHeapAllocator *a, D3D12_CPU_DESCRIPTOR_HANDLE *out_cpu, D3D12_GPU_DESCRIPTOR_HANDLE *out_gpu) -{ - int idx = a->free_indices[--a->free_count]; - out_cpu->ptr = a->start_cpu.ptr + (idx * a->increment); - out_gpu->ptr = a->start_gpu.ptr + (idx * a->increment); -} - -static void srv_alloc_free(SrvHeapAllocator *a, D3D12_CPU_DESCRIPTOR_HANDLE cpu, D3D12_GPU_DESCRIPTOR_HANDLE gpu) -{ - (void)gpu; - int idx = (int)((cpu.ptr - a->start_cpu.ptr) / a->increment); - a->free_indices[a->free_count++] = idx; -} - -struct Renderer { - HWND hwnd; - int32_t width; - int32_t height; - int32_t frame_count; - UINT frame_index; - - ID3D12Device *device; - ID3D12CommandQueue *command_queue; - IDXGISwapChain3 *swap_chain; - HANDLE swap_chain_waitable; - bool swap_chain_occluded; - bool tearing_support; - - ID3D12DescriptorHeap *rtv_heap; - ID3D12DescriptorHeap *srv_heap; - SrvHeapAllocator srv_alloc; - - FrameContext frames[NUM_BACK_BUFFERS]; - ID3D12Resource *render_targets[NUM_BACK_BUFFERS]; - D3D12_CPU_DESCRIPTOR_HANDLE rtv_descriptors[NUM_BACK_BUFFERS]; - - ID3D12GraphicsCommandList *command_list; - ID3D12Fence *fence; - HANDLE fence_event; - UINT64 fence_last_signaled; -}; - -static bool create_device(Renderer *r) -{ -#ifdef DX12_ENABLE_DEBUG_LAYER - ID3D12Debug *debug = nullptr; - if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug)))) { - debug->EnableDebugLayer(); - debug->Release(); - } -#endif - - if (D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&r->device)) != S_OK) - return false; - -#ifdef DX12_ENABLE_DEBUG_LAYER - { - ID3D12InfoQueue *info_queue = nullptr; - if (SUCCEEDED(r->device->QueryInterface(IID_PPV_ARGS(&info_queue)))) { - info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); - info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - info_queue->Release(); - } - } -#endif - - return true; -} - -static bool create_command_queue(Renderer *r) -{ - D3D12_COMMAND_QUEUE_DESC desc = {}; - desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - desc.NodeMask = 1; - return r->device->CreateCommandQueue(&desc, IID_PPV_ARGS(&r->command_queue)) == S_OK; -} - -static bool create_descriptor_heaps(Renderer *r) -{ - { - D3D12_DESCRIPTOR_HEAP_DESC desc = {}; - desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - desc.NumDescriptors = NUM_BACK_BUFFERS; - desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - desc.NodeMask = 1; - if (r->device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&r->rtv_heap)) != S_OK) - return false; - - SIZE_T rtv_size = r->device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - D3D12_CPU_DESCRIPTOR_HANDLE handle = r->rtv_heap->GetCPUDescriptorHandleForHeapStart(); - for (int i = 0; i < NUM_BACK_BUFFERS; i++) { - r->rtv_descriptors[i] = handle; - handle.ptr += rtv_size; - } - } - - { - D3D12_DESCRIPTOR_HEAP_DESC desc = {}; - desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = SRV_HEAP_SIZE; - desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - if (r->device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&r->srv_heap)) != S_OK) - return false; - - srv_alloc_init(&r->srv_alloc, r->device, r->srv_heap); - } - - return true; -} - -static bool create_frame_resources(Renderer *r) -{ - for (int i = 0; i < r->frame_count; i++) { - if (r->device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, - IID_PPV_ARGS(&r->frames[i].command_allocator)) != S_OK) - return false; - r->frames[i].fence_value = 0; - } - - if (r->device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, - r->frames[0].command_allocator, nullptr, IID_PPV_ARGS(&r->command_list)) != S_OK) - return false; - if (r->command_list->Close() != S_OK) - return false; - - if (r->device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&r->fence)) != S_OK) - return false; - - r->fence_event = CreateEventW(nullptr, FALSE, FALSE, nullptr); - return r->fence_event != nullptr; -} - -static bool create_swap_chain(Renderer *r) -{ - DXGI_SWAP_CHAIN_DESC1 sd = {}; - sd.BufferCount = NUM_BACK_BUFFERS; - sd.Width = 0; - sd.Height = 0; - sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - sd.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; - sd.Scaling = DXGI_SCALING_STRETCH; - sd.Stereo = FALSE; - - IDXGIFactory5 *factory = nullptr; - if (CreateDXGIFactory1(IID_PPV_ARGS(&factory)) != S_OK) - return false; - - BOOL allow_tearing = FALSE; - factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing)); - r->tearing_support = (allow_tearing == TRUE); - if (r->tearing_support) - sd.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - - IDXGISwapChain1 *swap_chain1 = nullptr; - if (factory->CreateSwapChainForHwnd(r->command_queue, r->hwnd, &sd, nullptr, nullptr, &swap_chain1) != S_OK) { - factory->Release(); - return false; - } - - if (swap_chain1->QueryInterface(IID_PPV_ARGS(&r->swap_chain)) != S_OK) { - swap_chain1->Release(); - factory->Release(); - return false; - } - - if (r->tearing_support) - factory->MakeWindowAssociation(r->hwnd, DXGI_MWA_NO_ALT_ENTER); - - swap_chain1->Release(); - factory->Release(); - - r->swap_chain->SetMaximumFrameLatency(NUM_BACK_BUFFERS); - r->swap_chain_waitable = r->swap_chain->GetFrameLatencyWaitableObject(); - return true; -} - -static void create_render_targets(Renderer *r) -{ - for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { - ID3D12Resource *back_buffer = nullptr; - r->swap_chain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); - r->device->CreateRenderTargetView(back_buffer, nullptr, r->rtv_descriptors[i]); - r->render_targets[i] = back_buffer; - } -} - -static void cleanup_render_targets(Renderer *r) -{ - for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { - if (r->render_targets[i]) { - r->render_targets[i]->Release(); - r->render_targets[i] = nullptr; - } - } -} - -static void wait_for_pending(Renderer *r) -{ - r->command_queue->Signal(r->fence, ++r->fence_last_signaled); - r->fence->SetEventOnCompletion(r->fence_last_signaled, r->fence_event); - WaitForSingleObject(r->fence_event, INFINITE); -} - -static FrameContext *wait_for_next_frame(Renderer *r) -{ - FrameContext *fc = &r->frames[r->frame_index % r->frame_count]; - if (r->fence->GetCompletedValue() < fc->fence_value) { - r->fence->SetEventOnCompletion(fc->fence_value, r->fence_event); - HANDLE waitables[] = { r->swap_chain_waitable, r->fence_event }; - WaitForMultipleObjects(2, waitables, TRUE, INFINITE); - } else { - WaitForSingleObject(r->swap_chain_waitable, INFINITE); - } - return fc; -} - -static void init_imgui(Renderer *r) -{ - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - - ImGui::StyleColorsDark(); - - ImGui_ImplWin32_Init(r->hwnd); - - ImGui_ImplDX12_InitInfo init_info = {}; - init_info.Device = r->device; - init_info.CommandQueue = r->command_queue; - init_info.NumFramesInFlight = r->frame_count; - init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - init_info.DSVFormat = DXGI_FORMAT_UNKNOWN; - init_info.SrvDescriptorHeap = r->srv_heap; - init_info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo *info, D3D12_CPU_DESCRIPTOR_HANDLE *out_cpu, D3D12_GPU_DESCRIPTOR_HANDLE *out_gpu) { - Renderer *r = (Renderer *)info->UserData; - srv_alloc_alloc(&r->srv_alloc, out_cpu, out_gpu); - }; - init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo *info, D3D12_CPU_DESCRIPTOR_HANDLE cpu, D3D12_GPU_DESCRIPTOR_HANDLE gpu) { - Renderer *r = (Renderer *)info->UserData; - srv_alloc_free(&r->srv_alloc, cpu, gpu); - }; - init_info.UserData = r; - ImGui_ImplDX12_Init(&init_info); -} - -Renderer *renderer_create(RendererDesc *desc) -{ - Renderer *r = new Renderer(); - memset(r, 0, sizeof(*r)); - - r->hwnd = (HWND)desc->window_handle; - r->width = desc->width; - r->height = desc->height; - r->frame_count = desc->frame_count; - if (r->frame_count > NUM_BACK_BUFFERS) r->frame_count = NUM_BACK_BUFFERS; - - if (!create_device(r)) goto fail; - if (!create_command_queue(r)) goto fail; - if (!create_descriptor_heaps(r)) goto fail; - if (!create_frame_resources(r)) goto fail; - if (!create_swap_chain(r)) goto fail; - create_render_targets(r); - - init_imgui(r); - return r; - -fail: - renderer_destroy(r); - return nullptr; -} - -void renderer_destroy(Renderer *r) -{ - if (!r) return; - - wait_for_pending(r); - - ImGui_ImplDX12_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); - - cleanup_render_targets(r); - - if (r->swap_chain) { r->swap_chain->SetFullscreenState(false, nullptr); r->swap_chain->Release(); } - if (r->swap_chain_waitable) CloseHandle(r->swap_chain_waitable); - for (int i = 0; i < r->frame_count; i++) - if (r->frames[i].command_allocator) r->frames[i].command_allocator->Release(); - if (r->command_queue) r->command_queue->Release(); - if (r->command_list) r->command_list->Release(); - if (r->rtv_heap) r->rtv_heap->Release(); - if (r->srv_heap) r->srv_heap->Release(); - if (r->fence) r->fence->Release(); - if (r->fence_event) CloseHandle(r->fence_event); - if (r->device) r->device->Release(); - -#ifdef DX12_ENABLE_DEBUG_LAYER - IDXGIDebug1 *dxgi_debug = nullptr; - if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgi_debug)))) { - dxgi_debug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_SUMMARY); - dxgi_debug->Release(); - } -#endif - - delete r; -} - -bool renderer_begin_frame(Renderer *r) -{ - if ((r->swap_chain_occluded && r->swap_chain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) - || IsIconic(r->hwnd)) - { - Sleep(10); - return false; - } - r->swap_chain_occluded = false; - - ImGui_ImplDX12_NewFrame(); - ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); - return true; -} - -void renderer_end_frame(Renderer *r) -{ - ImGui::Render(); - - FrameContext *fc = wait_for_next_frame(r); - UINT back_buffer_idx = r->swap_chain->GetCurrentBackBufferIndex(); - - fc->command_allocator->Reset(); - r->command_list->Reset(fc->command_allocator, nullptr); - - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = r->render_targets[back_buffer_idx]; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; - r->command_list->ResourceBarrier(1, &barrier); - - const float clear_color[4] = { 0.1f, 0.1f, 0.1f, 1.0f }; - r->command_list->ClearRenderTargetView(r->rtv_descriptors[back_buffer_idx], clear_color, 0, nullptr); - r->command_list->OMSetRenderTargets(1, &r->rtv_descriptors[back_buffer_idx], FALSE, nullptr); - r->command_list->SetDescriptorHeaps(1, &r->srv_heap); - - ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), r->command_list); - - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; - r->command_list->ResourceBarrier(1, &barrier); - r->command_list->Close(); - - r->command_queue->ExecuteCommandLists(1, (ID3D12CommandList *const *)&r->command_list); - r->command_queue->Signal(r->fence, ++r->fence_last_signaled); - fc->fence_value = r->fence_last_signaled; - - HRESULT hr = r->swap_chain->Present(1, 0); - r->swap_chain_occluded = (hr == DXGI_STATUS_OCCLUDED); - r->frame_index++; -} - -void renderer_resize(Renderer *r, int32_t width, int32_t height) -{ - if (width <= 0 || height <= 0) return; - - wait_for_pending(r); - cleanup_render_targets(r); - - DXGI_SWAP_CHAIN_DESC1 desc = {}; - r->swap_chain->GetDesc1(&desc); - r->swap_chain->ResizeBuffers(0, (UINT)width, (UINT)height, desc.Format, desc.Flags); - - create_render_targets(r); - - r->width = width; - r->height = height; -}