Compare commits
3 Commits
6656b6d0b2
...
7a5c1c5159
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a5c1c5159 | |||
| 68235b57ce | |||
| 12dae774e4 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,6 +1,12 @@
|
|||||||
# Build output
|
# Build output
|
||||||
build/
|
build/
|
||||||
|
|
||||||
|
# bullshit files
|
||||||
|
nul
|
||||||
|
|
||||||
|
# editor files
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
# nob build system
|
# nob build system
|
||||||
nob.exe
|
nob.exe
|
||||||
nob.obj
|
nob.obj
|
||||||
@@ -24,4 +30,3 @@ nob.ilk
|
|||||||
# Misc
|
# Misc
|
||||||
*.exe
|
*.exe
|
||||||
!nob.c
|
!nob.c
|
||||||
|
|
||||||
|
|||||||
81
README.md
81
README.md
@@ -4,17 +4,51 @@ Graphical interface for automatically recording samples from existing analog aud
|
|||||||
|
|
||||||
## Build
|
## 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:
|
Open a Developer Command Prompt, then:
|
||||||
|
|
||||||
```
|
```
|
||||||
cl /nologo nob.c
|
cl /nologo nob.c
|
||||||
nob.exe
|
nob.exe debug
|
||||||
build\autosample.exe
|
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 32–126 (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
|
## 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.c Build script (compiled to nob.exe)
|
||||||
nob.h nob build system (vendored, single-header)
|
nob.h nob build system (vendored, single-header)
|
||||||
src/
|
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/
|
||||||
platform.h Window management API (platform-agnostic)
|
platform.h Window management API (platform-agnostic)
|
||||||
platform_win32.cpp Win32 implementation
|
platform_win32.cpp Win32 implementation
|
||||||
renderer/
|
renderer/
|
||||||
renderer.h Renderer API (graphics-agnostic)
|
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/
|
vendor/
|
||||||
imgui/ Dear ImGui (vendored source)
|
clay/
|
||||||
backends/ Platform and renderer backends (Win32, DX12)
|
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 158–163): 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 ~3155–3858): 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
|
## 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.
|
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.
|
- 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
|
## Dependencies
|
||||||
|
|
||||||
All dependencies are vendored as source. Nothing to download or install beyond the Windows SDK.
|
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
|
- [nob.h](https://github.com/tsoding/nob.h) — build system
|
||||||
- [Dear ImGui](https://github.com/ocornut/imgui) - GUI
|
- [Clay](https://github.com/nicbarker/clay) — single-header C layout library (v0.14, with MSVC C++ patches)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
// raddbg 0.9.24 project file
|
// 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/main.cpp"
|
||||||
recent_file: path: "src/theme.cpp"
|
recent_file: path: "src/theme.cpp"
|
||||||
recent_file: path: "nob.obj"
|
recent_file: path: "nob.obj"
|
||||||
@@ -14,11 +17,11 @@ target:
|
|||||||
debug_info:
|
debug_info:
|
||||||
{
|
{
|
||||||
path: "C:/Users/mta/projects/autosample/build/autosample.pdb"
|
path: "C:/Users/mta/projects/autosample/build/autosample.pdb"
|
||||||
timestamp: 66207529127862
|
timestamp: 66207573824751
|
||||||
}
|
}
|
||||||
target:
|
target:
|
||||||
{
|
{
|
||||||
executable: "build/autosample.exe"
|
executable: "build/autosample.exe"
|
||||||
working_directory: "build/"
|
working_directory: build
|
||||||
enabled: 1
|
enabled: 1
|
||||||
}
|
}
|
||||||
|
|||||||
30
autosample.sublime-project
Normal file
30
autosample.sublime-project
Normal 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
337
build_log.txt
Normal 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
|
||||||
48
imgui.ini
48
imgui.ini
@@ -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
|
|
||||||
|
|
||||||
102
nob.c
102
nob.c
@@ -5,22 +5,6 @@
|
|||||||
#include "nob.h"
|
#include "nob.h"
|
||||||
|
|
||||||
#define BUILD_DIR "build"
|
#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[] = {
|
static const char *link_libs[] = {
|
||||||
"d3d12.lib",
|
"d3d12.lib",
|
||||||
@@ -34,61 +18,6 @@ static const char *link_libs[] = {
|
|||||||
"winmm.lib",
|
"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) {
|
int main(int argc, char **argv) {
|
||||||
NOB_GO_REBUILD_URSELF(argc, argv);
|
NOB_GO_REBUILD_URSELF(argc, argv);
|
||||||
|
|
||||||
@@ -103,21 +32,18 @@ int main(int argc, char **argv) {
|
|||||||
nob_log(NOB_INFO, "Cleaning %s/", BUILD_DIR);
|
nob_log(NOB_INFO, "Cleaning %s/", BUILD_DIR);
|
||||||
Nob_Cmd cmd = {0};
|
Nob_Cmd cmd = {0};
|
||||||
nob_cmd_append(&cmd, "cmd.exe", "/c", "if exist " BUILD_DIR " rmdir /s /q " BUILD_DIR);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nob_mkdir_if_not_exists(BUILD_DIR)) return 1;
|
if (!nob_mkdir_if_not_exists(BUILD_DIR)) return 1;
|
||||||
|
|
||||||
// Build vendor libs (unless already built)
|
// Unity build: single cl.exe invocation compiles main.cpp (which #includes everything)
|
||||||
if (!build_imgui_lib(debug)) return 1;
|
{
|
||||||
|
|
||||||
// Compile and link
|
|
||||||
Nob_Cmd cmd = {0};
|
Nob_Cmd cmd = {0};
|
||||||
|
|
||||||
nob_cmd_append(&cmd, "cl.exe");
|
nob_cmd_append(&cmd, "cl.exe");
|
||||||
nob_cmd_append(&cmd, "/nologo", "/std:c++17", "/EHsc", "/W3");
|
nob_cmd_append(&cmd, "/nologo", "/std:c++20", "/EHsc", "/W3");
|
||||||
nob_cmd_append(&cmd, "/Isrc", "/Ivendor/imgui", "/Ivendor/imgui/backends");
|
nob_cmd_append(&cmd, "/Isrc", "/Ivendor/clay");
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
|
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
|
||||||
@@ -129,23 +55,23 @@ int main(int argc, char **argv) {
|
|||||||
nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", 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));
|
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/main.cpp");
|
||||||
nob_cmd_append(&cmd, src_files[i]);
|
|
||||||
|
|
||||||
nob_cmd_append(&cmd, "/link");
|
nob_cmd_append(&cmd, "/link");
|
||||||
nob_cmd_append(&cmd, "/MACHINE:X64");
|
nob_cmd_append(&cmd, "/MACHINE:X64");
|
||||||
nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE");
|
nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE");
|
||||||
nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", BUILD_DIR));
|
nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", BUILD_DIR));
|
||||||
nob_cmd_append(&cmd, "/DEBUG");
|
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++)
|
size_t i;
|
||||||
|
for (i = 0; i < NOB_ARRAY_LEN(link_libs); i++)
|
||||||
nob_cmd_append(&cmd, link_libs[i]);
|
nob_cmd_append(&cmd, link_libs[i]);
|
||||||
|
}
|
||||||
|
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
if (!nob_cmd_run(&cmd)) return 1;
|
// Clean up obj files
|
||||||
|
nob_delete_file(nob_temp_sprintf("%s/main.obj", BUILD_DIR));
|
||||||
// Clean up .obj files
|
|
||||||
for (size_t i = 0; i < NOB_ARRAY_LEN(src_files); i++)
|
|
||||||
nob_delete_file(obj_name(src_files[i]));
|
|
||||||
|
|
||||||
nob_log(NOB_INFO, "Build complete: %s/autosample.exe", BUILD_DIR);
|
nob_log(NOB_INFO, "Build complete: %s/autosample.exe", BUILD_DIR);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
53
src/base/base_arena.cpp
Normal file
53
src/base/base_arena.cpp
Normal 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
44
src/base/base_arena.h
Normal 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
176
src/base/base_core.h
Normal 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
3
src/base/base_inc.cpp
Normal 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
8
src/base/base_inc.h
Normal 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
110
src/base/base_math.h
Normal 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
32
src/base/base_strings.cpp
Normal 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
49
src/base/base_strings.h
Normal 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);
|
||||||
579
src/main.cpp
579
src/main.cpp
@@ -1,44 +1,460 @@
|
|||||||
// Unity build - include all src files here
|
// Unity build - include all src files here
|
||||||
// -mta
|
// -mta
|
||||||
// [h]
|
// [h]
|
||||||
|
#include "base/base_inc.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "renderer/renderer.h"
|
#include "renderer/renderer.h"
|
||||||
#include "midi/midi.h"
|
#include "midi/midi.h"
|
||||||
#include "imgui.h"
|
#include "ui/ui_core.h"
|
||||||
#include "imgui_internal.h"
|
#include "ui/ui_widgets.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
// [cpp]
|
// [cpp]
|
||||||
|
#include "base/base_inc.cpp"
|
||||||
|
#include "ui/ui_core.cpp"
|
||||||
|
#include "ui/ui_widgets.cpp"
|
||||||
#include "platform/platform_win32.cpp"
|
#include "platform/platform_win32.cpp"
|
||||||
#include "renderer/renderer_dx12.cpp"
|
#include "renderer/renderer_dx12.cpp"
|
||||||
#include "midi/midi_win32.cpp"
|
#include "midi/midi_win32.cpp"
|
||||||
#include "menus.cpp"
|
#include "menus.cpp"
|
||||||
#include "theme.cpp"
|
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Win32 input gathering
|
||||||
|
|
||||||
static void build_default_layout(ImGuiID dockspace_id) {
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
ImGui::DockBuilderRemoveNode(dockspace_id);
|
#define WIN32_LEAN_AND_MEAN
|
||||||
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace);
|
#endif
|
||||||
ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->Size);
|
#include <windows.h>
|
||||||
|
|
||||||
ImGuiID center = dockspace_id;
|
struct InputState {
|
||||||
ImGuiID left = ImGui::DockBuilderSplitNode(center, ImGuiDir_Left, 0.15f, nullptr, ¢er);
|
Vec2F32 mouse;
|
||||||
ImGuiID right = ImGui::DockBuilderSplitNode(center, ImGuiDir_Right, 0.20f, nullptr, ¢er);
|
Vec2F32 scroll_delta;
|
||||||
ImGuiID bottom = ImGui::DockBuilderSplitNode(center, ImGuiDir_Down, 0.25f, nullptr, ¢er);
|
B32 mouse_down;
|
||||||
|
B32 was_mouse_down;
|
||||||
|
};
|
||||||
|
|
||||||
ImGui::DockBuilderDockWindow("Browser", left);
|
static InputState g_input;
|
||||||
ImGui::DockBuilderDockWindow("Main", center);
|
|
||||||
ImGui::DockBuilderDockWindow("Properties", right);
|
|
||||||
ImGui::DockBuilderDockWindow("MIDI Devices", right);
|
|
||||||
ImGui::DockBuilderDockWindow("Log", bottom);
|
|
||||||
|
|
||||||
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) {
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
std::cout << "Hello" << std::endl;
|
|
||||||
|
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
@@ -47,7 +463,7 @@ int main(int argc, char **argv) {
|
|||||||
if (!window)
|
if (!window)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
int32_t w, h;
|
S32 w, h;
|
||||||
platform_get_size(window, &w, &h);
|
platform_get_size(window, &w, &h);
|
||||||
|
|
||||||
RendererDesc renderer_desc = {};
|
RendererDesc renderer_desc = {};
|
||||||
@@ -62,99 +478,52 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
MidiEngine *midi = midi_create();
|
MidiEngine *midi = midi_create();
|
||||||
|
|
||||||
setup_theme();
|
// Initialize UI (Clay)
|
||||||
setup_menus(window);
|
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;
|
setup_menus(window);
|
||||||
bool show_demo = true;
|
ui_widgets_init();
|
||||||
bool show_browser = true;
|
|
||||||
bool show_props = true;
|
AppState app = {};
|
||||||
bool show_log = true;
|
app.window = window;
|
||||||
bool show_midi_devices = true;
|
app.renderer = renderer;
|
||||||
bool first_frame = true;
|
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)) {
|
while (platform_poll_events(window)) {
|
||||||
|
// Menu commands
|
||||||
int32_t menu_cmd = platform_poll_menu_command(window);
|
int32_t menu_cmd = platform_poll_menu_command(window);
|
||||||
switch (menu_cmd) {
|
switch (menu_cmd) {
|
||||||
case MENU_FILE_EXIT: platform_destroy_window(window); return 0;
|
case MENU_FILE_EXIT: goto exit_app;
|
||||||
case MENU_VIEW_BROWSER: show_browser = !show_browser; break;
|
case MENU_VIEW_BROWSER: app.show_browser = !app.show_browser; break;
|
||||||
case MENU_VIEW_PROPERTIES:show_props = !show_props; break;
|
case MENU_VIEW_PROPERTIES:app.show_props = !app.show_props; break;
|
||||||
case MENU_VIEW_LOG: show_log = !show_log; break;
|
case MENU_VIEW_LOG: app.show_log = !app.show_log; break;
|
||||||
case MENU_VIEW_DEMO: show_demo = !show_demo; break;
|
case MENU_VIEW_MIDI_DEVICES: app.show_midi_devices = !app.show_midi_devices; break;
|
||||||
case MENU_VIEW_MIDI_DEVICES: show_midi_devices = !show_midi_devices; break;
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
platform_get_size(window, &w, &h);
|
|
||||||
if (w != last_w || h != last_h) {
|
do_frame(&app);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit_app:
|
||||||
midi_destroy(midi);
|
midi_destroy(midi);
|
||||||
|
ui_destroy(ui);
|
||||||
renderer_destroy(renderer);
|
renderer_destroy(renderer);
|
||||||
platform_destroy_window(window);
|
platform_destroy_window(window);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -3,6 +3,46 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.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 PlatformWindow;
|
||||||
|
|
||||||
struct PlatformWindowDesc {
|
struct PlatformWindowDesc {
|
||||||
@@ -22,11 +62,26 @@ struct PlatformMenu {
|
|||||||
int32_t item_count;
|
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);
|
PlatformWindow *platform_create_window(PlatformWindowDesc *desc);
|
||||||
void platform_destroy_window(PlatformWindow *window);
|
void platform_destroy_window(PlatformWindow *window);
|
||||||
bool platform_poll_events(PlatformWindow *window);
|
bool platform_poll_events(PlatformWindow *window);
|
||||||
void platform_get_size(PlatformWindow *window, int32_t *w, int32_t *h);
|
void platform_get_size(PlatformWindow *window, int32_t *w, int32_t *h);
|
||||||
void *platform_get_native_handle(PlatformWindow *window);
|
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);
|
void platform_set_menu(PlatformWindow *window, PlatformMenu *menus, int32_t menu_count);
|
||||||
int32_t platform_poll_menu_command(PlatformWindow *window);
|
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();
|
||||||
|
|||||||
@@ -6,35 +6,62 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <malloc.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 {
|
struct PlatformWindow {
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
bool should_close;
|
bool should_close;
|
||||||
int32_t width;
|
int32_t width;
|
||||||
int32_t height;
|
int32_t height;
|
||||||
int32_t pending_menu_cmd;
|
int32_t pending_menu_cmd;
|
||||||
|
PlatformFrameCallback frame_callback;
|
||||||
|
void *frame_callback_user_data;
|
||||||
|
PlatformInputEvents input_events;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PlatformWindow *g_current_window = nullptr;
|
static PlatformWindow *g_current_window = nullptr;
|
||||||
|
|
||||||
static LRESULT CALLBACK win32_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
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) {
|
switch (msg) {
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
if (g_current_window && wparam != SIZE_MINIMIZED) {
|
if (g_current_window && wparam != SIZE_MINIMIZED) {
|
||||||
g_current_window->width = (int32_t)LOWORD(lparam);
|
g_current_window->width = (int32_t)LOWORD(lparam);
|
||||||
g_current_window->height = (int32_t)HIWORD(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;
|
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:
|
case WM_COMMAND:
|
||||||
if (g_current_window && HIWORD(wparam) == 0)
|
if (g_current_window && HIWORD(wparam) == 0)
|
||||||
g_current_window->pending_menu_cmd = (int32_t)LOWORD(wparam);
|
g_current_window->pending_menu_cmd = (int32_t)LOWORD(wparam);
|
||||||
return 0;
|
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:
|
case WM_CLOSE:
|
||||||
if (g_current_window)
|
if (g_current_window)
|
||||||
g_current_window->should_close = true;
|
g_current_window->should_close = true;
|
||||||
@@ -56,6 +83,7 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
|
|||||||
wc.style = CS_CLASSDC;
|
wc.style = CS_CLASSDC;
|
||||||
wc.lpfnWndProc = win32_wndproc;
|
wc.lpfnWndProc = win32_wndproc;
|
||||||
wc.hInstance = GetModuleHandleW(nullptr);
|
wc.hInstance = GetModuleHandleW(nullptr);
|
||||||
|
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
wc.lpszClassName = L"autosample_wc";
|
wc.lpszClassName = L"autosample_wc";
|
||||||
RegisterClassExW(&wc);
|
RegisterClassExW(&wc);
|
||||||
|
|
||||||
@@ -133,6 +161,11 @@ void *platform_get_native_handle(PlatformWindow *window) {
|
|||||||
return (void *)window->hwnd;
|
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) {
|
void platform_set_menu(PlatformWindow *window, PlatformMenu *menus, int32_t menu_count) {
|
||||||
HMENU menu_bar = CreateMenu();
|
HMENU menu_bar = CreateMenu();
|
||||||
|
|
||||||
@@ -167,3 +200,57 @@ int32_t platform_poll_menu_command(PlatformWindow *window) {
|
|||||||
window->pending_menu_cmd = 0;
|
window->pending_menu_cmd = 0;
|
||||||
return cmd;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct Renderer;
|
struct Renderer;
|
||||||
|
struct Clay_RenderCommandArray;
|
||||||
|
|
||||||
struct RendererDesc {
|
struct RendererDesc {
|
||||||
void *window_handle = nullptr;
|
void *window_handle = nullptr;
|
||||||
@@ -15,5 +16,11 @@ struct RendererDesc {
|
|||||||
Renderer *renderer_create(RendererDesc *desc);
|
Renderer *renderer_create(RendererDesc *desc);
|
||||||
void renderer_destroy(Renderer *renderer);
|
void renderer_destroy(Renderer *renderer);
|
||||||
bool renderer_begin_frame(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);
|
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
104
src/theme.cpp
104
src/theme.cpp
@@ -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
107
src/ui/ui_core.cpp
Normal 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
65
src/ui/ui_core.h
Normal 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
735
src/ui/ui_widgets.cpp
Normal 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
80
src/ui/ui_widgets.h
Normal 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
4470
vendor/clay/clay.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1342
vendor/imgui/backends/imgui_impl_dx12.cpp
vendored
1342
vendor/imgui/backends/imgui_impl_dx12.cpp
vendored
File diff suppressed because it is too large
Load Diff
90
vendor/imgui/backends/imgui_impl_dx12.h
vendored
90
vendor/imgui/backends/imgui_impl_dx12.h
vendored
@@ -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
|
|
||||||
1505
vendor/imgui/backends/imgui_impl_win32.cpp
vendored
1505
vendor/imgui/backends/imgui_impl_win32.cpp
vendored
File diff suppressed because it is too large
Load Diff
54
vendor/imgui/backends/imgui_impl_win32.h
vendored
54
vendor/imgui/backends/imgui_impl_win32.h
vendored
@@ -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
|
|
||||||
147
vendor/imgui/imconfig.h
vendored
147
vendor/imgui/imconfig.h
vendored
@@ -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
24161
vendor/imgui/imgui.cpp
vendored
File diff suppressed because it is too large
Load Diff
4474
vendor/imgui/imgui.h
vendored
4474
vendor/imgui/imgui.h
vendored
File diff suppressed because it is too large
Load Diff
11285
vendor/imgui/imgui_demo.cpp
vendored
11285
vendor/imgui/imgui_demo.cpp
vendored
File diff suppressed because it is too large
Load Diff
6754
vendor/imgui/imgui_draw.cpp
vendored
6754
vendor/imgui/imgui_draw.cpp
vendored
File diff suppressed because it is too large
Load Diff
4288
vendor/imgui/imgui_internal.h
vendored
4288
vendor/imgui/imgui_internal.h
vendored
File diff suppressed because it is too large
Load Diff
4573
vendor/imgui/imgui_tables.cpp
vendored
4573
vendor/imgui/imgui_tables.cpp
vendored
File diff suppressed because it is too large
Load Diff
10942
vendor/imgui/imgui_widgets.cpp
vendored
10942
vendor/imgui/imgui_widgets.cpp
vendored
File diff suppressed because it is too large
Load Diff
627
vendor/imgui/imstb_rectpack.h
vendored
627
vendor/imgui/imstb_rectpack.h
vendored
@@ -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.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
1527
vendor/imgui/imstb_textedit.h
vendored
1527
vendor/imgui/imstb_textedit.h
vendored
File diff suppressed because it is too large
Load Diff
5085
vendor/imgui/imstb_truetype.h
vendored
5085
vendor/imgui/imstb_truetype.h
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user