Compare commits

...

3 Commits

Author SHA1 Message Date
7a5c1c5159 update widgets, add copy paste buffer 2026-02-26 00:04:02 -05:00
68235b57ce fix ui widgets 2026-02-25 16:40:14 -05:00
12dae774e4 move from imgui to CLAY 2026-02-25 15:20:47 -05:00
41 changed files with 7884 additions and 77321 deletions

9
.gitignore vendored
View File

@@ -1,6 +1,12 @@
# Build output
build/
# bullshit files
nul
# editor files
*.sublime-workspace
# nob build system
nob.exe
nob.obj
@@ -23,5 +29,4 @@ nob.ilk
# Misc
*.exe
!nob.c
!nob.c

View File

@@ -4,17 +4,51 @@ Graphical interface for automatically recording samples from existing analog aud
## Build
Requires MSVC (Visual Studio or Build Tools) with the Windows SDK.
Requires MSVC (Visual Studio 2019 Build Tools or later) with the Windows SDK and C++20 support.
Open a Developer Command Prompt, then:
```
cl /nologo nob.c
nob.exe
nob.exe debug
build\autosample.exe
```
The first command is a one-time bootstrap. After that, `nob.exe` detects changes to `nob.c` and rebuilds itself automatically.
The first command is a one-time bootstrap. After that, `nob.exe` detects changes to `nob.c` and rebuilds itself automatically. Pass `debug` for a debug build (default is release). Pass `clean` to wipe the build directory.
## Architecture
The project uses a **unity build**: `src/main.cpp` includes all other `.cpp` files, producing a single translation unit compiled with one `$CC` invocation.
### Base layer (`src/base/`)
Foundational types and utilities shared across the project. Provides sized integer/float typedefs (`U8`, `S32`, `F32`, `B32`, etc.), math primitives (`Vec2F32`), string helpers, and arena allocators. This layer has no dependencies beyond the C standard library.
### Platform layer (`src/platform/`)
Abstracts window creation, event polling, and native handles behind a C-style API with opaque `PlatformWindow` handles. The Win32 backend (`platform_win32.cpp`) implements the interface. Other backends can be added without touching the rest of the code.
### UI layer (`src/ui/`)
A thin wrapper around [Clay](https://github.com/nicbarker/clay) (v0.14), a single-header C layout library. Clay uses macros (`CLAY()`, `CLAY_TEXT()`, etc.) for declarative layout with automatic sizing, flex-like child arrangement, and built-in text measurement.
- `ui_core.h` / `ui_core.cpp` — Defines `UI_Context` and `UI_Theme`, handles Clay initialization, lifecycle (`ui_begin_frame` / `ui_end_frame`), text measurement bridge, and error handling. `CLAY_IMPLEMENTATION` is defined here.
- `ui_widgets.h` / `ui_widgets.cpp` — Widget abstractions (currently stubs, reserved for future use).
The application layout is built in `main.cpp` using Clay macros directly. Panel builder functions (`build_browser_panel`, `build_main_panel`, etc.) compose the UI each frame.
### Renderer (`src/renderer/`)
DirectX 12 renderer with a custom SDF-based pipeline for UI rendering. Processes Clay's `Clay_RenderCommandArray` output directly — no intermediate scene graph.
- **Font atlas**: Built at startup using GDI (`TextOutA` into a DIB section), converted to a single-channel R8 texture. Covers ASCII 32126 (Segoe UI).
- **Text measurement**: GDI-based (`GetTextExtentPoint32A`), exposed to Clay via the `Clay_SetMeasureTextFunction` callback.
- **Render commands**: Handles `RECTANGLE` (SDF rounded rect with corner radius), `BORDER` (individual sides as thin rects), `TEXT` (glyph quads from the font atlas), and `SCISSOR_START`/`SCISSOR_END` (clip regions).
- **Vertex format**: Position, UV, color, rect bounds, corner radius, border thickness, softness, and mode (0 = SDF rect, 1 = textured glyph). Alpha blending with premultiplied SDF anti-aliasing.
### MIDI (`src/midi/`)
Enumerates MIDI input and output devices via the Win32 multimedia API (`midiInGetDevCapsA` / `midiOutGetDevCapsA`). Provides a simple `MidiEngine` with device listing and refresh.
## Project structure
@@ -22,19 +56,42 @@ The first command is a one-time bootstrap. After that, `nob.exe` detects changes
nob.c Build script (compiled to nob.exe)
nob.h nob build system (vendored, single-header)
src/
main.cpp Entry point and main loop
main.cpp Entry point, unity build includes, Clay layout
menus.cpp Menu bar setup
theme.cpp Theme stub
base/
base_core.h Sized types, macros
base_arena.h / .cpp Arena allocator
base_math.h Vec2, min/max
base_strings.h / .cpp String utilities
base_inc.h / .cpp Aggregate include/impl
platform/
platform.h Window management API (platform-agnostic)
platform_win32.cpp Win32 implementation
renderer/
renderer.h Renderer API (graphics-agnostic)
renderer_dx12.cpp DirectX 12 implementation + Dear ImGui backend
renderer_dx12.cpp DirectX 12 implementation, SDF pipeline, font atlas
ui/
ui_core.h Clay wrapper types and lifecycle API
ui_core.cpp Clay init, text measurement bridge, theme
ui_widgets.h / .cpp Widget stubs (reserved)
midi/
midi.h MIDI device enumeration API
midi_win32.cpp Win32 multimedia implementation
vendor/
imgui/ Dear ImGui (vendored source)
backends/ Platform and renderer backends (Win32, DX12)
clay/
clay.h Clay v0.14 (modified for MSVC C++ compatibility)
```
The platform and renderer layers are C-style APIs with opaque handles. `platform.h` abstracts window creation so other backends can be added without touching the rest of the code. `renderer.h` abstracts graphics initialization and frame management.
### Modifications to `vendor/clay/clay.h`
Two targeted patches for MSVC C++ compatibility:
1. **`CLAY__CONFIG_WRAPPER` bypass** (lines 158163): MSVC C++ rejects designated initializers inside function-style casts. In C++ mode, the wrapper struct is bypassed: `(type { __VA_ARGS__ })` instead of `(WrapperType { .field = ... }).wrapped`.
2. **Debug view stub** (lines ~31553858): Clay's built-in debug view functions use `CLAY__INIT(type) { .field = ... }` directly (not through `CLAY__CONFIG_WRAPPER`), which also fails in MSVC C++. An `#ifdef __cplusplus` guard stubs out the 4 debug view functions as empty no-ops. The debug overlay is not needed.
These patches allow the entire project (including Clay) to compile as a single C++20 translation unit, avoiding C/C++ ABI mismatches with `CLAY_PACKED_ENUM` (which controls enum sizing differently in C vs C++ mode).
## Code style
@@ -42,14 +99,14 @@ This project is written in C-style C++. We use `.cpp` files and a small subset o
Memory should be managed with arena allocators where possible rather than individual `malloc`/`free` or `new`/`delete` calls. Arenas make allocation fast, avoid fragmentation, and simplify cleanup.
### Syntax Style
### Syntax style
- Opening braces go on the same line as the function signature (K&R style), not on the next line.
- use CAPS_SNAKE_CASE for constants, lower_snake_case for functions and variables, and CapsCamelCase for types.
- Use `CAPS_SNAKE_CASE` for constants, `lower_snake_case` for functions and variables, and `CapsCamelCase` for types.
## Dependencies
All dependencies are vendored as source. Nothing to download or install beyond the Windows SDK.
- [nob.h](https://github.com/tsoding/nob.h) - build system
- [Dear ImGui](https://github.com/ocornut/imgui) - GUI
- [nob.h](https://github.com/tsoding/nob.h) build system
- [Clay](https://github.com/nicbarker/clay) — single-header C layout library (v0.14, with MSVC C++ patches)

View File

@@ -1,5 +1,8 @@
// raddbg 0.9.24 project file
recent_file: path: "vendor/clay/clay.h"
recent_file: path: "src/base/base_arena.cpp"
recent_file: path: "src/ui/ui_core.cpp"
recent_file: path: "src/main.cpp"
recent_file: path: "src/theme.cpp"
recent_file: path: "nob.obj"
@@ -14,11 +17,11 @@ target:
debug_info:
{
path: "C:/Users/mta/projects/autosample/build/autosample.pdb"
timestamp: 66207529127862
timestamp: 66207573824751
}
target:
{
executable: "build/autosample.exe"
working_directory: "build/"
working_directory: build
enabled: 1
}

View File

@@ -0,0 +1,30 @@
{
"folders": [
{
"path": ".",
"folder_exclude_patterns": ["build", ".vscode", ".vs"]
}
],
"build_systems": [
{
"name": "nob",
"shell_cmd": "nob.exe",
"working_dir": "$project_path",
"file_regex": "^(.+?)\\(([0-9]+)\\):? *(error|fatal error|warning) *\\w+: *(.*)$",
"variants": [
{
"name": "Debug",
"shell_cmd": "nob.exe debug"
},
{
"name": "Clean",
"shell_cmd": "nob.exe clean"
},
{
"name": "Bootstrap",
"shell_cmd": "cl /nologo nob.c"
}
]
}
]
}

337
build_log.txt Normal file
View File

@@ -0,0 +1,337 @@
[INFO] directory `build` already exists
[INFO] CMD: cl.exe /nologo /std:c++20 /EHsc /W3 /Isrc /Ivendor/clay /MTd /Zi /Od /D_DEBUG /Fe:build/autosample.exe /Fo:build/ /Fd:build/autosample.pdb src/main.cpp /link /MACHINE:X64 /SUBSYSTEM:CONSOLE /PDB:build/autosample.pdb /DEBUG d3d12.lib dxgi.lib d3dcompiler.lib user32.lib gdi32.lib shell32.lib ole32.lib dwmapi.lib winmm.lib
main.cpp
C:\Users\mta\projects\autosample\vendor\clay\clay.h(1539): warning C4244: '+=': conversion from 'uintptr_t' to 'uint32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2248): warning C4305: 'initializing': truncation from 'double' to 'float'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3046): warning C4244: 'initializing': conversion from 'int' to 'float', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3207): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3207): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3207): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3208): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3208): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3208): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3208): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3238): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3238): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3238): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3241): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3241): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3241): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3241): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3241): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3246): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3246): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3246): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3246): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3246): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3246): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3249): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3249): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3249): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3250): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3250): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3250): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3250): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3250): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3256): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3256): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3256): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3256): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3257): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3257): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3257): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3257): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3257): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3257): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3261): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3261): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3261): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3261): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3262): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3262): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3262): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3262): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3262): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3262): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3268): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3268): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3268): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3268): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3268): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3268): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3278): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3278): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3278): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3278): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3278): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3278): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3279): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3279): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3279): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3279): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3279): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3279): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3283): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3283): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3283): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3283): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3283): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3283): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3284): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3284): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3284): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3284): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3284): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3284): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3292): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3292): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3292): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3292): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3292): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3292): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3293): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3293): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3293): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3293): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3293): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3293): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3302): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3302): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3302): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3302): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3303): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3303): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3303): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3304): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3304): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3304): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3344): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3344): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3344): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3344): note: 'floating': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3345): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3345): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3345): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3345): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3365): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3372): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3377): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_Padding'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): note: 'initializing': cannot convert from 'initializer list' to 'uint16_t'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): note: The initializer contains too many elements
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3386): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3387): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3387): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3387): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3387): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3387): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3387): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3388): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3388): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3388): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3388): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3388): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3388): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3390): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3390): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3390): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3391): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3391): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3391): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3391): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3391): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3391): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3396): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3396): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3396): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3398): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3400): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3402): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3404): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3406): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3406): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3406): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3407): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3407): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3407): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3407): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3407): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3407): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3412): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3412): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3412): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3414): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3416): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3418): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3420): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3448): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3448): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3448): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3448): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3449): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3449): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3449): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3449): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3471): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3471): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3471): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3471): note: 'floating': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3471): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3476): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3476): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3476): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3476): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3478): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3478): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3478): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3480): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3480): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3480): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3480): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3480): note: 'cornerRadius': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3480): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3487): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3487): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3487): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3487): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3487): error C2660: 'Clay__OpenTextElement': function does not take 1 arguments
C:\Users\mta\projects\autosample\vendor\clay\clay.h(2044): note: see declaration of 'Clay__OpenTextElement'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3487): note: while trying to match the argument list '(Clay_String)'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3490): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3490): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3490): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3490): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3491): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3491): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3491): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3491): note: 'clip': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3492): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3492): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3492): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3492): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3495): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3495): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3495): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3495): note: 'floating': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3496): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3496): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3496): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3501): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3501): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3501): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3512): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3512): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3512): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3512): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3516): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3516): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3516): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3516): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3519): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3519): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3519): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3519): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3519): note: 'clip': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3519): note: 'border': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3525): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3525): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3525): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3527): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3527): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3527): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3539): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3539): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3539): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3542): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3542): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3542): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3544): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3546): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3548): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3550): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3559): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3559): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3559): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3563): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3563): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3563): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3585): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3585): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3585): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3611): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3611): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3611): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3623): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3623): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3623): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3662): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3662): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3662): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3666): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3673): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3684): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3684): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3684): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3687): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3687): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3687): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3687): note: 'aspectRatio': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3687): note: 'image': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3693): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3693): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3693): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3705): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3705): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3705): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3708): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3708): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3708): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3710): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3712): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3717): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3717): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3717): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3719): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3721): warning C4244: 'argument': conversion from 'float' to 'int32_t', possible loss of data
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3733): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3733): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3733): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3806): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3806): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3806): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3808): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3808): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3808): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3831): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3831): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3831): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3831): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3831): note: 'clip': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3832): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_TextElementConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3832): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3832): note: 'void *': designated initialization can only be used to initialize aggregate class types
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3832): note: too many initializers
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3833): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3833): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3833): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3836): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3836): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3836): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3836): note: 'backgroundColor': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3840): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Clay_ElementDeclaration'
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3840): note: Invalid aggregate initialization
C:\Users\mta\projects\autosample\vendor\clay\clay.h(3840): note: 'layout': designator does not name a direct non-static data member of type 'Clay_LayoutConfig'
[ERROR] command exited with exit code 2
EXITCODE=1

View File

@@ -1,48 +0,0 @@
[Window][Browser]
Pos=0,0
Size=191,700
Collapsed=0
DockId=0x00000001,0
[Window][Main]
Pos=193,0
Size=868,523
Collapsed=0
DockId=0x00000005,0
[Window][Properties]
Pos=1063,0
Size=217,700
Collapsed=0
DockId=0x00000004,0
[Window][Log]
Pos=193,525
Size=868,175
Collapsed=0
DockId=0x00000006,0
[Window][WindowOverViewport_11111111]
Pos=0,0
Size=1280,700
Collapsed=0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Dear ImGui Demo]
Pos=650,20
Size=550,680
Collapsed=0
[Docking][Data]
DockSpace ID=0xF8498067 Window=0x1BBC0F80 Pos=0,0 Size=1280,700 Split=X
DockNode ID=0x00000001 Parent=0xF8498067 SizeRef=191,700 Selected=0x54719807
DockNode ID=0x00000002 Parent=0xF8498067 SizeRef=1087,700 Split=X
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=868,700 Split=Y
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=868,523 CentralNode=1 Selected=0x3E095604
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=868,175 Selected=0x139FDA3F
DockNode ID=0x00000004 Parent=0x00000002 SizeRef=217,700 Selected=0x8C72BEA8

134
nob.c
View File

@@ -5,22 +5,6 @@
#include "nob.h"
#define BUILD_DIR "build"
#define IMGUI_LIB_DEBUG BUILD_DIR "/imgui_d.lib"
#define IMGUI_LIB_RELEASE BUILD_DIR "/imgui.lib"
static const char *src_files[] = {
"src/main.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",
@@ -34,61 +18,6 @@ static const char *link_libs[] = {
"winmm.lib",
};
static const char *obj_name(const char *src_path) {
const char *slash = strrchr(src_path, '/');
const char *name = slash ? slash + 1 : src_path;
size_t len = strlen(name);
return nob_temp_sprintf("%s/%.*s.obj", BUILD_DIR, (int)(len - 4), name);
}
static bool build_imgui_lib(bool debug) {
const char *lib_path = debug ? IMGUI_LIB_DEBUG : IMGUI_LIB_RELEASE;
int need = nob_needs_rebuild(lib_path, imgui_files, NOB_ARRAY_LEN(imgui_files));
if (need < 0) return false;
if (!need) {
nob_log(NOB_INFO, "%s is up to date", lib_path);
return true;
}
nob_log(NOB_INFO, "Building %s...", lib_path);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe");
nob_cmd_append(&cmd, "/nologo", "/std:c++17", "/EHsc", "/W3", "/c");
nob_cmd_append(&cmd, "/Ivendor/imgui", "/Ivendor/imgui/backends");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
} else {
nob_cmd_append(&cmd, "/MT", "/O2", "/DNDEBUG");
}
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(imgui_files); i++)
nob_cmd_append(&cmd, imgui_files[i]);
if (!nob_cmd_run(&cmd)) return false;
// Archive .obj files into a .lib
cmd.count = 0;
nob_cmd_append(&cmd, "lib.exe", "/nologo", "/MACHINE:X64");
nob_cmd_append(&cmd, nob_temp_sprintf("/OUT:%s", lib_path));
for (size_t i = 0; i < NOB_ARRAY_LEN(imgui_files); i++)
nob_cmd_append(&cmd, obj_name(imgui_files[i]));
if (!nob_cmd_run(&cmd)) return false;
// Clean up imgui .obj files
for (size_t i = 0; i < NOB_ARRAY_LEN(imgui_files); i++)
nob_delete_file(obj_name(imgui_files[i]));
return true;
}
int main(int argc, char **argv) {
NOB_GO_REBUILD_URSELF(argc, argv);
@@ -103,49 +32,46 @@ int main(int argc, char **argv) {
nob_log(NOB_INFO, "Cleaning %s/", BUILD_DIR);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cmd.exe", "/c", "if exist " BUILD_DIR " rmdir /s /q " BUILD_DIR);
if (!nob_cmd_run(&cmd)) return 1;
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
return 0;
}
if (!nob_mkdir_if_not_exists(BUILD_DIR)) return 1;
// Build vendor libs (unless already built)
if (!build_imgui_lib(debug)) return 1;
// Unity build: single cl.exe invocation compiles main.cpp (which #includes everything)
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe");
nob_cmd_append(&cmd, "/nologo", "/std:c++20", "/EHsc", "/W3");
nob_cmd_append(&cmd, "/Isrc", "/Ivendor/clay");
// Compile and link
Nob_Cmd cmd = {0};
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
} else {
nob_cmd_append(&cmd, "/MT", "/Zi", "/O2", "/DNDEBUG");
}
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");
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/autosample.pdb", BUILD_DIR));
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
} else {
nob_cmd_append(&cmd, "/MT", "/Zi", "/O2", "/DNDEBUG");
nob_cmd_append(&cmd, "src/main.cpp");
nob_cmd_append(&cmd, "/link");
nob_cmd_append(&cmd, "/MACHINE:X64");
nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE");
nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", BUILD_DIR));
nob_cmd_append(&cmd, "/DEBUG");
{
size_t i;
for (i = 0; i < NOB_ARRAY_LEN(link_libs); i++)
nob_cmd_append(&cmd, link_libs[i]);
}
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
}
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/autosample.pdb", BUILD_DIR));
for (size_t i = 0; i < NOB_ARRAY_LEN(src_files); i++)
nob_cmd_append(&cmd, src_files[i]);
nob_cmd_append(&cmd, "/link");
nob_cmd_append(&cmd, "/MACHINE:X64");
nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE");
nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", BUILD_DIR));
nob_cmd_append(&cmd, "/DEBUG");
nob_cmd_append(&cmd, debug ? IMGUI_LIB_DEBUG : IMGUI_LIB_RELEASE);
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;
// Clean up .obj files
for (size_t i = 0; i < NOB_ARRAY_LEN(src_files); i++)
nob_delete_file(obj_name(src_files[i]));
// Clean up obj files
nob_delete_file(nob_temp_sprintf("%s/main.obj", BUILD_DIR));
nob_log(NOB_INFO, "Build complete: %s/autosample.exe", BUILD_DIR);
return 0;

53
src/base/base_arena.cpp Normal file
View File

@@ -0,0 +1,53 @@
#include "base/base_arena.h"
#include <stdlib.h>
Arena *arena_alloc(U64 cap) {
U8 *mem = (U8 *)malloc(sizeof(Arena) + cap);
if (!mem) return nullptr;
Arena *arena = (Arena *)mem;
arena->base = mem + sizeof(Arena);
arena->pos = 0;
arena->cap = cap;
return arena;
}
void arena_release(Arena *arena) {
if (arena) free(arena);
}
void *arena_push(Arena *arena, U64 size) {
U64 aligned = AlignPow2(size, 8);
if (arena->pos + aligned > arena->cap) {
Assert(!"Arena overflow");
return nullptr;
}
void *result = arena->base + arena->pos;
arena->pos += aligned;
MemoryZero(result, aligned);
return result;
}
void *arena_push_no_zero(Arena *arena, U64 size) {
U64 aligned = AlignPow2(size, 8);
if (arena->pos + aligned > arena->cap) {
Assert(!"Arena overflow");
return nullptr;
}
void *result = arena->base + arena->pos;
arena->pos += aligned;
return result;
}
U64 arena_pos(Arena *arena) {
return arena->pos;
}
void arena_pop_to(Arena *arena, U64 pos) {
if (pos < arena->pos) {
arena->pos = pos;
}
}
void arena_clear(Arena *arena) {
arena->pos = 0;
}

44
src/base/base_arena.h Normal file
View File

@@ -0,0 +1,44 @@
#pragma once
// base_arena.h - Linear arena allocator
// Simplified from raddebugger's virtual-memory-backed arena to a malloc-based one.
// Suitable for per-frame scratch allocations and persistent state.
#include "base/base_core.h"
////////////////////////////////
// Arena type
struct Arena {
U8 *base;
U64 pos;
U64 cap;
};
// Temporary scope (save/restore position)
struct Temp {
Arena *arena;
U64 pos;
};
////////////////////////////////
// Arena functions
Arena *arena_alloc(U64 cap);
void arena_release(Arena *arena);
void *arena_push(Arena *arena, U64 size);
void *arena_push_no_zero(Arena *arena, U64 size);
U64 arena_pos(Arena *arena);
void arena_pop_to(Arena *arena, U64 pos);
void arena_clear(Arena *arena);
////////////////////////////////
// Temporary scope helpers
inline Temp temp_begin(Arena *arena) { return {arena, arena->pos}; }
inline void temp_end(Temp temp) { arena_pop_to(temp.arena, temp.pos); }
////////////////////////////////
// Push helper macros
#define push_array(arena, T, count) ((T *)arena_push((arena), sizeof(T) * (count)))
#define push_array_no_zero(arena, T, count) ((T *)arena_push_no_zero((arena), sizeof(T) * (count)))

176
src/base/base_core.h Normal file
View File

@@ -0,0 +1,176 @@
#pragma once
// base_core.h - Fundamental types, macros, and linked list helpers
// Inspired by raddebugger's base_core.h
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
////////////////////////////////
// Codebase keywords
#define internal static
#define global static
#define local_persist static
////////////////////////////////
// Base types
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef S32 B32;
typedef float F32;
typedef double F64;
////////////////////////////////
// Limits
#define max_U8 0xFF
#define max_U16 0xFFFF
#define max_U32 0xFFFFFFFF
#define max_U64 0xFFFFFFFFFFFFFFFFull
#define max_S8 0x7F
#define max_S16 0x7FFF
#define max_S32 0x7FFFFFFF
#define max_S64 0x7FFFFFFFFFFFFFFFll
////////////////////////////////
// Units
#define KB(n) (((U64)(n)) << 10)
#define MB(n) (((U64)(n)) << 20)
#define GB(n) (((U64)(n)) << 30)
////////////////////////////////
// Clamps, Mins, Maxes
#define Min(A, B) (((A) < (B)) ? (A) : (B))
#define Max(A, B) (((A) > (B)) ? (A) : (B))
#define ClampTop(A, X) Min(A, X)
#define ClampBot(X, B) Max(X, B)
#define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) : (X))
////////////////////////////////
// Alignment / Sizing
#define AlignPow2(x, b) (((x) + (b) - 1) & (~((b) - 1)))
#define AlignDownPow2(x, b) ((x) & (~((b) - 1)))
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
////////////////////////////////
// Memory macros
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
#define MemoryZero(s, z) memset((s), 0, (z))
#define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s)))
#define MemoryZeroArray(a) MemoryZero((a), sizeof(a))
#define MemoryMatch(a, b, z) (MemoryCompare((a), (b), (z)) == 0)
////////////////////////////////
// Pointer / integer casts
#define IntFromPtr(ptr) ((U64)(ptr))
#define PtrFromInt(i) (void *)(i)
#define OffsetOf(T, m) IntFromPtr(&(((T *)0)->m))
////////////////////////////////
// Member access
#define CastFromMember(T, m, ptr) (T *)(((U8 *)(ptr)) - OffsetOf(T, m))
////////////////////////////////
// For-Loop construct macros
#define DeferLoop(begin, end) for (int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
#define DeferLoopChecked(begin, end) for (int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
#define EachIndex(it, count) (U64 it = 0; it < (count); it += 1)
#define EachElement(it, array) (U64 it = 0; it < ArrayCount(array); it += 1)
////////////////////////////////
// Glue / Stringify
#define Stringify_(S) #S
#define Stringify(S) Stringify_(S)
#define Glue_(A, B) A##B
#define Glue(A, B) Glue_(A, B)
#define Swap(T, a, b) do { T t__ = a; a = b; b = t__; } while (0)
////////////////////////////////
// Assert
#if defined(_MSC_VER)
# define Trap() __debugbreak()
#elif defined(__clang__) || defined(__GNUC__)
# define Trap() __builtin_trap()
#else
# define Trap() (*(volatile int *)0 = 0)
#endif
#define AssertAlways(x) do { if (!(x)) { Trap(); } } while (0)
#ifdef _DEBUG
# define Assert(x) AssertAlways(x)
#else
# define Assert(x) (void)(x)
#endif
#define InvalidPath Assert(!"Invalid Path!")
#define NotImplemented Assert(!"Not Implemented!")
////////////////////////////////
// Linked list macros
// Nil-aware doubly-linked-list operations
#define CheckNil(nil, p) ((p) == 0 || (p) == nil)
#define SetNil(nil, p) ((p) = nil)
// Doubly-linked-list (with nil support)
#define DLLInsert_NPZ(nil, f, l, p, n, next, prev) \
(CheckNil(nil, f) ? \
((f) = (l) = (n), SetNil(nil, (n)->next), SetNil(nil, (n)->prev)) : \
CheckNil(nil, p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil, (n)->prev)) : \
((p) == (l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) : \
(((!CheckNil(nil, p) && CheckNil(nil, (p)->next)) ? (0) : ((p)->next->prev = (n))), \
((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
#define DLLPushBack_NPZ(nil, f, l, n, next, prev) DLLInsert_NPZ(nil, f, l, l, n, next, prev)
#define DLLPushFront_NPZ(nil, f, l, n, next, prev) DLLInsert_NPZ(nil, l, f, f, n, prev, next)
#define DLLRemove_NPZ(nil, f, l, n, next, prev) \
(((n) == (f) ? (f) = (n)->next : (0)), \
((n) == (l) ? (l) = (l)->prev : (0)), \
(CheckNil(nil, (n)->prev) ? (0) : ((n)->prev->next = (n)->next)), \
(CheckNil(nil, (n)->next) ? (0) : ((n)->next->prev = (n)->prev)))
// Convenience wrappers using 0 as nil
#define DLLPushBack(f, l, n) DLLPushBack_NPZ(0, f, l, n, next, prev)
#define DLLPushFront(f, l, n) DLLPushFront_NPZ(0, f, l, n, next, prev)
#define DLLRemove(f, l, n) DLLRemove_NPZ(0, f, l, n, next, prev)
// Singly-linked queue (doubly-headed)
#define SLLQueuePush_NZ(nil, f, l, n, next) \
(CheckNil(nil, f) ? \
((f) = (l) = (n), SetNil(nil, (n)->next)) : \
((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
#define SLLQueuePush(f, l, n) SLLQueuePush_NZ(0, f, l, n, next)
#define SLLQueuePushFront(f, l, n) (((n)->next = (f)), ((f) = (n)))
#define SLLQueuePop(f, l) ((f) == (l) ? ((f) = 0, (l) = 0) : ((f) = (f)->next))
// Singly-linked stack
#define SLLStackPush(f, n) ((n)->next = (f), (f) = (n))
#define SLLStackPop(f) ((f) = (f)->next)

3
src/base/base_inc.cpp Normal file
View File

@@ -0,0 +1,3 @@
// base_inc.cpp - Unity build for the base layer
#include "base/base_arena.cpp"
#include "base/base_strings.cpp"

8
src/base/base_inc.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
// base_inc.h - Umbrella include for the base layer
// Include this one header to get all base types.
#include "base/base_core.h"
#include "base/base_arena.h"
#include "base/base_math.h"
#include "base/base_strings.h"

110
src/base/base_math.h Normal file
View File

@@ -0,0 +1,110 @@
#pragma once
// base_math.h - Vector, range, and color types
// Inspired by raddebugger's base_math.h
#include "base/base_core.h"
////////////////////////////////
// Axis enum
enum Axis2 {
Axis2_X = 0,
Axis2_Y = 1,
Axis2_COUNT,
};
enum Side {
Side_Min = 0,
Side_Max = 1,
Side_COUNT,
};
enum Corner {
Corner_00 = 0, // top-left
Corner_01 = 1, // top-right
Corner_10 = 2, // bottom-left
Corner_11 = 3, // bottom-right
Corner_COUNT,
};
////////////////////////////////
// Vector types
struct Vec2F32 { F32 x, y; };
struct Vec2S32 { S32 x, y; };
struct Vec3F32 { F32 x, y, z; };
struct Vec4F32 { F32 x, y, z, w; };
////////////////////////////////
// Range types
struct Rng1F32 { F32 min, max; };
struct Rng1S64 { S64 min, max; };
struct Rng2F32 { Vec2F32 p0, p1; };
////////////////////////////////
// Constructors
static inline Vec2F32 v2f32(F32 x, F32 y) { return {x, y}; }
static inline Vec2S32 v2s32(S32 x, S32 y) { return {x, y}; }
static inline Vec3F32 v3f32(F32 x, F32 y, F32 z) { return {x, y, z}; }
static inline Vec4F32 v4f32(F32 x, F32 y, F32 z, F32 w) { return {x, y, z, w}; }
static inline Rng1F32 rng1f32(F32 min, F32 max) { return {min, max}; }
static inline Rng1S64 rng1s64(S64 min, S64 max) { return {min, max}; }
static inline Rng2F32 rng2f32(Vec2F32 p0, Vec2F32 p1) { return {p0, p1}; }
static inline Rng2F32 rng2f32p(F32 x0, F32 y0, F32 x1, F32 y1) { return {{x0, y0}, {x1, y1}}; }
////////////////////////////////
// Vec2F32 operations
static inline Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b) { return {a.x + b.x, a.y + b.y}; }
static inline Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b) { return {a.x - b.x, a.y - b.y}; }
static inline Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b) { return {a.x * b.x, a.y * b.y}; }
static inline Vec2F32 scale_2f32(Vec2F32 v, F32 s) { return {v.x * s, v.y * s}; }
// Axis-indexed access
static inline F32 v2f32_axis(Vec2F32 v, Axis2 a) { return a == Axis2_X ? v.x : v.y; }
static inline void v2f32_set_axis(Vec2F32 *v, Axis2 a, F32 val) {
if (a == Axis2_X) v->x = val; else v->y = val;
}
////////////////////////////////
// Vec4F32 operations
static inline Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b) { return {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; }
static inline Vec4F32 scale_4f32(Vec4F32 v, F32 s) { return {v.x*s, v.y*s, v.z*s, v.w*s}; }
static inline Vec4F32 lerp_4f32(Vec4F32 a, Vec4F32 b, F32 t) {
return {a.x + (b.x - a.x)*t, a.y + (b.y - a.y)*t, a.z + (b.z - a.z)*t, a.w + (b.w - a.w)*t};
}
////////////////////////////////
// Rng2F32 operations
static inline F32 rng2f32_width(Rng2F32 r) { return r.p1.x - r.p0.x; }
static inline F32 rng2f32_height(Rng2F32 r) { return r.p1.y - r.p0.y; }
static inline Vec2F32 rng2f32_dim(Rng2F32 r) { return {r.p1.x - r.p0.x, r.p1.y - r.p0.y}; }
static inline Vec2F32 rng2f32_center(Rng2F32 r) { return {(r.p0.x + r.p1.x)*0.5f, (r.p0.y + r.p1.y)*0.5f}; }
static inline B32 rng2f32_contains(Rng2F32 r, Vec2F32 p) {
return p.x >= r.p0.x && p.x <= r.p1.x && p.y >= r.p0.y && p.y <= r.p1.y;
}
static inline Rng2F32 rng2f32_pad(Rng2F32 r, F32 p) {
return {{r.p0.x - p, r.p0.y - p}, {r.p1.x + p, r.p1.y + p}};
}
static inline Rng2F32 rng2f32_shift(Rng2F32 r, Vec2F32 v) {
return {{r.p0.x + v.x, r.p0.y + v.y}, {r.p1.x + v.x, r.p1.y + v.y}};
}
static inline Rng2F32 rng2f32_intersect(Rng2F32 a, Rng2F32 b) {
return {{Max(a.p0.x, b.p0.x), Max(a.p0.y, b.p0.y)},
{Min(a.p1.x, b.p1.x), Min(a.p1.y, b.p1.y)}};
}
// Axis-indexed range dimension
static inline F32 rng2f32_dim_axis(Rng2F32 r, Axis2 a) {
return a == Axis2_X ? (r.p1.x - r.p0.x) : (r.p1.y - r.p0.y);
}
////////////////////////////////
// F32 helpers
static inline F32 lerp_1f32(F32 a, F32 b, F32 t) { return a + (b - a) * t; }
static inline F32 abs_f32(F32 x) { return x < 0 ? -x : x; }

32
src/base/base_strings.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include "base/base_strings.h"
#include "base/base_arena.h"
Str8 str8_pushf(Arena *arena, const char *fmt, ...) {
va_list args, args2;
va_start(args, fmt);
va_copy(args2, args);
int len = vsnprintf(nullptr, 0, fmt, args);
va_end(args);
char *buf = push_array(arena, char, len + 1);
vsnprintf(buf, len + 1, fmt, args2);
va_end(args2);
return {buf, (U64)len};
}
Str8 str8_push_copy(Arena *arena, Str8 s) {
if (s.size == 0 || !s.str) return {nullptr, 0};
char *buf = push_array_no_zero(arena, char, s.size + 1);
MemoryCopy(buf, s.str, s.size);
buf[s.size] = 0;
return {buf, s.size};
}
void str8_list_push(Arena *arena, Str8List *list, Str8 s) {
Str8Node *node = push_array(arena, Str8Node, 1);
node->string = s;
SLLQueuePush(list->first, list->last, node);
list->count++;
list->total_size += s.size;
}

49
src/base/base_strings.h Normal file
View File

@@ -0,0 +1,49 @@
#pragma once
// base_strings.h - Simple length-delimited string type
// Inspired by raddebugger's String8
#include "base/base_core.h"
////////////////////////////////
// String types
struct Str8 {
const char *str;
U64 size;
};
struct Str8Node {
Str8Node *next;
Str8 string;
};
struct Str8List {
Str8Node *first;
Str8Node *last;
U64 count;
U64 total_size;
};
////////////////////////////////
// Forward declaration for Arena
struct Arena;
////////////////////////////////
// Constructors
static inline Str8 str8(const char *s, U64 len) { return {s, len}; }
static inline Str8 str8_cstr(const char *s) { return {s, s ? (U64)strlen(s) : 0}; }
static inline Str8 str8_lit(const char *s) { return {s, s ? (U64)strlen(s) : 0}; }
static inline B32 str8_match(Str8 a, Str8 b) {
if (a.size != b.size) return 0;
return MemoryCompare(a.str, b.str, a.size) == 0;
}
static inline B32 str8_is_empty(Str8 s) { return s.size == 0 || s.str == nullptr; }
////////////////////////////////
// String operations (require arena)
Str8 str8_pushf(Arena *arena, const char *fmt, ...);
Str8 str8_push_copy(Arena *arena, Str8 s);
void str8_list_push(Arena *arena, Str8List *list, Str8 s);

View File

@@ -1,44 +1,460 @@
// Unity build - include all src files here
// -mta
// [h]
#include "base/base_inc.h"
#include "platform/platform.h"
#include "renderer/renderer.h"
#include "midi/midi.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <iostream>
#include "ui/ui_core.h"
#include "ui/ui_widgets.h"
// [cpp]
#include "base/base_inc.cpp"
#include "ui/ui_core.cpp"
#include "ui/ui_widgets.cpp"
#include "platform/platform_win32.cpp"
#include "renderer/renderer_dx12.cpp"
#include "midi/midi_win32.cpp"
#include "menus.cpp"
#include "theme.cpp"
////////////////////////////////
// Win32 input gathering
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);
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
ImGuiID center = dockspace_id;
ImGuiID left = ImGui::DockBuilderSplitNode(center, ImGuiDir_Left, 0.15f, nullptr, &center);
ImGuiID right = ImGui::DockBuilderSplitNode(center, ImGuiDir_Right, 0.20f, nullptr, &center);
ImGuiID bottom = ImGui::DockBuilderSplitNode(center, ImGuiDir_Down, 0.25f, nullptr, &center);
struct InputState {
Vec2F32 mouse;
Vec2F32 scroll_delta;
B32 mouse_down;
B32 was_mouse_down;
};
ImGui::DockBuilderDockWindow("Browser", left);
ImGui::DockBuilderDockWindow("Main", center);
ImGui::DockBuilderDockWindow("Properties", right);
ImGui::DockBuilderDockWindow("MIDI Devices", right);
ImGui::DockBuilderDockWindow("Log", bottom);
static InputState g_input;
ImGui::DockBuilderFinish(dockspace_id);
static void input_gather(void *window_handle) {
HWND hwnd = (HWND)window_handle;
// Mouse position
POINT cursor;
GetCursorPos(&cursor);
ScreenToClient(hwnd, &cursor);
g_input.mouse = v2f32((F32)cursor.x, (F32)cursor.y);
// Mouse button
g_input.was_mouse_down = g_input.mouse_down;
g_input.mouse_down = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
// Scroll (TODO: hook WM_MOUSEWHEEL for real scroll deltas)
g_input.scroll_delta = v2f32(0, 0);
}
////////////////////////////////
// Clay text config helpers
static Clay_TextElementConfig g_text_config_normal;
static Clay_TextElementConfig g_text_config_title;
static Clay_TextElementConfig g_text_config_dim;
static void init_text_configs() {
g_text_config_normal = {};
g_text_config_normal.textColor = g_theme.text;
g_text_config_normal.fontSize = 15;
g_text_config_normal.wrapMode = CLAY_TEXT_WRAP_NONE;
g_text_config_title = {};
g_text_config_title.textColor = g_theme.text;
g_text_config_title.fontSize = 15;
g_text_config_title.wrapMode = CLAY_TEXT_WRAP_NONE;
g_text_config_dim = {};
g_text_config_dim.textColor = g_theme.text_dim;
g_text_config_dim.fontSize = 15;
g_text_config_dim.wrapMode = CLAY_TEXT_WRAP_NONE;
}
////////////////////////////////
// App state — all mutable state the frame function needs
struct AppState {
PlatformWindow *window;
Renderer *renderer;
MidiEngine *midi;
UI_Context *ui;
S32 last_w, last_h;
B32 show_browser;
B32 show_props;
B32 show_log;
B32 show_midi_devices;
LARGE_INTEGER freq;
LARGE_INTEGER last_time;
// Demo widget state
B32 demo_checkbox_a;
B32 demo_checkbox_b;
int32_t demo_radio_sel;
int32_t demo_dropdown_sel;
char demo_text_a[128];
char demo_text_b[128];
int32_t demo_button_count;
};
////////////////////////////////
// Panel builders
static void build_panel_title_bar(Clay_ElementId id, Clay_String title) {
CLAY(id,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(24) },
.padding = { 8, 8, 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.title_bar,
.border = { .color = g_theme.border, .width = { .bottom = 1 } }
) {
CLAY_TEXT(title, &g_text_config_title);
}
}
static void build_browser_panel(B32 show) {
if (!show) return;
CLAY(CLAY_ID("BrowserPanel"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(200), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_medium,
.border = { .color = g_theme.border, .width = { .right = 1 } }
) {
build_panel_title_bar(CLAY_ID("BrowserTitleBar"), CLAY_STRING("Browser"));
CLAY(CLAY_ID("BrowserContent"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.padding = { 8, 8, 6, 6 },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
CLAY_TEXT(CLAY_STRING("Instruments"), &g_text_config_normal);
}
}
}
static void build_main_panel(AppState *app) {
CLAY(CLAY_ID("MainPanel"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_light
) {
build_panel_title_bar(CLAY_ID("MainTitleBar"), CLAY_STRING("Main"));
CLAY(CLAY_ID("MainContent"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.padding = { 16, 16, 12, 12 },
.childGap = 12,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
// Section: Buttons
ui_label("LblButtons", "Buttons");
CLAY(CLAY_ID("ButtonRow"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = 8,
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
) {
if (ui_button("BtnHello", "Click Me")) {
app->demo_button_count++;
}
if (ui_button("BtnReset", "Reset")) {
app->demo_button_count = 0;
}
}
// Show click count
static char btn_count_buf[64];
snprintf(btn_count_buf, sizeof(btn_count_buf), "Button clicked %d times", app->demo_button_count);
ui_label("LblBtnCount", btn_count_buf);
// Separator
CLAY(CLAY_ID("Sep1"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border
) {}
// Section: Checkboxes
ui_label("LblCheckboxes", "Checkboxes");
ui_checkbox("ChkA", "Enable feature A", &app->demo_checkbox_a);
ui_checkbox("ChkB", "Enable feature B", &app->demo_checkbox_b);
CLAY(CLAY_ID("Sep2"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border
) {}
// Section: Radio buttons
ui_label("LblRadio", "Output Format");
static const char *radio_options[] = { "WAV", "AIFF", "FLAC" };
ui_radio_group("RadioFmt", radio_options, 3, &app->demo_radio_sel);
CLAY(CLAY_ID("Sep3"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border
) {}
// Section: Text inputs
ui_label("LblText", "Text Inputs");
CLAY(CLAY_ID("TextRow"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.childGap = 8,
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
) {
CLAY(CLAY_ID("TextCol1"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
ui_label("LblName", "Name:");
ui_text_input("TxtName", app->demo_text_a, sizeof(app->demo_text_a));
}
CLAY(CLAY_ID("TextCol2"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
ui_label("LblPath", "Output Path:");
ui_text_input("TxtPath", app->demo_text_b, sizeof(app->demo_text_b));
}
}
CLAY(CLAY_ID("Sep4"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border
) {}
// Section: Dropdown
ui_label("LblDropdown", "Sample Rate");
CLAY(CLAY_ID("DropdownWrapper"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(200), .height = CLAY_SIZING_FIT() },
}
) {
static const char *rate_options[] = { "44100 Hz", "48000 Hz", "88200 Hz", "96000 Hz", "192000 Hz" };
ui_dropdown("DropRate", rate_options, 5, &app->demo_dropdown_sel);
}
}
}
}
static void build_properties_panel(B32 show) {
if (!show) return;
CLAY(CLAY_ID("PropertiesPanel"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_medium,
.border = { .color = g_theme.border, .width = { .bottom = 1 } }
) {
build_panel_title_bar(CLAY_ID("PropertiesTitleBar"), CLAY_STRING("Properties"));
CLAY(CLAY_ID("PropertiesContent"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.padding = { 8, 8, 6, 6 },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
CLAY_TEXT(CLAY_STRING("Details"), &g_text_config_normal);
}
}
}
static void build_midi_panel(B32 show, MidiEngine *midi) {
if (!show) return;
CLAY(CLAY_ID("MidiPanel"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_medium
) {
build_panel_title_bar(CLAY_ID("MidiTitleBar"), CLAY_STRING("MIDI Devices"));
CLAY(CLAY_ID("MidiContent"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.padding = { 8, 8, 6, 6 },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
// Refresh button
CLAY(CLAY_ID("MidiRefreshBtn"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(28) },
.padding = { 12, 12, 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = Clay_Hovered() ? g_theme.accent_hover : g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(3)
) {
CLAY_TEXT(CLAY_STRING("Refresh"), &g_text_config_normal);
}
// Device list - use static buffers so strings persist for Clay rendering
static char device_bufs[64][128];
int32_t device_count = midi_get_device_count(midi);
for (int32_t i = 0; i < device_count && i < 64; i++) {
MidiDeviceInfo *dev = midi_get_device(midi, i);
int len = snprintf(device_bufs[i], sizeof(device_bufs[i]), "[%s] %s", dev->is_input ? "IN" : "OUT", dev->name);
Clay_String device_str = { .isStaticallyAllocated = false, .length = len, .chars = device_bufs[i] };
CLAY(CLAY_IDI("MidiDevice", i),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.padding = { 4, 4, 2, 2 },
}
) {
CLAY_TEXT(device_str, &g_text_config_normal);
}
}
if (device_count == 0) {
CLAY_TEXT(CLAY_STRING("No MIDI devices found"), &g_text_config_dim);
}
}
}
}
static void build_log_panel(B32 show) {
if (!show) return;
CLAY(CLAY_ID("LogPanel"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(180) },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_medium,
.border = { .color = g_theme.border, .width = { .top = 1 } }
) {
build_panel_title_bar(CLAY_ID("LogTitleBar"), CLAY_STRING("Log"));
CLAY(CLAY_ID("LogContent"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.padding = { 8, 8, 6, 6 },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
CLAY_TEXT(CLAY_STRING("Output / Log"), &g_text_config_normal);
}
}
}
////////////////////////////////
// Build the full UI layout for one frame
static void build_ui(AppState *app) {
CLAY(CLAY_ID("Root"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
// Top row: browser | main | right column
CLAY(CLAY_ID("TopRow"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
) {
build_browser_panel(app->show_browser);
build_main_panel(app);
if (app->show_props || app->show_midi_devices) {
CLAY(CLAY_ID("RightColumn"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.border = { .color = g_theme.border, .width = { .left = 1 } }
) {
build_properties_panel(app->show_props);
build_midi_panel(app->show_midi_devices, app->midi);
}
}
}
build_log_panel(app->show_log);
}
}
////////////////////////////////
// Render one frame: resize if needed, build UI, submit to GPU.
// Called from the main loop and from WM_SIZE during live resize.
static void do_frame(AppState *app) {
// Timing
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
F32 dt = (F32)(now.QuadPart - app->last_time.QuadPart) / (F32)app->freq.QuadPart;
app->last_time = now;
if (dt > 0.1f) dt = 0.1f;
// Resize
S32 w, h;
platform_get_size(app->window, &w, &h);
if (w != app->last_w || h != app->last_h) {
renderer_resize(app->renderer, w, h);
app->last_w = w;
app->last_h = h;
}
if (!renderer_begin_frame(app->renderer))
return;
// Gather input
input_gather(platform_get_native_handle(app->window));
PlatformInputEvents input_events = platform_get_input_events(app->window);
ui_widgets_begin_frame(input_events, g_input.mouse_down, g_input.was_mouse_down);
// Build UI with Clay
ui_begin_frame(app->ui, (F32)w, (F32)h, g_input.mouse, g_input.mouse_down,
g_input.scroll_delta, dt);
build_ui(app);
Clay_RenderCommandArray render_commands = ui_end_frame(app->ui);
// Render
renderer_end_frame(app->renderer, render_commands);
}
////////////////////////////////
// Platform frame callback for live resize
static void frame_callback(void *user_data) {
do_frame((AppState *)user_data);
}
////////////////////////////////
// Entry point
int main(int argc, char **argv) {
std::cout << "Hello" << std::endl;
(void)argc;
(void)argv;
@@ -47,7 +463,7 @@ int main(int argc, char **argv) {
if (!window)
return 1;
int32_t w, h;
S32 w, h;
platform_get_size(window, &w, &h);
RendererDesc renderer_desc = {};
@@ -62,99 +478,52 @@ int main(int argc, char **argv) {
MidiEngine *midi = midi_create();
setup_theme();
setup_menus(window);
// Initialize UI (Clay)
ui_init_theme();
UI_Context *ui = ui_create((F32)w, (F32)h);
ui_set_measure_text_fn(ui, renderer_measure_text, renderer);
init_text_configs();
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 show_midi_devices = true;
bool first_frame = true;
setup_menus(window);
ui_widgets_init();
AppState app = {};
app.window = window;
app.renderer = renderer;
app.midi = midi;
app.ui = ui;
app.last_w = w;
app.last_h = h;
app.show_browser = 1;
app.show_props = 1;
app.show_log = 1;
app.show_midi_devices = 1;
app.demo_dropdown_sel = 1; // default to 48000 Hz
snprintf(app.demo_text_a, sizeof(app.demo_text_a), "My Instrument");
snprintf(app.demo_text_b, sizeof(app.demo_text_b), "C:\\Samples\\output");
QueryPerformanceFrequency(&app.freq);
QueryPerformanceCounter(&app.last_time);
platform_set_frame_callback(window, frame_callback, &app);
while (platform_poll_events(window)) {
// Menu commands
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;
case MENU_VIEW_MIDI_DEVICES: show_midi_devices = !show_midi_devices; break;
case MENU_FILE_EXIT: goto exit_app;
case MENU_VIEW_BROWSER: app.show_browser = !app.show_browser; break;
case MENU_VIEW_PROPERTIES:app.show_props = !app.show_props; break;
case MENU_VIEW_LOG: app.show_log = !app.show_log; break;
case MENU_VIEW_MIDI_DEVICES: app.show_midi_devices = !app.show_midi_devices; 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();
}
// MIDI Devices panel
if (show_midi_devices) {
ImGui::Begin("MIDI Devices", &show_midi_devices);
if (ImGui::Button("Refresh"))
midi_refresh_devices(midi);
ImGui::Separator();
for (int32_t i = 0; i < midi_get_device_count(midi); i++) {
MidiDeviceInfo *dev = midi_get_device(midi, i);
ImGui::Text("[%s] %s", dev->is_input ? "IN" : "OUT", dev->name);
}
if (midi_get_device_count(midi) == 0)
ImGui::TextDisabled("No MIDI devices found");
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);
do_frame(&app);
}
exit_app:
midi_destroy(midi);
ui_destroy(ui);
renderer_destroy(renderer);
platform_destroy_window(window);
return 0;

View File

@@ -3,6 +3,46 @@
#include <stdint.h>
#include <stdbool.h>
////////////////////////////////
// Input event buffer
// Accumulated per frame, consumed by the app each tick.
#define PLATFORM_MAX_CHARS_PER_FRAME 64
#define PLATFORM_MAX_KEYS_PER_FRAME 32
// Virtual key codes (subset matching Win32 VK_ codes)
enum {
PKEY_BACKSPACE = 0x08,
PKEY_TAB = 0x09,
PKEY_RETURN = 0x0D,
PKEY_ESCAPE = 0x1B,
PKEY_DELETE = 0x2E,
PKEY_LEFT = 0x25,
PKEY_UP = 0x26,
PKEY_RIGHT = 0x27,
PKEY_DOWN = 0x28,
PKEY_HOME = 0x24,
PKEY_END = 0x23,
PKEY_A = 0x41,
PKEY_C = 0x43,
PKEY_V = 0x56,
PKEY_X = 0x58,
};
struct PlatformInputEvents {
// Typed characters (UTF-16 code units, printable only)
uint16_t chars[PLATFORM_MAX_CHARS_PER_FRAME];
int32_t char_count;
// Key-down events (virtual key codes)
uint8_t keys[PLATFORM_MAX_KEYS_PER_FRAME];
int32_t key_count;
// Modifier state at time of last key event
bool ctrl_held;
bool shift_held;
};
struct PlatformWindow;
struct PlatformWindowDesc {
@@ -22,11 +62,26 @@ struct PlatformMenu {
int32_t item_count;
};
// Called by the platform layer when the window needs a frame rendered
// (e.g., during a live resize). user_data is the pointer passed to
// platform_set_frame_callback.
typedef void (*PlatformFrameCallback)(void *user_data);
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_frame_callback(PlatformWindow *window, PlatformFrameCallback cb, void *user_data);
void platform_set_menu(PlatformWindow *window, PlatformMenu *menus, int32_t menu_count);
int32_t platform_poll_menu_command(PlatformWindow *window);
// Returns accumulated input events since last call, then clears the buffer.
PlatformInputEvents platform_get_input_events(PlatformWindow *window);
// Clipboard operations (null-terminated UTF-8 strings).
// platform_clipboard_set copies text to the system clipboard.
// platform_clipboard_get returns a pointer to a static buffer (valid until next call), or nullptr.
void platform_clipboard_set(const char *text);
const char *platform_clipboard_get();

View File

@@ -6,35 +6,62 @@
#include <windows.h>
#include <malloc.h>
#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;
PlatformFrameCallback frame_callback;
void *frame_callback_user_data;
PlatformInputEvents input_events;
};
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);
// Render a frame during the modal resize loop so the UI
// stays responsive instead of showing a stretched image.
if (g_current_window->frame_callback) {
g_current_window->frame_callback(g_current_window->frame_callback_user_data);
}
}
return 0;
case WM_CHAR:
if (g_current_window && wparam >= 32 && wparam < 0xFFFF) {
PlatformInputEvents *ev = &g_current_window->input_events;
if (ev->char_count < PLATFORM_MAX_CHARS_PER_FRAME)
ev->chars[ev->char_count++] = (uint16_t)wparam;
}
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (g_current_window) {
PlatformInputEvents *ev = &g_current_window->input_events;
if (ev->key_count < PLATFORM_MAX_KEYS_PER_FRAME)
ev->keys[ev->key_count++] = (uint8_t)wparam;
ev->ctrl_held = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
ev->shift_held = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
}
break; // fall through to DefWindowProc for system keys
case WM_COMMAND:
if (g_current_window && HIWORD(wparam) == 0)
g_current_window->pending_menu_cmd = (int32_t)LOWORD(wparam);
return 0;
case WM_SETCURSOR:
// When the cursor is in our client area, force it to an arrow.
// Without this, moving from a resize border back into the client
// area would leave the resize cursor shape stuck.
if (LOWORD(lparam) == HTCLIENT) {
SetCursor(LoadCursor(nullptr, IDC_ARROW));
return TRUE;
}
break;
case WM_CLOSE:
if (g_current_window)
g_current_window->should_close = true;
@@ -56,6 +83,7 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
wc.style = CS_CLASSDC;
wc.lpfnWndProc = win32_wndproc;
wc.hInstance = GetModuleHandleW(nullptr);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.lpszClassName = L"autosample_wc";
RegisterClassExW(&wc);
@@ -133,6 +161,11 @@ void *platform_get_native_handle(PlatformWindow *window) {
return (void *)window->hwnd;
}
void platform_set_frame_callback(PlatformWindow *window, PlatformFrameCallback cb, void *user_data) {
window->frame_callback = cb;
window->frame_callback_user_data = user_data;
}
void platform_set_menu(PlatformWindow *window, PlatformMenu *menus, int32_t menu_count) {
HMENU menu_bar = CreateMenu();
@@ -167,3 +200,57 @@ int32_t platform_poll_menu_command(PlatformWindow *window) {
window->pending_menu_cmd = 0;
return cmd;
}
PlatformInputEvents platform_get_input_events(PlatformWindow *window) {
PlatformInputEvents result = window->input_events;
window->input_events = {};
return result;
}
void platform_clipboard_set(const char *text) {
if (!text) return;
int len = (int)strlen(text);
if (len == 0) return;
// Convert UTF-8 to wide string for Windows clipboard
int wlen = MultiByteToWideChar(CP_UTF8, 0, text, len, nullptr, 0);
if (wlen == 0) return;
HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, (wlen + 1) * sizeof(wchar_t));
if (!hmem) return;
wchar_t *wbuf = (wchar_t *)GlobalLock(hmem);
MultiByteToWideChar(CP_UTF8, 0, text, len, wbuf, wlen);
wbuf[wlen] = L'\0';
GlobalUnlock(hmem);
HWND hwnd = g_current_window ? g_current_window->hwnd : nullptr;
if (OpenClipboard(hwnd)) {
EmptyClipboard();
SetClipboardData(CF_UNICODETEXT, hmem);
CloseClipboard();
} else {
GlobalFree(hmem);
}
}
const char *platform_clipboard_get() {
static char buf[4096];
buf[0] = '\0';
HWND hwnd = g_current_window ? g_current_window->hwnd : nullptr;
if (!OpenClipboard(hwnd)) return nullptr;
HGLOBAL hmem = GetClipboardData(CF_UNICODETEXT);
if (hmem) {
wchar_t *wbuf = (wchar_t *)GlobalLock(hmem);
if (wbuf) {
int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, sizeof(buf) - 1, nullptr, nullptr);
buf[len > 0 ? len - 1 : 0] = '\0'; // WideCharToMultiByte includes null in count
GlobalUnlock(hmem);
}
}
CloseClipboard();
return buf[0] ? buf : nullptr;
}

View File

@@ -4,6 +4,7 @@
#include <stdbool.h>
struct Renderer;
struct Clay_RenderCommandArray;
struct RendererDesc {
void *window_handle = nullptr;
@@ -15,5 +16,11 @@ struct RendererDesc {
Renderer *renderer_create(RendererDesc *desc);
void renderer_destroy(Renderer *renderer);
bool renderer_begin_frame(Renderer *renderer);
void renderer_end_frame(Renderer *renderer);
void renderer_end_frame(Renderer *renderer, Clay_RenderCommandArray render_commands);
void renderer_resize(Renderer *renderer, int32_t width, int32_t height);
// Text measurement callback compatible with UI_MeasureTextFn
// Measures text of given length (NOT necessarily null-terminated) at font_size pixels.
// user_data should be the Renderer pointer.
struct Vec2F32;
Vec2F32 renderer_measure_text(const char *text, int32_t length, float font_size, void *user_data);

File diff suppressed because it is too large Load Diff

View File

@@ -1,104 +0,0 @@
#include "imgui.h"
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);
}

107
src/ui/ui_core.cpp Normal file
View File

@@ -0,0 +1,107 @@
// ui_core.cpp - Clay wrapper implementation
// CLAY_IMPLEMENTATION must be defined exactly once before including clay.h.
// In the unity build, ui_core.h (which includes clay.h) has #pragma once,
// so we include clay.h directly here first to get the implementation compiled.
#include <stdlib.h>
#define CLAY_IMPLEMENTATION
#include "clay.h"
#include "ui/ui_core.h"
////////////////////////////////
// Theme global
UI_Theme g_theme = {};
void ui_init_theme() {
g_theme.bg_dark = Clay_Color{ 30, 30, 33, 255};
g_theme.bg_medium = Clay_Color{ 41, 41, 43, 255};
g_theme.bg_light = Clay_Color{ 51, 51, 56, 255};
g_theme.bg_lighter = Clay_Color{ 56, 56, 61, 255};
g_theme.border = Clay_Color{ 56, 56, 61, 255};
g_theme.text = Clay_Color{224, 224, 224, 255};
g_theme.text_dim = Clay_Color{112, 112, 112, 255};
g_theme.accent = Clay_Color{ 87, 138, 176, 255};
g_theme.accent_hover = Clay_Color{102, 153, 191, 255};
g_theme.title_bar = Clay_Color{ 26, 26, 28, 255};
g_theme.scrollbar_bg = Clay_Color{ 26, 26, 28, 255};
g_theme.scrollbar_grab= Clay_Color{ 61, 61, 66, 255};
}
////////////////////////////////
// Clay error handler
static void clay_error_handler(Clay_ErrorData error) {
char buf[512];
int len = error.errorText.length < 511 ? error.errorText.length : 511;
memcpy(buf, error.errorText.chars, len);
buf[len] = '\0';
fprintf(stderr, "[Clay Error] %s\n", buf);
}
////////////////////////////////
// Clay text measurement bridge
// Clay calls this; we forward to the app's UI_MeasureTextFn
static UI_Context *g_measure_ctx = nullptr;
static Clay_Dimensions clay_measure_text(Clay_StringSlice text, Clay_TextElementConfig *config, void *user_data) {
UI_Context *ctx = (UI_Context *)user_data;
if (!ctx || !ctx->measure_text_fn || text.length == 0) {
return Clay_Dimensions{0, (float)config->fontSize};
}
Vec2F32 result = ctx->measure_text_fn(text.chars, text.length, (F32)config->fontSize, ctx->measure_text_user_data);
return Clay_Dimensions{result.x, result.y};
}
////////////////////////////////
// Lifecycle
UI_Context *ui_create(F32 viewport_w, F32 viewport_h) {
UI_Context *ctx = (UI_Context *)calloc(1, sizeof(UI_Context));
uint32_t min_memory = Clay_MinMemorySize();
ctx->clay_memory = malloc(min_memory);
Clay_Arena clay_arena = Clay_CreateArenaWithCapacityAndMemory(min_memory, ctx->clay_memory);
Clay_ErrorHandler err_handler = {};
err_handler.errorHandlerFunction = clay_error_handler;
err_handler.userData = ctx;
ctx->clay_ctx = Clay_Initialize(clay_arena,
Clay_Dimensions{viewport_w, viewport_h},
err_handler);
Clay_SetMeasureTextFunction(clay_measure_text, ctx);
return ctx;
}
void ui_destroy(UI_Context *ctx) {
if (!ctx) return;
free(ctx->clay_memory);
free(ctx);
}
void ui_begin_frame(UI_Context *ctx, F32 viewport_w, F32 viewport_h,
Vec2F32 mouse_pos, B32 mouse_down,
Vec2F32 scroll_delta, F32 dt)
{
Clay_SetCurrentContext(ctx->clay_ctx);
Clay_SetLayoutDimensions(Clay_Dimensions{viewport_w, viewport_h});
Clay_SetPointerState(Clay_Vector2{mouse_pos.x, mouse_pos.y}, mouse_down != 0);
Clay_UpdateScrollContainers(true, Clay_Vector2{scroll_delta.x, scroll_delta.y}, dt);
Clay_BeginLayout();
}
Clay_RenderCommandArray ui_end_frame(UI_Context *ctx) {
(void)ctx;
return Clay_EndLayout();
}
void ui_set_measure_text_fn(UI_Context *ctx, UI_MeasureTextFn fn, void *user_data) {
ctx->measure_text_fn = fn;
ctx->measure_text_user_data = user_data;
}

65
src/ui/ui_core.h Normal file
View File

@@ -0,0 +1,65 @@
#pragma once
// ui_core.h - Thin wrapper around Clay (https://github.com/nicbarker/clay)
// Provides Clay initialization, per-frame lifecycle, and text measurement bridging.
#include "base/base_inc.h"
#include "clay.h"
////////////////////////////////
// Text measurement callback (provided by renderer)
// This is our app-level callback; we adapt it to Clay's signature internally.
typedef Vec2F32 (*UI_MeasureTextFn)(const char *text, S32 length, F32 font_size, void *user_data);
////////////////////////////////
// UI Context
struct UI_Context {
Clay_Context *clay_ctx;
void *clay_memory;
// Text measurement
UI_MeasureTextFn measure_text_fn;
void *measure_text_user_data;
};
////////////////////////////////
// Lifecycle
UI_Context *ui_create(F32 viewport_w, F32 viewport_h);
void ui_destroy(UI_Context *ctx);
// Call each frame before declaring layout
void ui_begin_frame(UI_Context *ctx, F32 viewport_w, F32 viewport_h,
Vec2F32 mouse_pos, B32 mouse_down,
Vec2F32 scroll_delta, F32 dt);
// Call after layout is declared; returns Clay's render command array
Clay_RenderCommandArray ui_end_frame(UI_Context *ctx);
////////////////////////////////
// Text measurement
void ui_set_measure_text_fn(UI_Context *ctx, UI_MeasureTextFn fn, void *user_data);
////////////////////////////////
// Theme colors (convenience - 0-255 Clay_Color)
struct UI_Theme {
Clay_Color bg_dark;
Clay_Color bg_medium;
Clay_Color bg_light;
Clay_Color bg_lighter;
Clay_Color border;
Clay_Color text;
Clay_Color text_dim;
Clay_Color accent;
Clay_Color accent_hover;
Clay_Color title_bar;
Clay_Color scrollbar_bg;
Clay_Color scrollbar_grab;
};
extern UI_Theme g_theme;
void ui_init_theme();

735
src/ui/ui_widgets.cpp Normal file
View File

@@ -0,0 +1,735 @@
// ui_widgets.cpp - Immediate-mode widget implementations on top of Clay.
//
// IMPORTANT: Clay_Hovered() only works inside CLAY() macro declaration args
// (where the element is the "open" element on the stack). For hover checks
// AFTER a CLAY() block, use Clay_PointerOver(elementId).
#include "ui/ui_widgets.h"
#include <string.h>
#include <stdio.h>
UI_WidgetState g_wstate = {};
void ui_widgets_init() {
g_wstate = {};
}
void ui_widgets_begin_frame(PlatformInputEvents input, B32 mouse_down, B32 was_mouse_down) {
g_wstate.input = input;
g_wstate.was_mouse_down = g_wstate.mouse_down;
g_wstate.mouse_down = mouse_down;
g_wstate.mouse_clicked = (mouse_down && !g_wstate.was_mouse_down);
g_wstate.cursor_blink += 1.0f / 60.0f;
g_wstate.text_input_count = 0;
g_wstate.tab_pressed = 0;
// Detect Tab key press this frame
for (S32 k = 0; k < input.key_count; k++) {
if (input.keys[k] == PKEY_TAB) {
g_wstate.tab_pressed = 1;
break;
}
}
ui_text_input_reset_display_bufs();
}
////////////////////////////////
// Helpers
static Clay_TextElementConfig g_widget_text_config;
static Clay_TextElementConfig g_widget_text_config_dim;
static Clay_TextElementConfig g_widget_text_config_sel;
static bool g_widget_text_configs_init = false;
static void ensure_widget_text_configs() {
if (g_widget_text_configs_init) return;
g_widget_text_configs_init = true;
g_widget_text_config = {};
g_widget_text_config.textColor = g_theme.text;
g_widget_text_config.fontSize = 15;
g_widget_text_config.wrapMode = CLAY_TEXT_WRAP_NONE;
g_widget_text_config_dim = {};
g_widget_text_config_dim.textColor = g_theme.text_dim;
g_widget_text_config_dim.fontSize = 15;
g_widget_text_config_dim.wrapMode = CLAY_TEXT_WRAP_NONE;
// Selected text: white on accent background (background set on parent element)
g_widget_text_config_sel = {};
g_widget_text_config_sel.textColor = Clay_Color{255, 255, 255, 255};
g_widget_text_config_sel.fontSize = 15;
g_widget_text_config_sel.wrapMode = CLAY_TEXT_WRAP_NONE;
}
static Clay_String clay_str(const char *s) {
Clay_String r = {};
r.isStaticallyAllocated = false;
r.length = (S32)strlen(s);
r.chars = s;
return r;
}
// Build Clay_ElementId from runtime string (CLAY_ID requires string literals)
#define WID(s) CLAY_SID(clay_str(s))
#define WIDI(s, i) CLAY_SIDI(clay_str(s), i)
////////////////////////////////
// Label
void ui_label(const char *id, const char *text) {
ensure_widget_text_configs();
CLAY(WID(id),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.padding = { 0, 0, 2, 2 },
}
) {
CLAY_TEXT(clay_str(text), &g_widget_text_config);
}
}
////////////////////////////////
// Button
B32 ui_button(const char *id, const char *text) {
ensure_widget_text_configs();
Clay_ElementId eid = WID(id);
B32 hovered = Clay_PointerOver(eid);
CLAY(eid,
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(30) },
.padding = { 12, 12, 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = hovered ? g_theme.accent_hover : g_theme.accent,
.cornerRadius = CLAY_CORNER_RADIUS(3)
) {
CLAY_TEXT(clay_str(text), &g_widget_text_config);
}
return (hovered && g_wstate.mouse_clicked) ? 1 : 0;
}
////////////////////////////////
// Checkbox
B32 ui_checkbox(const char *id, const char *label, B32 *value) {
ensure_widget_text_configs();
B32 changed = 0;
Clay_ElementId eid = WID(id);
B32 hovered = Clay_PointerOver(eid);
CLAY(eid,
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(28) },
.childGap = 8,
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
) {
// Box
Clay_Color box_bg = *value ? g_theme.accent : g_theme.bg_dark;
if (hovered) {
box_bg = *value ? g_theme.accent_hover : g_theme.bg_lighter;
}
CLAY(WIDI(id, 1),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(18), .height = CLAY_SIZING_FIXED(18) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = box_bg,
.cornerRadius = CLAY_CORNER_RADIUS(3),
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
if (*value) {
CLAY_TEXT(CLAY_STRING("x"), &g_widget_text_config);
}
}
// Label
CLAY_TEXT(clay_str(label), &g_widget_text_config);
}
if (hovered && g_wstate.mouse_clicked) {
*value = !(*value);
changed = 1;
}
return changed;
}
////////////////////////////////
// Radio group
B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selected) {
ensure_widget_text_configs();
B32 changed = 0;
CLAY(WID(id),
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = 4,
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}
) {
for (S32 i = 0; i < count; i++) {
B32 is_selected = (*selected == i);
Clay_ElementId row_id = WIDI(id, i + 100);
B32 row_hovered = Clay_PointerOver(row_id);
CLAY(row_id,
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(26) },
.childGap = 8,
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
) {
// Radio circle
Clay_Color dot_bg = is_selected ? g_theme.accent : g_theme.bg_dark;
if (row_hovered) {
dot_bg = is_selected ? g_theme.accent_hover : g_theme.bg_lighter;
}
CLAY(WIDI(id, i + 200),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(16), .height = CLAY_SIZING_FIXED(16) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = dot_bg,
.cornerRadius = CLAY_CORNER_RADIUS(8),
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
if (is_selected) {
CLAY(WIDI(id, i + 300),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(8), .height = CLAY_SIZING_FIXED(8) },
},
.backgroundColor = g_theme.text,
.cornerRadius = CLAY_CORNER_RADIUS(4)
) {}
}
}
// Label
CLAY_TEXT(clay_str(options[i]), &g_widget_text_config);
}
if (row_hovered && g_wstate.mouse_clicked && !is_selected) {
*selected = i;
changed = 1;
}
}
}
return changed;
}
////////////////////////////////
// Text input
//
// Each text input gets its own display buffer(s) so Clay string pointers
// remain valid until the end of the frame. We support up to
// MAX_TEXT_INPUTS simultaneous text inputs per frame.
// Each text input may need up to 3 display buffers (before/sel/after).
#define MAX_TEXT_INPUTS 8
#define DISPLAY_BUF_SIZE 512
// 3 buffers per input: [0]=before selection, [1]=selected text, [2]=after selection
static char g_text_display_bufs[MAX_TEXT_INPUTS * 3][DISPLAY_BUF_SIZE];
static S32 g_text_display_buf_idx = 0;
void ui_text_input_reset_display_bufs() {
g_text_display_buf_idx = 0;
}
// Helper: get selection range in normalized order (lo <= hi)
static void text_input_get_sel(S32 *lo, S32 *hi) {
S32 a = g_wstate.sel_start;
S32 b = g_wstate.sel_end;
if (a <= b) { *lo = a; *hi = b; }
else { *lo = b; *hi = a; }
}
// Helper: true if there's an active selection
static B32 text_input_has_sel() {
return (g_wstate.sel_start != g_wstate.sel_end);
}
// Helper: delete selected range from buf, update cursor, clear selection
// Returns new string length.
static S32 text_input_delete_sel(char *buf, S32 len) {
S32 lo, hi;
text_input_get_sel(&lo, &hi);
if (lo == hi) return len;
memmove(&buf[lo], &buf[hi], len - hi + 1);
g_wstate.cursor_pos = lo;
g_wstate.sel_start = lo;
g_wstate.sel_end = lo;
return len - (hi - lo);
}
// Helper: copy selected text to clipboard
static void text_input_copy_sel(const char *buf, S32 len) {
S32 lo, hi;
text_input_get_sel(&lo, &hi);
if (lo == hi || lo >= len) return;
if (hi > len) hi = len;
// Use a temp buffer to null-terminate the selection
char tmp[DISPLAY_BUF_SIZE];
S32 sel_len = hi - lo;
if (sel_len > (S32)sizeof(tmp) - 1) sel_len = (S32)sizeof(tmp) - 1;
memcpy(tmp, &buf[lo], sel_len);
tmp[sel_len] = '\0';
platform_clipboard_set(tmp);
}
B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
ensure_widget_text_configs();
B32 text_changed = 0;
// Register this text input for Tab cycling
Clay_ElementId eid = WID(id);
if (g_wstate.text_input_count < UI_WIDGET_MAX_TEXT_INPUTS) {
g_wstate.text_input_ids[g_wstate.text_input_count++] = eid.id;
}
// Grab unique display buffers for this text input (up to 3)
S32 my_buf_base = g_text_display_buf_idx;
g_text_display_buf_idx += 3;
if (my_buf_base + 2 >= MAX_TEXT_INPUTS * 3) my_buf_base = 0; // safety
char *dbuf_before = g_text_display_bufs[my_buf_base + 0];
char *dbuf_sel = g_text_display_bufs[my_buf_base + 1];
char *dbuf_after = g_text_display_bufs[my_buf_base + 2];
B32 hovered = Clay_PointerOver(eid);
B32 is_focused = (g_wstate.focused_id == eid.id);
// Tab cycling: if Tab was pressed and we're focused, move to next input.
// We handle this BEFORE processing other input so the Tab key doesn't
// get processed as a regular key. The actual focus change is deferred
// to after all text inputs have registered (see end of function).
B32 wants_tab = 0;
if (is_focused && g_wstate.tab_pressed) {
wants_tab = 1;
}
// Click to focus / unfocus
if (g_wstate.mouse_clicked) {
if (hovered) {
if (!is_focused) {
g_wstate.focused_id = eid.id;
g_wstate.cursor_pos = (S32)strlen(buf);
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
g_wstate.cursor_blink = 0;
is_focused = 1;
} else {
// Already focused, clicking clears selection
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
}
} else if (is_focused) {
g_wstate.focused_id = 0;
is_focused = 0;
}
}
// Process keyboard input if focused
if (is_focused) {
S32 len = (S32)strlen(buf);
B32 ctrl = g_wstate.input.ctrl_held;
// Clamp cursor and selection
if (g_wstate.cursor_pos > len) g_wstate.cursor_pos = len;
if (g_wstate.cursor_pos < 0) g_wstate.cursor_pos = 0;
if (g_wstate.sel_start > len) g_wstate.sel_start = len;
if (g_wstate.sel_end > len) g_wstate.sel_end = len;
// Key events
for (S32 k = 0; k < g_wstate.input.key_count; k++) {
uint8_t key = g_wstate.input.keys[k];
// Skip Tab — handled via tab cycling
if (key == PKEY_TAB) continue;
// Ctrl shortcuts
if (ctrl) {
if (key == PKEY_A) {
// Select all
g_wstate.sel_start = 0;
g_wstate.sel_end = len;
g_wstate.cursor_pos = len;
continue;
}
if (key == PKEY_C) {
// Copy
text_input_copy_sel(buf, len);
continue;
}
if (key == PKEY_X) {
// Cut
if (text_input_has_sel()) {
text_input_copy_sel(buf, len);
len = text_input_delete_sel(buf, len);
text_changed = 1;
}
continue;
}
if (key == PKEY_V) {
// Paste
const char *clip = platform_clipboard_get();
if (clip) {
// Delete selection first if any
if (text_input_has_sel()) {
len = text_input_delete_sel(buf, len);
}
S32 clip_len = (S32)strlen(clip);
// Filter to single line (stop at newline)
for (S32 i = 0; i < clip_len; i++) {
if (clip[i] == '\n' || clip[i] == '\r') { clip_len = i; break; }
}
S32 space = buf_size - 1 - len;
if (clip_len > space) clip_len = space;
if (clip_len > 0) {
memmove(&buf[g_wstate.cursor_pos + clip_len], &buf[g_wstate.cursor_pos], len - g_wstate.cursor_pos + 1);
memcpy(&buf[g_wstate.cursor_pos], clip, clip_len);
g_wstate.cursor_pos += clip_len;
len += clip_len;
text_changed = 1;
}
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
}
continue;
}
// Other Ctrl combos: ignore
continue;
}
switch (key) {
case PKEY_BACKSPACE:
if (text_input_has_sel()) {
len = text_input_delete_sel(buf, len);
text_changed = 1;
} else if (g_wstate.cursor_pos > 0) {
memmove(&buf[g_wstate.cursor_pos - 1], &buf[g_wstate.cursor_pos], len - g_wstate.cursor_pos + 1);
g_wstate.cursor_pos--;
len--;
text_changed = 1;
}
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
break;
case PKEY_DELETE:
if (text_input_has_sel()) {
len = text_input_delete_sel(buf, len);
text_changed = 1;
} else if (g_wstate.cursor_pos < len) {
memmove(&buf[g_wstate.cursor_pos], &buf[g_wstate.cursor_pos + 1], len - g_wstate.cursor_pos);
len--;
text_changed = 1;
}
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
break;
case PKEY_LEFT:
if (text_input_has_sel()) {
S32 lo, hi; text_input_get_sel(&lo, &hi);
g_wstate.cursor_pos = lo;
} else if (g_wstate.cursor_pos > 0) {
g_wstate.cursor_pos--;
}
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
g_wstate.cursor_blink = 0;
break;
case PKEY_RIGHT:
if (text_input_has_sel()) {
S32 lo, hi; text_input_get_sel(&lo, &hi);
g_wstate.cursor_pos = hi;
} else if (g_wstate.cursor_pos < len) {
g_wstate.cursor_pos++;
}
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
g_wstate.cursor_blink = 0;
break;
case PKEY_HOME:
g_wstate.cursor_pos = 0;
g_wstate.sel_start = 0;
g_wstate.sel_end = 0;
g_wstate.cursor_blink = 0;
break;
case PKEY_END:
g_wstate.cursor_pos = len;
g_wstate.sel_start = len;
g_wstate.sel_end = len;
g_wstate.cursor_blink = 0;
break;
case PKEY_RETURN:
case PKEY_ESCAPE:
g_wstate.focused_id = 0;
is_focused = 0;
break;
}
}
// Character input (printable only, skip control chars)
if (is_focused) {
for (S32 c = 0; c < g_wstate.input.char_count; c++) {
uint16_t ch = g_wstate.input.chars[c];
if (ch >= 32 && ch < 127) {
// Delete selection first if any
if (text_input_has_sel()) {
len = text_input_delete_sel(buf, len);
}
if (len < buf_size - 1) {
memmove(&buf[g_wstate.cursor_pos + 1], &buf[g_wstate.cursor_pos], len - g_wstate.cursor_pos + 1);
buf[g_wstate.cursor_pos] = (char)ch;
g_wstate.cursor_pos++;
len++;
text_changed = 1;
g_wstate.cursor_blink = 0;
}
g_wstate.sel_start = g_wstate.cursor_pos;
g_wstate.sel_end = g_wstate.cursor_pos;
}
}
}
}
// Tab cycling: find next text input after this one
if (wants_tab && is_focused) {
// We need to find our index. Since text inputs register in order,
// our ID was just added above. Find it and advance to next.
S32 my_idx = -1;
for (S32 i = 0; i < g_wstate.text_input_count; i++) {
if (g_wstate.text_input_ids[i] == eid.id) { my_idx = i; break; }
}
if (my_idx >= 0) {
// Focus next (wrapping). But we might not have all inputs registered
// yet this frame. Store the "next index" request; actual focus change
// happens via a simple approach: just focus the next ID if known,
// otherwise wrap to first.
S32 next_idx = my_idx + 1;
// We can't know total count yet (more inputs may register after us).
// Instead, unfocus ourselves and set a "pending tab focus" that will
// be resolved. Simpler approach: Tab from last input wraps to first,
// Tab from others goes to next. Since we know the IDs registered so
// far, and inputs are registered in declaration order:
// If there IS a next already-registered input, go to it.
// Otherwise, wrap to index 0.
if (next_idx < g_wstate.text_input_count) {
g_wstate.focused_id = g_wstate.text_input_ids[next_idx];
} else {
// Wrap to first
g_wstate.focused_id = g_wstate.text_input_ids[0];
}
g_wstate.cursor_pos = 0;
g_wstate.sel_start = 0;
g_wstate.sel_end = 0;
is_focused = 0; // no longer focused on THIS input
}
}
// Build display
S32 len = (S32)strlen(buf);
S32 sel_lo = 0, sel_hi = 0;
B32 has_sel = 0;
if (is_focused) {
text_input_get_sel(&sel_lo, &sel_hi);
if (sel_lo < 0) sel_lo = 0;
if (sel_hi > len) sel_hi = len;
has_sel = (sel_lo != sel_hi);
}
Clay_Color bg = is_focused ? g_theme.bg_dark : g_theme.bg_medium;
Clay_Color border_color = is_focused ? g_theme.accent : g_theme.border;
CLAY(eid,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(30) },
.padding = { 8, 8, 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = bg,
.cornerRadius = CLAY_CORNER_RADIUS(3),
.border = { .color = border_color, .width = { 1, 1, 1, 1 } }
) {
if (len == 0 && !is_focused) {
// Placeholder
CLAY_TEXT(CLAY_STRING("..."), &g_widget_text_config_dim);
} else if (is_focused && has_sel) {
// Three segments: before | selected | after
// Before selection
if (sel_lo > 0) {
S32 n = sel_lo < (S32)DISPLAY_BUF_SIZE - 1 ? sel_lo : (S32)DISPLAY_BUF_SIZE - 1;
memcpy(dbuf_before, buf, n);
dbuf_before[n] = '\0';
CLAY_TEXT(clay_str(dbuf_before), &g_widget_text_config);
}
// Selected text with highlight background
{
S32 slen = sel_hi - sel_lo;
if (slen > (S32)DISPLAY_BUF_SIZE - 1) slen = (S32)DISPLAY_BUF_SIZE - 1;
memcpy(dbuf_sel, &buf[sel_lo], slen);
dbuf_sel[slen] = '\0';
CLAY(WIDI(id, 900),
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
},
.backgroundColor = g_theme.accent
) {
CLAY_TEXT(clay_str(dbuf_sel), &g_widget_text_config_sel);
}
}
// After selection
if (sel_hi < len) {
S32 n = len - sel_hi;
if (n > (S32)DISPLAY_BUF_SIZE - 1) n = (S32)DISPLAY_BUF_SIZE - 1;
memcpy(dbuf_after, &buf[sel_hi], n);
dbuf_after[n] = '\0';
CLAY_TEXT(clay_str(dbuf_after), &g_widget_text_config);
}
} else {
// No selection: show text with cursor '|'
if (is_focused) {
S32 cp = g_wstate.cursor_pos;
if (cp > len) cp = len;
S32 total = len + 1; // +1 for cursor char
if (total > (S32)DISPLAY_BUF_SIZE - 1) total = (S32)DISPLAY_BUF_SIZE - 1;
S32 before = cp < total ? cp : total;
memcpy(dbuf_before, buf, before);
dbuf_before[before] = '|';
S32 after = total - before - 1;
if (after > 0) memcpy(dbuf_before + before + 1, buf + cp, after);
dbuf_before[total] = '\0';
CLAY_TEXT(clay_str(dbuf_before), &g_widget_text_config);
} else {
S32 n = len < (S32)DISPLAY_BUF_SIZE - 1 ? len : (S32)DISPLAY_BUF_SIZE - 1;
memcpy(dbuf_before, buf, n);
dbuf_before[n] = '\0';
CLAY_TEXT(clay_str(dbuf_before), &g_widget_text_config);
}
}
}
return text_changed;
}
////////////////////////////////
// Dropdown
B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected) {
ensure_widget_text_configs();
B32 changed = 0;
Clay_ElementId eid = WID(id);
B32 header_hovered = Clay_PointerOver(eid);
B32 is_open = (g_wstate.open_dropdown_id == eid.id);
// Display current selection
const char *current_label = (*selected >= 0 && *selected < count) ? options[*selected] : "Select...";
Clay_Color bg = is_open ? g_theme.bg_dark : g_theme.bg_medium;
if (header_hovered && !is_open) bg = g_theme.bg_lighter;
CLAY(eid,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(30) },
.padding = { 8, 8, 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = bg,
.cornerRadius = CLAY_CORNER_RADIUS(3),
.border = { .color = is_open ? g_theme.accent : g_theme.border, .width = { 1, 1, 1, 1 } }
) {
CLAY(WIDI(id, 500),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
}
) {
CLAY_TEXT(clay_str(current_label), &g_widget_text_config);
}
CLAY(WIDI(id, 501),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(20), .height = CLAY_SIZING_FIT() },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}
) {
CLAY_TEXT(CLAY_STRING("v"), &g_widget_text_config_dim);
}
}
// Toggle open on click of header
if (header_hovered && g_wstate.mouse_clicked) {
if (is_open) {
g_wstate.open_dropdown_id = 0;
is_open = 0;
} else {
g_wstate.open_dropdown_id = eid.id;
is_open = 1;
}
}
// Draw dropdown list if open
if (is_open) {
Clay_ElementId list_id = WIDI(id, 502);
CLAY(list_id,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_dark,
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
for (S32 i = 0; i < count; i++) {
B32 is_item_selected = (*selected == i);
Clay_ElementId item_id = WIDI(id, i + 600);
B32 item_hovered = Clay_PointerOver(item_id);
Clay_Color item_bg = is_item_selected ? g_theme.accent : g_theme.bg_dark;
if (item_hovered) item_bg = g_theme.bg_lighter;
CLAY(item_id,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(28) },
.padding = { 8, 8, 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = item_bg
) {
CLAY_TEXT(clay_str(options[i]), &g_widget_text_config);
}
if (item_hovered && g_wstate.mouse_clicked) {
*selected = i;
changed = 1;
g_wstate.open_dropdown_id = 0;
}
}
}
// Close if clicked outside both header and list
if (g_wstate.mouse_clicked && !header_hovered && !Clay_PointerOver(list_id)) {
// Check if any item was clicked (already handled above)
B32 clicked_item = 0;
for (S32 i = 0; i < count; i++) {
if (Clay_PointerOver(WIDI(id, i + 600))) { clicked_item = 1; break; }
}
if (!clicked_item) {
g_wstate.open_dropdown_id = 0;
}
}
}
return changed;
}

80
src/ui/ui_widgets.h Normal file
View File

@@ -0,0 +1,80 @@
#pragma once
// ui_widgets.h - Immediate-mode widgets built on top of Clay.
//
// Each widget function takes a unique string ID, the value to display/edit,
// and returns whether the value was changed (or the widget was activated).
// The caller owns all data — the widget layer only stores transient UI state
// like which text field is focused or which dropdown is open.
#include "ui/ui_core.h"
#include "platform/platform.h"
////////////////////////////////
// Widget state (global, managed by widget layer)
#define UI_WIDGET_MAX_DROPDOWN_ITEMS 32
#define UI_WIDGET_MAX_TEXT_INPUTS 16
struct UI_WidgetState {
// Text input focus
uint32_t focused_id; // Clay element ID hash of the focused text input (0 = none)
int32_t cursor_pos; // Cursor position in focused text input
F32 cursor_blink; // Blink timer (seconds)
// Text selection (sel_start == sel_end means no selection)
int32_t sel_start; // Selection anchor (where selection began)
int32_t sel_end; // Selection extent (moves with cursor)
// Tab cycling: registered text input IDs in order of declaration
uint32_t text_input_ids[UI_WIDGET_MAX_TEXT_INPUTS];
int32_t text_input_count;
B32 tab_pressed; // True on the frame Tab was pressed
// Dropdown
uint32_t open_dropdown_id; // Clay element ID hash of the open dropdown (0 = none)
// Input events for this frame
PlatformInputEvents input;
// Click detection
B32 mouse_down;
B32 was_mouse_down;
B32 mouse_clicked; // true on the frame mouse transitions from up->down
};
extern UI_WidgetState g_wstate;
// Call once at startup
void ui_widgets_init();
// Call each frame before building widgets. Pass in the frame's input events.
void ui_widgets_begin_frame(PlatformInputEvents input, B32 mouse_down, B32 was_mouse_down);
// Reset per-frame text input display buffer allocator (called by begin_frame, but
// can also be called manually if needed)
void ui_text_input_reset_display_bufs();
////////////////////////////////
// Widgets
// All IDs must be unique string literals (passed to CLAY_ID internally).
// Simple label
void ui_label(const char *id, const char *text);
// Clickable button. Returns true on the frame it was clicked.
B32 ui_button(const char *id, const char *text);
// Checkbox. Toggles *value on click. Returns true if value changed.
B32 ui_checkbox(const char *id, const char *label, B32 *value);
// Radio button group. Sets *selected to the clicked index. Returns true if changed.
// options is an array of label strings, count is the number of options.
B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selected);
// Single-line text input. Edits buf in-place (null-terminated, max buf_size-1 chars).
// Returns true if the text changed this frame.
B32 ui_text_input(const char *id, char *buf, S32 buf_size);
// Dropdown / combo box. Sets *selected to chosen index. Returns true if changed.
// options is an array of label strings, count is the number of options.
B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected);

4470
vendor/clay/clay.h vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,90 +0,0 @@
// dear imgui: Renderer Backend for DirectX12
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
#include <dxgiformat.h> // DXGI_FORMAT
#include <d3d12.h> // D3D12_CPU_DESCRIPTOR_HANDLE
// Clang/GCC warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
#endif
// Initialization data, for ImGui_ImplDX12_Init()
struct ImGui_ImplDX12_InitInfo
{
ID3D12Device* Device;
ID3D12CommandQueue* CommandQueue; // Command queue used for queuing texture uploads.
int NumFramesInFlight;
DXGI_FORMAT RTVFormat; // RenderTarget format.
DXGI_FORMAT DSVFormat; // DepthStencilView format.
void* UserData;
// Allocating SRV descriptors for textures is up to the application, so we provide callbacks.
// (current version of the backend will only allocate one descriptor, from 1.92 the backend will need to allocate more)
ID3D12DescriptorHeap* SrvDescriptorHeap;
void (*SrvDescriptorAllocFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle);
void (*SrvDescriptorFreeFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
D3D12_CPU_DESCRIPTOR_HANDLE LegacySingleSrvCpuDescriptor; // To facilitate transition from single descriptor to allocator callback, you may use those.
D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor;
#endif
ImGui_ImplDX12_InitInfo() { memset((void*)this, 0, sizeof(*this)); }
};
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* info);
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
#endif
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually.
IMGUI_IMPL_API void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex);
// [BETA] Selected render state data shared with callbacks.
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX12_RenderDrawData() call.
// (Please open an issue if you feel you need access to more data)
struct ImGui_ImplDX12_RenderState
{
ID3D12Device* Device;
ID3D12GraphicsCommandList* CommandList;
};
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif // #ifndef IMGUI_DISABLE

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +0,0 @@
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5]
// [X] Platform: Gamepad support.
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd);
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
// Win32 message handler your application needs to call.
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
// - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
#if 0
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
#endif
// DPI-related helpers (optional)
// - Use to enable DPI awareness without having to create an application manifest.
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
// neither of which we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
// Transparency related helpers (optional) [experimental]
// - Use to enable alpha compositing transparency with the desktop.
// - Use together with e.g. clearing your framebuffer with zero-alpha.
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
#endif // #ifndef IMGUI_DISABLE

View File

@@ -1,147 +0,0 @@
//-----------------------------------------------------------------------------
// DEAR IMGUI COMPILE-TIME OPTIONS
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// - If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
// - Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// - Windows 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.
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean/ProggyForever), remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Enable Test Engine / Automation features.
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_IMGUI_USER_H
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
//#define IMGUI_USE_LEGACY_CRC32_ADLER
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
//#define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// Note that imgui_freetype.cpp may be used _without_ this define, if you manually call ImFontAtlas::SetFontLoader(). The define is simply a convenience.
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- ...Or use Dear ImGui's own very basic math operators.
//#define IMGUI_DEFINE_MATH_OPERATORS
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
/*
namespace ImGui
{
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/

24161
vendor/imgui/imgui.cpp vendored

File diff suppressed because it is too large Load Diff

4474
vendor/imgui/imgui.h vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,627 +0,0 @@
// [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 1.01.
// Grep for [DEAR IMGUI] to find the changes.
//
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Before #including,
//
// #define STB_RECT_PACK_IMPLEMENTATION
//
// in the file that you want to have the implementation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
typedef int stbrp_coord;
#define STBRP__MAXVAL 0x7fffffff
// Mostly for internal use, but this is the maximum supported coordinate value.
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
context->extra[1].y = (1<<30);
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
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.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff