Format all

This commit is contained in:
2026-03-12 10:41:16 -04:00
parent 13f856cfbc
commit c7bb89fd6d
31 changed files with 3289 additions and 3200 deletions

31
.clang-format Normal file
View File

@@ -0,0 +1,31 @@
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
AlignConsecutiveDeclarations: true
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AlignConsecutiveMacros: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true
Cpp11BracedListStyle: false
ColumnLimit: 0

View File

@@ -13,7 +13,7 @@ AudioEngine *audio_create(void *hwnd);
void audio_destroy(AudioEngine *engine); void audio_destroy(AudioEngine *engine);
void audio_refresh_devices(AudioEngine *engine); void audio_refresh_devices(AudioEngine *engine);
S32 audio_get_device_count(AudioEngine *engine); S32 audio_get_device_count(AudioEngine *engine);
AudioDeviceInfo*audio_get_device(AudioEngine *engine, S32 index); AudioDeviceInfo *audio_get_device(AudioEngine *engine, S32 index);
B32 audio_open_device(AudioEngine *engine, S32 index); B32 audio_open_device(AudioEngine *engine, S32 index);
void audio_close_device(AudioEngine *engine); void audio_close_device(AudioEngine *engine);

View File

@@ -1,8 +1,8 @@
#include "audio/audio.h" #include "audio/audio.h"
#include <windows.h> #include <math.h>
#include <objbase.h> #include <objbase.h>
#include <string.h> #include <string.h>
#include <math.h> #include <windows.h>
#define AUDIO_MAX_DEVICES 32 #define AUDIO_MAX_DEVICES 32
#define AUDIO_MAX_CHANNELS 32 #define AUDIO_MAX_CHANNELS 32
@@ -124,7 +124,7 @@ enum {
// Standard ASIO vtable — inherits IUnknown // Standard ASIO vtable — inherits IUnknown
class IASIO : public IUnknown { class IASIO : public IUnknown {
public: public:
virtual ASIOBool init(void *sysHandle) = 0; virtual ASIOBool init(void *sysHandle) = 0;
virtual void getDriverName(char *name) = 0; virtual void getDriverName(char *name) = 0;
virtual long getDriverVersion() = 0; virtual long getDriverVersion() = 0;

View File

@@ -1,9 +1,9 @@
#include "audio/audio.h" #include "audio/audio.h"
#include <AudioToolbox/AudioToolbox.h> #include <AudioToolbox/AudioToolbox.h>
#include <CoreAudio/CoreAudio.h> #include <CoreAudio/CoreAudio.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <string.h>
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -44,9 +44,11 @@ static OSStatus audio_render_callback(void *inRefCon,
const AudioTimeStamp *inTimeStamp, const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber, UInt32 inBusNumber,
UInt32 inNumberFrames, UInt32 inNumberFrames,
AudioBufferList *ioData) AudioBufferList *ioData) {
{ (void)inRefCon;
(void)inRefCon; (void)ioActionFlags; (void)inTimeStamp; (void)inBusNumber; (void)ioActionFlags;
(void)inTimeStamp;
(void)inBusNumber;
AudioEngine *engine = g_audio_engine; AudioEngine *engine = g_audio_engine;
if (!engine) { if (!engine) {
@@ -85,7 +87,8 @@ static OSStatus audio_render_callback(void *inRefCon,
// Advance phase using first channel's traversal // Advance phase using first channel's traversal
phase += phase_inc * samples_to_gen; phase += phase_inc * samples_to_gen;
while (phase >= 2.0 * AUDIO_PI) phase -= 2.0 * AUDIO_PI; while (phase >= 2.0 * AUDIO_PI)
phase -= 2.0 * AUDIO_PI;
engine->test_tone_phase = phase; engine->test_tone_phase = phase;
S32 new_remaining = atomic_fetch_sub(&engine->test_tone_samples_remaining, samples_to_gen); S32 new_remaining = atomic_fetch_sub(&engine->test_tone_samples_remaining, samples_to_gen);

View File

@@ -34,7 +34,7 @@ void arena_clear(Arena *arena);
//////////////////////////////// ////////////////////////////////
// Temporary scope helpers // Temporary scope helpers
inline Temp temp_begin(Arena *arena) { return {arena, arena->pos}; } inline Temp temp_begin(Arena *arena) { return { arena, arena->pos }; }
inline void temp_end(Temp temp) { arena_pop_to(temp.arena, temp.pos); } inline void temp_end(Temp temp) { arena_pop_to(temp.arena, temp.pos); }
//////////////////////////////// ////////////////////////////////

View File

@@ -2,11 +2,11 @@
// base_core.h - Fundamental types, macros, and linked list helpers // base_core.h - Fundamental types, macros, and linked list helpers
// Inspired by raddebugger's base_core.h // Inspired by raddebugger's base_core.h
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <math.h> #include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
//////////////////////////////// ////////////////////////////////
// Codebase keywords // Codebase keywords
@@ -60,13 +60,14 @@ typedef double F64;
#define Max(A, B) (((A) > (B)) ? (A) : (B)) #define Max(A, B) (((A) > (B)) ? (A) : (B))
#define ClampTop(A, X) Min(A, X) #define ClampTop(A, X) Min(A, X)
#define ClampBot(X, B) Max(X, B) #define ClampBot(X, B) Max(X, B)
#define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) : (X)) #define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) \
: (X))
//////////////////////////////// ////////////////////////////////
// Alignment / Sizing // Alignment / Sizing
#define AlignPow2(x, b) (((x) + (b) - 1) & (~((b) - 1))) #define AlignPow2(x, b) (((x) + (b)-1) & (~((b)-1)))
#define AlignDownPow2(x, b) ((x) & (~((b) - 1))) #define AlignDownPow2(x, b) ((x) & (~((b)-1)))
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) #define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
//////////////////////////////// ////////////////////////////////
@@ -109,25 +110,33 @@ typedef double F64;
#define Glue_(A, B) A##B #define Glue_(A, B) A##B
#define Glue(A, B) Glue_(A, B) #define Glue(A, B) Glue_(A, B)
#define Swap(T, a, b) do { T t__ = a; a = b; b = t__; } while (0) #define Swap(T, a, b) \
do { \
T t__ = a; \
a = b; \
b = t__; \
} while (0)
//////////////////////////////// ////////////////////////////////
// Assert // Assert
#if defined(_MSC_VER) #if defined(_MSC_VER)
# define Trap() __debugbreak() #define Trap() __debugbreak()
#elif defined(__clang__) || defined(__GNUC__) #elif defined(__clang__) || defined(__GNUC__)
# define Trap() __builtin_trap() #define Trap() __builtin_trap()
#else #else
# define Trap() (*(volatile int *)0 = 0) #define Trap() (*(volatile int *)0 = 0)
#endif #endif
#define AssertAlways(x) do { if (!(x)) { Trap(); } } while (0) #define AssertAlways(x) \
do { \
if (!(x)) { Trap(); } \
} while (0)
#ifdef _DEBUG #ifdef _DEBUG
# define Assert(x) AssertAlways(x) #define Assert(x) AssertAlways(x)
#else #else
# define Assert(x) (void)(x) #define Assert(x) (void)(x)
#endif #endif
#define InvalidPath Assert(!"Invalid Path!") #define InvalidPath Assert(!"Invalid Path!")
@@ -142,14 +151,9 @@ typedef double F64;
// Doubly-linked-list (with nil support) // Doubly-linked-list (with nil support)
#define DLLInsert_NPZ(nil, f, l, p, n, next, prev) \ #define DLLInsert_NPZ(nil, f, l, p, n, next, prev) \
(CheckNil(nil, f) ? \ (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)) \
((f) = (l) = (n), SetNil(nil, (n)->next), SetNil(nil, (n)->prev)) : \ : ((p) == (l)) ? ((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) \
CheckNil(nil, p) ? \ : (((!CheckNil(nil, p) && CheckNil(nil, (p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (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 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 DLLPushFront_NPZ(nil, f, l, n, next, prev) DLLInsert_NPZ(nil, l, f, f, n, prev, next)
@@ -167,9 +171,7 @@ typedef double F64;
// Singly-linked queue (doubly-headed) // Singly-linked queue (doubly-headed)
#define SLLQueuePush_NZ(nil, f, l, n, next) \ #define SLLQueuePush_NZ(nil, f, l, n, next) \
(CheckNil(nil, f) ? \ (CheckNil(nil, f) ? ((f) = (l) = (n), SetNil(nil, (n)->next)) : ((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
((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 SLLQueuePush(f, l, n) SLLQueuePush_NZ(0, f, l, n, next)
#define SLLQueuePushFront(f, l, n) (((n)->next = (f)), ((f) = (n))) #define SLLQueuePushFront(f, l, n) (((n)->next = (f)), ((f) = (n)))

View File

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

View File

@@ -30,51 +30,66 @@ enum Corner {
//////////////////////////////// ////////////////////////////////
// Vector types // Vector types
struct Vec2F32 { F32 x, y; }; struct Vec2F32 {
struct Vec2S32 { S32 x, y; }; F32 x, y;
struct Vec3F32 { F32 x, y, z; }; };
struct Vec4F32 { F32 x, y, z, w; }; struct Vec2S32 {
S32 x, y;
};
struct Vec3F32 {
F32 x, y, z;
};
struct Vec4F32 {
F32 x, y, z, w;
};
//////////////////////////////// ////////////////////////////////
// Range types // Range types
struct Rng1F32 { F32 min, max; }; struct Rng1F32 {
struct Rng1S64 { S64 min, max; }; F32 min, max;
struct Rng2F32 { Vec2F32 p0, p1; }; };
struct Rng1S64 {
S64 min, max;
};
struct Rng2F32 {
Vec2F32 p0, p1;
};
//////////////////////////////// ////////////////////////////////
// Constructors // Constructors
static inline Vec2F32 v2f32(F32 x, F32 y) { return {x, y}; } static inline Vec2F32 v2f32(F32 x, F32 y) { return { x, y }; }
static inline Vec2S32 v2s32(S32 x, S32 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 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 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 Rng1F32 rng1f32(F32 min, F32 max) { return { min, max }; }
static inline Rng1S64 rng1s64(S64 min, S64 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 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}}; } static inline Rng2F32 rng2f32p(F32 x0, F32 y0, F32 x1, F32 y1) { return { { x0, y0 }, { x1, y1 } }; }
//////////////////////////////// ////////////////////////////////
// Vec2F32 operations // Vec2F32 operations
static inline Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b) { return {a.x + b.x, a.y + b.y}; } 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 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 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}; } static inline Vec2F32 scale_2f32(Vec2F32 v, F32 s) { return { v.x * s, v.y * s }; }
// Axis-indexed access // Axis-indexed access
static inline F32 v2f32_axis(Vec2F32 v, Axis2 a) { return a == Axis2_X ? v.x : v.y; } 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) { static inline void v2f32_set_axis(Vec2F32 *v, Axis2 a, F32 val) {
if (a == Axis2_X) v->x = val; else v->y = val; if (a == Axis2_X) v->x = val;
else v->y = val;
} }
//////////////////////////////// ////////////////////////////////
// Vec4F32 operations // 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 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 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) { 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}; 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 };
} }
//////////////////////////////// ////////////////////////////////
@@ -82,20 +97,20 @@ static inline Vec4F32 lerp_4f32(Vec4F32 a, Vec4F32 b, F32 t) {
static inline F32 rng2f32_width(Rng2F32 r) { return r.p1.x - r.p0.x; } 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 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_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 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) { 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; 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) { 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}}; 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) { 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}}; 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) { static inline Rng2F32 rng2f32_intersect(Rng2F32 a, Rng2F32 b) {
return {{Max(a.p0.x, b.p0.x), Max(a.p0.y, b.p0.y)}, 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)}}; { Min(a.p1.x, b.p1.x), Min(a.p1.y, b.p1.y) } };
} }
// Axis-indexed range dimension // Axis-indexed range dimension

View File

@@ -12,15 +12,15 @@ Str8 str8_pushf(Arena *arena, const char *fmt, ...) {
vsnprintf(buf, len + 1, fmt, args2); vsnprintf(buf, len + 1, fmt, args2);
va_end(args2); va_end(args2);
return {buf, (U64)len}; return { buf, (U64)len };
} }
Str8 str8_push_copy(Arena *arena, Str8 s) { Str8 str8_push_copy(Arena *arena, Str8 s) {
if (s.size == 0 || !s.str) return {nullptr, 0}; if (s.size == 0 || !s.str) return { nullptr, 0 };
char *buf = push_array_no_zero(arena, char, s.size + 1); char *buf = push_array_no_zero(arena, char, s.size + 1);
MemoryCopy(buf, s.str, s.size); MemoryCopy(buf, s.str, s.size);
buf[s.size] = 0; buf[s.size] = 0;
return {buf, s.size}; return { buf, s.size };
} }
void str8_list_push(Arena *arena, Str8List *list, Str8 s) { void str8_list_push(Arena *arena, Str8List *list, Str8 s) {

View File

@@ -31,9 +31,9 @@ struct Arena;
//////////////////////////////// ////////////////////////////////
// Constructors // Constructors
static inline Str8 str8(const char *s, U64 len) { return {s, len}; } 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_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 Str8 str8_lit(const char *s) { return { s, s ? (U64)strlen(s) : 0 }; }
static inline B32 str8_match(Str8 a, Str8 b) { static inline B32 str8_match(Str8 a, Str8 b) {
if (a.size != b.size) return 0; if (a.size != b.size) return 0;
return MemoryCompare(a.str, b.str, a.size) == 0; return MemoryCompare(a.str, b.str, a.size) == 0;

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
#include "midi/midi.h" #include "midi/midi.h"
#include <CoreMIDI/CoreMIDI.h>
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <string.h> #include <CoreMIDI/CoreMIDI.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <string.h>
#define MIDI_MAX_DEVICES 64 #define MIDI_MAX_DEVICES 64
#define MIDI_RELEASE_FLASH_DURATION 0.15f #define MIDI_RELEASE_FLASH_DURATION 0.15f
@@ -46,11 +46,14 @@ static void midi_read_callback(const MIDIPacketList *pktlist, void *readProcRefC
const MIDIPacket *packet = &pktlist->packet[0]; const MIDIPacket *packet = &pktlist->packet[0];
for (UInt32 i = 0; i < pktlist->numPackets; i++) { for (UInt32 i = 0; i < pktlist->numPackets; i++) {
// Parse MIDI bytes // Parse MIDI bytes
for (UInt16 j = 0; j < packet->length; ) { for (UInt16 j = 0; j < packet->length;) {
U8 status = packet->data[j]; U8 status = packet->data[j];
// Skip non-status bytes (running status not handled for simplicity) // Skip non-status bytes (running status not handled for simplicity)
if (status < 0x80) { j++; continue; } if (status < 0x80) {
j++;
continue;
}
U8 kind = status & 0xF0; U8 kind = status & 0xF0;
@@ -92,7 +95,8 @@ static void midi_read_callback(const MIDIPacketList *pktlist, void *readProcRefC
} else if (kind == 0xF0) { } else if (kind == 0xF0) {
// System messages — skip to end or next status byte // System messages — skip to end or next status byte
j++; j++;
while (j < packet->length && packet->data[j] < 0x80) j++; while (j < packet->length && packet->data[j] < 0x80)
j++;
} else { } else {
j += 3; // Default: 3-byte message j += 3; // Default: 3-byte message
} }

View File

@@ -1,7 +1,7 @@
#include "midi/midi.h" #include "midi/midi.h"
#include <windows.h>
#include <mmeapi.h> #include <mmeapi.h>
#include <string.h> #include <string.h>
#include <windows.h>
#define MIDI_MAX_DEVICES 64 #define MIDI_MAX_DEVICES 64
#define MIDI_RELEASE_FLASH_DURATION 0.15f #define MIDI_RELEASE_FLASH_DURATION 0.15f

View File

@@ -4,16 +4,27 @@
// macOS virtual key codes (avoids Carbon.h include) // macOS virtual key codes (avoids Carbon.h include)
enum { enum {
kVK_ANSI_A = 0x00, kVK_ANSI_C = 0x08, kVK_ANSI_V = 0x09, kVK_ANSI_A = 0x00,
kVK_ANSI_C = 0x08,
kVK_ANSI_V = 0x09,
kVK_ANSI_X = 0x07, kVK_ANSI_X = 0x07,
kVK_Return = 0x24, kVK_Tab = 0x30, kVK_Delete = 0x33, kVK_Return = 0x24,
kVK_Escape = 0x35, kVK_ForwardDelete = 0x75, kVK_Tab = 0x30,
kVK_LeftArrow = 0x7B, kVK_RightArrow = 0x7C, kVK_Delete = 0x33,
kVK_DownArrow = 0x7D, kVK_UpArrow = 0x7E, kVK_Escape = 0x35,
kVK_Home = 0x73, kVK_End = 0x77, kVK_ForwardDelete = 0x75,
kVK_Command = 0x37, kVK_Shift = 0x38, kVK_LeftArrow = 0x7B,
kVK_RightShift = 0x3C, kVK_RightCommand = 0x36, kVK_RightArrow = 0x7C,
kVK_ANSI_Equal = 0x18, kVK_ANSI_Minus = 0x1B, kVK_DownArrow = 0x7D,
kVK_UpArrow = 0x7E,
kVK_Home = 0x73,
kVK_End = 0x77,
kVK_Command = 0x37,
kVK_Shift = 0x38,
kVK_RightShift = 0x3C,
kVK_RightCommand = 0x36,
kVK_ANSI_Equal = 0x18,
kVK_ANSI_Minus = 0x1B,
kVK_ANSI_0 = 0x1D, kVK_ANSI_0 = 0x1D,
kVK_ANSI_KeypadEnter = 0x4C, kVK_ANSI_KeypadEnter = 0x4C,
}; };
@@ -28,7 +39,7 @@ static U8 macos_keycode_to_pkey(U16 keycode) {
case kVK_ANSI_KeypadEnter: return PKEY_RETURN; case kVK_ANSI_KeypadEnter: return PKEY_RETURN;
case kVK_Tab: return PKEY_TAB; case kVK_Tab: return PKEY_TAB;
case kVK_Delete: return PKEY_BACKSPACE; case kVK_Delete: return PKEY_BACKSPACE;
case kVK_ForwardDelete:return PKEY_DELETE; case kVK_ForwardDelete: return PKEY_DELETE;
case kVK_Escape: return PKEY_ESCAPE; case kVK_Escape: return PKEY_ESCAPE;
case kVK_LeftArrow: return PKEY_LEFT; case kVK_LeftArrow: return PKEY_LEFT;
case kVK_RightArrow: return PKEY_RIGHT; case kVK_RightArrow: return PKEY_RIGHT;
@@ -58,18 +69,23 @@ static PlatformWindow *g_main_window = nullptr;
@end @end
@implementation ASmplAppDelegate @implementation ASmplAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification { (void)notification; } - (void)applicationDidFinishLaunching:(NSNotification *)notification {
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { (void)sender; return YES; } (void)notification;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
(void)sender;
return YES;
}
@end @end
@interface ASmplWindowDelegate : NSObject <NSWindowDelegate> { @interface ASmplWindowDelegate : NSObject <NSWindowDelegate> {
@public @public
PlatformWindow *_platformWindow; PlatformWindow *_platformWindow;
} }
@end @end
@interface ASmplView : NSView <NSTextInputClient> { @interface ASmplView : NSView <NSTextInputClient> {
@public @public
PlatformWindow *_platformWindow; PlatformWindow *_platformWindow;
} }
@end @end
@@ -101,7 +117,10 @@ static void platform_macos_insert_text_pw(PlatformWindow *pw, const char *utf8)
PlatformInput *ev = &pw->input; PlatformInput *ev = &pw->input;
while (*utf8 && ev->char_count < PLATFORM_MAX_CHARS_PER_FRAME) { while (*utf8 && ev->char_count < PLATFORM_MAX_CHARS_PER_FRAME) {
U8 c = (U8)*utf8; U8 c = (U8)*utf8;
if (c < 32) { utf8++; continue; } if (c < 32) {
utf8++;
continue;
}
// Handle ASCII printable range (single-byte UTF-8) // Handle ASCII printable range (single-byte UTF-8)
if (c < 0x80) { if (c < 0x80) {
ev->chars[ev->char_count++] = (U16)c; ev->chars[ev->char_count++] = (U16)c;
@@ -155,25 +174,45 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
@implementation ASmplView @implementation ASmplView
- (BOOL)acceptsFirstResponder { return YES; } - (BOOL)acceptsFirstResponder {
- (BOOL)canBecomeKeyView { return YES; } return YES;
}
- (BOOL)canBecomeKeyView {
return YES;
}
// Needed for NSTextInputClient // Needed for NSTextInputClient
- (BOOL)hasMarkedText { return NO; } - (BOOL)hasMarkedText {
- (NSRange)markedRange { return NSMakeRange(NSNotFound, 0); } return NO;
- (NSRange)selectedRange { return NSMakeRange(NSNotFound, 0); } }
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange { - (NSRange)markedRange {
(void)string; (void)selectedRange; (void)replacementRange; return NSMakeRange(NSNotFound, 0);
}
- (NSRange)selectedRange {
return NSMakeRange(NSNotFound, 0);
}
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
(void)string;
(void)selectedRange;
(void)replacementRange;
}
- (void)unmarkText {
}
- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText {
return @[];
} }
- (void)unmarkText {}
- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText { return @[]; }
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange {
(void)range; (void)actualRange; (void)range;
(void)actualRange;
return nil; return nil;
} }
- (NSUInteger)characterIndexForPoint:(NSPoint)point { (void)point; return NSNotFound; } - (NSUInteger)characterIndexForPoint:(NSPoint)point {
(void)point;
return NSNotFound;
}
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange {
(void)range; (void)actualRange; (void)range;
(void)actualRange;
return NSZeroRect; return NSZeroRect;
} }
@@ -192,7 +231,7 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
platform_macos_key_down_pw(_platformWindow, [event keyCode], [event modifierFlags]); platform_macos_key_down_pw(_platformWindow, [event keyCode], [event modifierFlags]);
// Feed into text input system for character generation // Feed into text input system for character generation
[self interpretKeyEvents:@[event]]; [self interpretKeyEvents:@[ event ]];
} }
- (void)flagsChanged:(NSEvent *)event { - (void)flagsChanged:(NSEvent *)event {
@@ -210,8 +249,12 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
if (_platformWindow) _platformWindow->mouse_down_state = 0; if (_platformWindow) _platformWindow->mouse_down_state = 0;
} }
- (void)mouseMoved:(NSEvent *)event { (void)event; } - (void)mouseMoved:(NSEvent *)event {
- (void)mouseDragged:(NSEvent *)event { (void)event; } (void)event;
}
- (void)mouseDragged:(NSEvent *)event {
(void)event;
}
- (void)scrollWheel:(NSEvent *)event { - (void)scrollWheel:(NSEvent *)event {
if (!_platformWindow) return; if (!_platformWindow) return;
@@ -221,7 +264,10 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
_platformWindow->input.scroll_delta.y += dy; _platformWindow->input.scroll_delta.y += dy;
} }
- (BOOL)acceptsFirstMouse:(NSEvent *)event { (void)event; return YES; } - (BOOL)acceptsFirstMouse:(NSEvent *)event {
(void)event;
return YES;
}
@end @end

View File

@@ -3,8 +3,8 @@
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h>
#include <malloc.h> #include <malloc.h>
#include <windows.h>
struct PlatformWindow { struct PlatformWindow {
HWND hwnd; HWND hwnd;
@@ -143,8 +143,7 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
x, y, x, y,
rect.right - rect.left, rect.right - rect.left,
rect.bottom - rect.top, rect.bottom - rect.top,
parent_hwnd, nullptr, GetModuleHandleW(nullptr), nullptr parent_hwnd, nullptr, GetModuleHandleW(nullptr), nullptr);
);
_freea(wtitle); _freea(wtitle);

View File

@@ -30,8 +30,8 @@
#include "renderer/font_inter.gen.h" #include "renderer/font_inter.gen.h"
// Embedded SPIR-V shaders (generated at build time by glslc) // Embedded SPIR-V shaders (generated at build time by glslc)
#include "renderer/ui_vert.spv.h"
#include "renderer/ui_frag.spv.h" #include "renderer/ui_frag.spv.h"
#include "renderer/ui_vert.spv.h"
#define NUM_BACK_BUFFERS 2 #define NUM_BACK_BUFFERS 2
#define MAX_VERTICES (64 * 1024) #define MAX_VERTICES (64 * 1024)
@@ -172,9 +172,9 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type, VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *data, const VkDebugUtilsMessengerCallbackDataEXT *data,
void *user_data) void *user_data) {
{ (void)type;
(void)type; (void)user_data; (void)user_data;
if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
OutputDebugStringA("VK: "); OutputDebugStringA("VK: ");
OutputDebugStringA(data->pMessage); OutputDebugStringA(data->pMessage);
@@ -188,7 +188,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
// Helper: begin/end one-shot command buffer // Helper: begin/end one-shot command buffer
static VkCommandBuffer begin_one_shot(Renderer *r) { static VkCommandBuffer begin_one_shot(Renderer *r) {
VkCommandBufferAllocateInfo ai = {0}; VkCommandBufferAllocateInfo ai = { 0 };
ai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; ai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
ai.commandPool = r->command_pool; ai.commandPool = r->command_pool;
ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
@@ -196,7 +196,7 @@ static VkCommandBuffer begin_one_shot(Renderer *r) {
VkCommandBuffer cb; VkCommandBuffer cb;
vkAllocateCommandBuffers(r->device, &ai, &cb); vkAllocateCommandBuffers(r->device, &ai, &cb);
VkCommandBufferBeginInfo bi = {0}; VkCommandBufferBeginInfo bi = { 0 };
bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cb, &bi); vkBeginCommandBuffer(cb, &bi);
@@ -205,7 +205,7 @@ static VkCommandBuffer begin_one_shot(Renderer *r) {
static void end_one_shot(Renderer *r, VkCommandBuffer cb) { static void end_one_shot(Renderer *r, VkCommandBuffer cb) {
vkEndCommandBuffer(cb); vkEndCommandBuffer(cb);
VkSubmitInfo si = {0}; VkSubmitInfo si = { 0 };
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
si.commandBufferCount = 1; si.commandBufferCount = 1;
si.pCommandBuffers = &cb; si.pCommandBuffers = &cb;
@@ -220,9 +220,8 @@ static void end_one_shot(Renderer *r, VkCommandBuffer cb) {
static void transition_image(VkCommandBuffer cb, VkImage image, static void transition_image(VkCommandBuffer cb, VkImage image,
VkImageLayout old_layout, VkImageLayout new_layout, VkImageLayout old_layout, VkImageLayout new_layout,
VkAccessFlags src_access, VkAccessFlags dst_access, VkAccessFlags src_access, VkAccessFlags dst_access,
VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage) VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage) {
{ VkImageMemoryBarrier barrier = { 0 };
VkImageMemoryBarrier barrier = {0};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = old_layout; barrier.oldLayout = old_layout;
barrier.newLayout = new_layout; barrier.newLayout = new_layout;
@@ -243,7 +242,7 @@ static void transition_image(VkCommandBuffer cb, VkImage image,
// Vulkan infrastructure // Vulkan infrastructure
static B32 create_instance(Renderer *r) { static B32 create_instance(Renderer *r) {
VkApplicationInfo app_info = {0}; VkApplicationInfo app_info = { 0 };
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = "autosample"; app_info.pApplicationName = "autosample";
app_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0); app_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
@@ -265,7 +264,7 @@ static B32 create_instance(Renderer *r) {
#endif #endif
}; };
VkInstanceCreateInfo ci = {0}; VkInstanceCreateInfo ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
ci.pApplicationInfo = &app_info; ci.pApplicationInfo = &app_info;
ci.enabledExtensionCount = ArrayCount(extensions); ci.enabledExtensionCount = ArrayCount(extensions);
@@ -278,13 +277,10 @@ static B32 create_instance(Renderer *r) {
#ifdef _DEBUG #ifdef _DEBUG
{ {
VkDebugUtilsMessengerCreateInfoEXT dbg = {0}; VkDebugUtilsMessengerCreateInfoEXT dbg = { 0 };
dbg.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; dbg.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
dbg.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT dbg.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; dbg.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
dbg.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
dbg.pfnUserCallback = vk_debug_callback; dbg.pfnUserCallback = vk_debug_callback;
PFN_vkCreateDebugUtilsMessengerEXT func = PFN_vkCreateDebugUtilsMessengerEXT func =
@@ -297,7 +293,7 @@ static B32 create_instance(Renderer *r) {
} }
static B32 create_surface(Renderer *r) { static B32 create_surface(Renderer *r) {
VkWin32SurfaceCreateInfoKHR ci = {0}; VkWin32SurfaceCreateInfoKHR ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; ci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
ci.hinstance = GetModuleHandle(NULL); ci.hinstance = GetModuleHandle(NULL);
ci.hwnd = r->hwnd; ci.hwnd = r->hwnd;
@@ -346,7 +342,7 @@ static B32 find_queue_family(Renderer *r) {
static B32 create_device(Renderer *r) { static B32 create_device(Renderer *r) {
float priority = 1.0f; float priority = 1.0f;
VkDeviceQueueCreateInfo queue_ci = {0}; VkDeviceQueueCreateInfo queue_ci = { 0 };
queue_ci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_ci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_ci.queueFamilyIndex = r->queue_family; queue_ci.queueFamilyIndex = r->queue_family;
queue_ci.queueCount = 1; queue_ci.queueCount = 1;
@@ -354,7 +350,7 @@ static B32 create_device(Renderer *r) {
const char *extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; const char *extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
VkDeviceCreateInfo ci = {0}; VkDeviceCreateInfo ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
ci.queueCreateInfoCount = 1; ci.queueCreateInfoCount = 1;
ci.pQueueCreateInfos = &queue_ci; ci.pQueueCreateInfos = &queue_ci;
@@ -369,7 +365,7 @@ static B32 create_device(Renderer *r) {
} }
static B32 create_vma(Renderer *r) { static B32 create_vma(Renderer *r) {
VmaAllocatorCreateInfo ci = {0}; VmaAllocatorCreateInfo ci = { 0 };
ci.physicalDevice = r->physical_device; ci.physicalDevice = r->physical_device;
ci.device = r->device; ci.device = r->device;
ci.instance = r->instance; ci.instance = r->instance;
@@ -426,7 +422,7 @@ static B32 create_swap_chain(Renderer *r) {
if (caps.maxImageCount > 0 && image_count > caps.maxImageCount) if (caps.maxImageCount > 0 && image_count > caps.maxImageCount)
image_count = caps.maxImageCount; image_count = caps.maxImageCount;
VkSwapchainCreateInfoKHR ci = {0}; VkSwapchainCreateInfoKHR ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
ci.surface = r->surface; ci.surface = r->surface;
ci.minImageCount = image_count; ci.minImageCount = image_count;
@@ -451,7 +447,7 @@ static B32 create_swap_chain(Renderer *r) {
// Create image views // Create image views
for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) { for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) {
VkImageViewCreateInfo vi = {0}; VkImageViewCreateInfo vi = { 0 };
vi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vi.image = r->swap_chain_images[i]; vi.image = r->swap_chain_images[i];
vi.viewType = VK_IMAGE_VIEW_TYPE_2D; vi.viewType = VK_IMAGE_VIEW_TYPE_2D;
@@ -469,7 +465,7 @@ static B32 create_swap_chain(Renderer *r) {
} }
static B32 create_render_pass(Renderer *r) { static B32 create_render_pass(Renderer *r) {
VkAttachmentDescription color_attach = {0}; VkAttachmentDescription color_attach = { 0 };
color_attach.format = r->swap_chain_format; color_attach.format = r->swap_chain_format;
color_attach.samples = VK_SAMPLE_COUNT_1_BIT; color_attach.samples = VK_SAMPLE_COUNT_1_BIT;
color_attach.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; color_attach.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
@@ -479,16 +475,16 @@ static B32 create_render_pass(Renderer *r) {
color_attach.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; color_attach.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
color_attach.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; color_attach.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference color_ref = {0}; VkAttachmentReference color_ref = { 0 };
color_ref.attachment = 0; color_ref.attachment = 0;
color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {0}; VkSubpassDescription subpass = { 0 };
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1; subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_ref; subpass.pColorAttachments = &color_ref;
VkSubpassDependency dep = {0}; VkSubpassDependency dep = { 0 };
dep.srcSubpass = VK_SUBPASS_EXTERNAL; dep.srcSubpass = VK_SUBPASS_EXTERNAL;
dep.dstSubpass = 0; dep.dstSubpass = 0;
dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
@@ -496,7 +492,7 @@ static B32 create_render_pass(Renderer *r) {
dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo ci = {0}; VkRenderPassCreateInfo ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
ci.attachmentCount = 1; ci.attachmentCount = 1;
ci.pAttachments = &color_attach; ci.pAttachments = &color_attach;
@@ -510,7 +506,7 @@ static B32 create_render_pass(Renderer *r) {
static B32 create_framebuffers(Renderer *r) { static B32 create_framebuffers(Renderer *r) {
for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) { for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) {
VkFramebufferCreateInfo ci = {0}; VkFramebufferCreateInfo ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
ci.renderPass = r->render_pass; ci.renderPass = r->render_pass;
ci.attachmentCount = 1; ci.attachmentCount = 1;
@@ -525,14 +521,14 @@ static B32 create_framebuffers(Renderer *r) {
} }
static B32 create_command_resources(Renderer *r) { static B32 create_command_resources(Renderer *r) {
VkCommandPoolCreateInfo pool_ci = {0}; VkCommandPoolCreateInfo pool_ci = { 0 };
pool_ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; pool_ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_ci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; pool_ci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
pool_ci.queueFamilyIndex = r->queue_family; pool_ci.queueFamilyIndex = r->queue_family;
if (vkCreateCommandPool(r->device, &pool_ci, NULL, &r->command_pool) != VK_SUCCESS) if (vkCreateCommandPool(r->device, &pool_ci, NULL, &r->command_pool) != VK_SUCCESS)
return 0; return 0;
VkCommandBufferAllocateInfo alloc_info = {0}; VkCommandBufferAllocateInfo alloc_info = { 0 };
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.commandPool = r->command_pool; alloc_info.commandPool = r->command_pool;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
@@ -545,7 +541,7 @@ static B32 create_command_resources(Renderer *r) {
for (S32 i = 0; i < NUM_BACK_BUFFERS; i++) { for (S32 i = 0; i < NUM_BACK_BUFFERS; i++) {
r->frames[i].command_buffer = cbs[i]; r->frames[i].command_buffer = cbs[i];
VkFenceCreateInfo fence_ci = {0}; VkFenceCreateInfo fence_ci = { 0 };
fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_ci.flags = VK_FENCE_CREATE_SIGNALED_BIT; fence_ci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
if (vkCreateFence(r->device, &fence_ci, NULL, &r->frames[i].fence) != VK_SUCCESS) if (vkCreateFence(r->device, &fence_ci, NULL, &r->frames[i].fence) != VK_SUCCESS)
@@ -553,7 +549,7 @@ static B32 create_command_resources(Renderer *r) {
} }
for (S32 i = 0; i < NUM_BACK_BUFFERS; i++) { for (S32 i = 0; i < NUM_BACK_BUFFERS; i++) {
VkSemaphoreCreateInfo sem_ci = {0}; VkSemaphoreCreateInfo sem_ci = { 0 };
sem_ci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; sem_ci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
if (vkCreateSemaphore(r->device, &sem_ci, NULL, &r->image_available_sema[i]) != VK_SUCCESS) if (vkCreateSemaphore(r->device, &sem_ci, NULL, &r->image_available_sema[i]) != VK_SUCCESS)
return 0; return 0;
@@ -565,7 +561,7 @@ static B32 create_command_resources(Renderer *r) {
} }
static B32 create_sampler(Renderer *r) { static B32 create_sampler(Renderer *r) {
VkSamplerCreateInfo ci = {0}; VkSamplerCreateInfo ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
ci.magFilter = VK_FILTER_LINEAR; ci.magFilter = VK_FILTER_LINEAR;
ci.minFilter = VK_FILTER_LINEAR; ci.minFilter = VK_FILTER_LINEAR;
@@ -578,13 +574,13 @@ static B32 create_sampler(Renderer *r) {
static B32 create_descriptor_resources(Renderer *r) { static B32 create_descriptor_resources(Renderer *r) {
// Descriptor set layout: single combined image sampler at binding 0 // Descriptor set layout: single combined image sampler at binding 0
VkDescriptorSetLayoutBinding binding = {0}; VkDescriptorSetLayoutBinding binding = { 0 };
binding.binding = 0; binding.binding = 0;
binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding.descriptorCount = 1; binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo layout_ci = {0}; VkDescriptorSetLayoutCreateInfo layout_ci = { 0 };
layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_ci.bindingCount = 1; layout_ci.bindingCount = 1;
layout_ci.pBindings = &binding; layout_ci.pBindings = &binding;
@@ -592,11 +588,11 @@ static B32 create_descriptor_resources(Renderer *r) {
return 0; return 0;
// Descriptor pool: 2 sets (font + icon) // Descriptor pool: 2 sets (font + icon)
VkDescriptorPoolSize pool_size = {0}; VkDescriptorPoolSize pool_size = { 0 };
pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pool_size.descriptorCount = 2; pool_size.descriptorCount = 2;
VkDescriptorPoolCreateInfo pool_ci = {0}; VkDescriptorPoolCreateInfo pool_ci = { 0 };
pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_ci.maxSets = 2; pool_ci.maxSets = 2;
pool_ci.poolSizeCount = 1; pool_ci.poolSizeCount = 1;
@@ -605,7 +601,7 @@ static B32 create_descriptor_resources(Renderer *r) {
return 0; return 0;
// Allocate font descriptor set // Allocate font descriptor set
VkDescriptorSetAllocateInfo alloc_info = {0}; VkDescriptorSetAllocateInfo alloc_info = { 0 };
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = r->descriptor_pool; alloc_info.descriptorPool = r->descriptor_pool;
alloc_info.descriptorSetCount = 1; alloc_info.descriptorSetCount = 1;
@@ -617,7 +613,7 @@ static B32 create_descriptor_resources(Renderer *r) {
} }
static VkShaderModule create_shader_module(Renderer *r, const U32 *code, size_t size) { static VkShaderModule create_shader_module(Renderer *r, const U32 *code, size_t size) {
VkShaderModuleCreateInfo ci = {0}; VkShaderModuleCreateInfo ci = { 0 };
ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
ci.codeSize = size; ci.codeSize = size;
ci.pCode = code; ci.pCode = code;
@@ -631,7 +627,7 @@ static B32 create_pipeline(Renderer *r) {
VkShaderModule frag_module = create_shader_module(r, ui_frag_spv, sizeof(ui_frag_spv)); VkShaderModule frag_module = create_shader_module(r, ui_frag_spv, sizeof(ui_frag_spv));
if (!vert_module || !frag_module) return 0; if (!vert_module || !frag_module) return 0;
VkPipelineShaderStageCreateInfo stages[2] = {{0}, {0}}; VkPipelineShaderStageCreateInfo stages[2] = { { 0 }, { 0 } };
stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
stages[0].module = vert_module; stages[0].module = vert_module;
@@ -642,57 +638,84 @@ static B32 create_pipeline(Renderer *r) {
stages[1].pName = "main"; stages[1].pName = "main";
// Vertex input // Vertex input
VkVertexInputBindingDescription binding = {0}; VkVertexInputBindingDescription binding = { 0 };
binding.binding = 0; binding.binding = 0;
binding.stride = sizeof(UIVertex); binding.stride = sizeof(UIVertex);
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription attrs[9] = {}; VkVertexInputAttributeDescription attrs[9] = {};
attrs[0].location = 0; attrs[0].binding = 0; attrs[0].format = VK_FORMAT_R32G32_SFLOAT; attrs[0].offset = offsetof(UIVertex, pos); attrs[0].location = 0;
attrs[1].location = 1; attrs[1].binding = 0; attrs[1].format = VK_FORMAT_R32G32_SFLOAT; attrs[1].offset = offsetof(UIVertex, uv); attrs[0].binding = 0;
attrs[2].location = 2; attrs[2].binding = 0; attrs[2].format = VK_FORMAT_R32G32B32A32_SFLOAT; attrs[2].offset = offsetof(UIVertex, col); attrs[0].format = VK_FORMAT_R32G32_SFLOAT;
attrs[3].location = 3; attrs[3].binding = 0; attrs[3].format = VK_FORMAT_R32G32_SFLOAT; attrs[3].offset = offsetof(UIVertex, rect_min); attrs[0].offset = offsetof(UIVertex, pos);
attrs[4].location = 4; attrs[4].binding = 0; attrs[4].format = VK_FORMAT_R32G32_SFLOAT; attrs[4].offset = offsetof(UIVertex, rect_max); attrs[1].location = 1;
attrs[5].location = 5; attrs[5].binding = 0; attrs[5].format = VK_FORMAT_R32G32B32A32_SFLOAT; attrs[5].offset = offsetof(UIVertex, corner_radii); attrs[1].binding = 0;
attrs[6].location = 6; attrs[6].binding = 0; attrs[6].format = VK_FORMAT_R32_SFLOAT; attrs[6].offset = offsetof(UIVertex, border_thickness); attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
attrs[7].location = 7; attrs[7].binding = 0; attrs[7].format = VK_FORMAT_R32_SFLOAT; attrs[7].offset = offsetof(UIVertex, softness); attrs[1].offset = offsetof(UIVertex, uv);
attrs[8].location = 8; attrs[8].binding = 0; attrs[8].format = VK_FORMAT_R32_SFLOAT; attrs[8].offset = offsetof(UIVertex, mode); attrs[2].location = 2;
attrs[2].binding = 0;
attrs[2].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attrs[2].offset = offsetof(UIVertex, col);
attrs[3].location = 3;
attrs[3].binding = 0;
attrs[3].format = VK_FORMAT_R32G32_SFLOAT;
attrs[3].offset = offsetof(UIVertex, rect_min);
attrs[4].location = 4;
attrs[4].binding = 0;
attrs[4].format = VK_FORMAT_R32G32_SFLOAT;
attrs[4].offset = offsetof(UIVertex, rect_max);
attrs[5].location = 5;
attrs[5].binding = 0;
attrs[5].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attrs[5].offset = offsetof(UIVertex, corner_radii);
attrs[6].location = 6;
attrs[6].binding = 0;
attrs[6].format = VK_FORMAT_R32_SFLOAT;
attrs[6].offset = offsetof(UIVertex, border_thickness);
attrs[7].location = 7;
attrs[7].binding = 0;
attrs[7].format = VK_FORMAT_R32_SFLOAT;
attrs[7].offset = offsetof(UIVertex, softness);
attrs[8].location = 8;
attrs[8].binding = 0;
attrs[8].format = VK_FORMAT_R32_SFLOAT;
attrs[8].offset = offsetof(UIVertex, mode);
VkPipelineVertexInputStateCreateInfo vertex_input = {0}; VkPipelineVertexInputStateCreateInfo vertex_input = { 0 };
vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input.vertexBindingDescriptionCount = 1; vertex_input.vertexBindingDescriptionCount = 1;
vertex_input.pVertexBindingDescriptions = &binding; vertex_input.pVertexBindingDescriptions = &binding;
vertex_input.vertexAttributeDescriptionCount = 9; vertex_input.vertexAttributeDescriptionCount = 9;
vertex_input.pVertexAttributeDescriptions = attrs; vertex_input.pVertexAttributeDescriptions = attrs;
VkPipelineInputAssemblyStateCreateInfo input_assembly = {0}; VkPipelineInputAssemblyStateCreateInfo input_assembly = { 0 };
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
// Dynamic viewport/scissor // Dynamic viewport/scissor
VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamic_state = {0}; VkPipelineDynamicStateCreateInfo dynamic_state = { 0 };
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state.dynamicStateCount = 2; dynamic_state.dynamicStateCount = 2;
dynamic_state.pDynamicStates = dynamic_states; dynamic_state.pDynamicStates = dynamic_states;
VkPipelineViewportStateCreateInfo viewport_state = {0}; VkPipelineViewportStateCreateInfo viewport_state = { 0 };
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state.viewportCount = 1; viewport_state.viewportCount = 1;
viewport_state.scissorCount = 1; viewport_state.scissorCount = 1;
VkPipelineRasterizationStateCreateInfo rasterizer = {0}; VkPipelineRasterizationStateCreateInfo rasterizer = { 0 };
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f; rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_NONE; rasterizer.cullMode = VK_CULL_MODE_NONE;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
VkPipelineMultisampleStateCreateInfo multisample = {0}; VkPipelineMultisampleStateCreateInfo multisample = { 0 };
multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState blend_attach = {0}; VkPipelineColorBlendAttachmentState blend_attach = { 0 };
blend_attach.blendEnable = VK_TRUE; blend_attach.blendEnable = VK_TRUE;
blend_attach.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blend_attach.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blend_attach.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blend_attach.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
@@ -700,24 +723,23 @@ static B32 create_pipeline(Renderer *r) {
blend_attach.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; blend_attach.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blend_attach.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blend_attach.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attach.alphaBlendOp = VK_BLEND_OP_ADD; blend_attach.alphaBlendOp = VK_BLEND_OP_ADD;
blend_attach.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT blend_attach.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo blend = {0}; VkPipelineColorBlendStateCreateInfo blend = { 0 };
blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
blend.attachmentCount = 1; blend.attachmentCount = 1;
blend.pAttachments = &blend_attach; blend.pAttachments = &blend_attach;
VkPipelineDepthStencilStateCreateInfo depth_stencil = {0}; VkPipelineDepthStencilStateCreateInfo depth_stencil = { 0 };
depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
// Pipeline layout: push constants + 1 descriptor set // Pipeline layout: push constants + 1 descriptor set
VkPushConstantRange push_range = {0}; VkPushConstantRange push_range = { 0 };
push_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
push_range.offset = 0; push_range.offset = 0;
push_range.size = 4 * sizeof(float); // viewport_size + padding push_range.size = 4 * sizeof(float); // viewport_size + padding
VkPipelineLayoutCreateInfo layout_ci = {0}; VkPipelineLayoutCreateInfo layout_ci = { 0 };
layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layout_ci.setLayoutCount = 1; layout_ci.setLayoutCount = 1;
layout_ci.pSetLayouts = &r->descriptor_set_layout; layout_ci.pSetLayouts = &r->descriptor_set_layout;
@@ -729,7 +751,7 @@ static B32 create_pipeline(Renderer *r) {
return 0; return 0;
} }
VkGraphicsPipelineCreateInfo pipeline_ci = {0}; VkGraphicsPipelineCreateInfo pipeline_ci = { 0 };
pipeline_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_ci.stageCount = 2; pipeline_ci.stageCount = 2;
pipeline_ci.pStages = stages; pipeline_ci.pStages = stages;
@@ -755,12 +777,12 @@ static B32 create_pipeline(Renderer *r) {
static B32 create_ui_buffers(Renderer *r) { static B32 create_ui_buffers(Renderer *r) {
for (S32 i = 0; i < NUM_BACK_BUFFERS; i++) { for (S32 i = 0; i < NUM_BACK_BUFFERS; i++) {
VkBufferCreateInfo buf_ci = {0}; VkBufferCreateInfo buf_ci = { 0 };
buf_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buf_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buf_ci.size = MAX_VERTICES * sizeof(UIVertex); buf_ci.size = MAX_VERTICES * sizeof(UIVertex);
buf_ci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; buf_ci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
VmaAllocationCreateInfo alloc_ci = {0}; VmaAllocationCreateInfo alloc_ci = { 0 };
alloc_ci.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; alloc_ci.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
@@ -784,12 +806,12 @@ static B32 create_ui_buffers(Renderer *r) {
// Helper: update a descriptor set to point to an image view // Helper: update a descriptor set to point to an image view
static void update_descriptor_set(Renderer *r, VkDescriptorSet set, VkImageView view) { static void update_descriptor_set(Renderer *r, VkDescriptorSet set, VkImageView view) {
VkDescriptorImageInfo img_info = {0}; VkDescriptorImageInfo img_info = { 0 };
img_info.sampler = r->sampler; img_info.sampler = r->sampler;
img_info.imageView = view; img_info.imageView = view;
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write = {0}; VkWriteDescriptorSet write = { 0 };
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = set; write.dstSet = set;
write.dstBinding = 0; write.dstBinding = 0;
@@ -862,7 +884,7 @@ static B32 create_font_atlas(Renderer *r, F32 font_size) {
} }
// Create Vulkan image // Create Vulkan image
VkImageCreateInfo img_ci = {0}; VkImageCreateInfo img_ci = { 0 };
img_ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; img_ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
img_ci.imageType = VK_IMAGE_TYPE_2D; img_ci.imageType = VK_IMAGE_TYPE_2D;
img_ci.format = VK_FORMAT_R8_UNORM; img_ci.format = VK_FORMAT_R8_UNORM;
@@ -875,7 +897,7 @@ static B32 create_font_atlas(Renderer *r, F32 font_size) {
img_ci.tiling = VK_IMAGE_TILING_OPTIMAL; img_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
img_ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; img_ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
VmaAllocationCreateInfo alloc_ci = {0}; VmaAllocationCreateInfo alloc_ci = { 0 };
alloc_ci.usage = VMA_MEMORY_USAGE_GPU_ONLY; alloc_ci.usage = VMA_MEMORY_USAGE_GPU_ONLY;
if (vmaCreateImage(r->allocator, &img_ci, &alloc_ci, &r->font_image, &r->font_alloc, NULL) != VK_SUCCESS) { if (vmaCreateImage(r->allocator, &img_ci, &alloc_ci, &r->font_image, &r->font_alloc, NULL) != VK_SUCCESS) {
@@ -884,12 +906,12 @@ static B32 create_font_atlas(Renderer *r, F32 font_size) {
} }
// Staging buffer // Staging buffer
VkBufferCreateInfo staging_ci = {0}; VkBufferCreateInfo staging_ci = { 0 };
staging_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; staging_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
staging_ci.size = FONT_ATLAS_W * FONT_ATLAS_H; staging_ci.size = FONT_ATLAS_W * FONT_ATLAS_H;
staging_ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; staging_ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo staging_alloc_ci = {0}; VmaAllocationCreateInfo staging_alloc_ci = { 0 };
staging_alloc_ci.usage = VMA_MEMORY_USAGE_CPU_ONLY; staging_alloc_ci.usage = VMA_MEMORY_USAGE_CPU_ONLY;
staging_alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; staging_alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
@@ -908,7 +930,7 @@ static B32 create_font_atlas(Renderer *r, F32 font_size) {
0, VK_ACCESS_TRANSFER_WRITE_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
VkBufferImageCopy region = {0}; VkBufferImageCopy region = { 0 };
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1; region.imageSubresource.layerCount = 1;
region.imageExtent.width = FONT_ATLAS_W; region.imageExtent.width = FONT_ATLAS_W;
@@ -926,7 +948,7 @@ static B32 create_font_atlas(Renderer *r, F32 font_size) {
vmaDestroyBuffer(r->allocator, staging_buf, staging_alloc); vmaDestroyBuffer(r->allocator, staging_buf, staging_alloc);
// Image view // Image view
VkImageViewCreateInfo view_ci = {0}; VkImageViewCreateInfo view_ci = { 0 };
view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_ci.image = r->font_image; view_ci.image = r->font_image;
view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D; view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
@@ -977,8 +999,7 @@ static void emit_quad(DrawBatch *batch,
F32 cr, F32 cg, F32 cb, F32 ca, F32 cr, F32 cg, F32 cb, F32 ca,
F32 rmin_x, F32 rmin_y, F32 rmax_x, F32 rmax_y, F32 rmin_x, F32 rmin_y, F32 rmax_x, F32 rmax_y,
F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl, F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl,
F32 border_thickness, F32 softness, F32 mode) F32 border_thickness, F32 softness, F32 mode) {
{
if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES) if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES)
return; return;
@@ -988,28 +1009,54 @@ static void emit_quad(DrawBatch *batch,
F32 px0 = x0, py0 = y0, px1 = x1, py1 = y1; F32 px0 = x0, py0 = y0, px1 = x1, py1 = y1;
if (mode < 0.5f) { if (mode < 0.5f) {
F32 pad = softness + 1.0f; F32 pad = softness + 1.0f;
px0 -= pad; py0 -= pad; px1 += pad; py1 += pad; px0 -= pad;
py0 -= pad;
px1 += pad;
py1 += pad;
} }
v[0].pos[0] = px0; v[0].pos[1] = py0; v[0].uv[0] = u0; v[0].uv[1] = v0; v[0].pos[0] = px0;
v[1].pos[0] = px1; v[1].pos[1] = py0; v[1].uv[0] = u1; v[1].uv[1] = v0; v[0].pos[1] = py0;
v[2].pos[0] = px1; v[2].pos[1] = py1; v[2].uv[0] = u1; v[2].uv[1] = v1; v[0].uv[0] = u0;
v[3].pos[0] = px0; v[3].pos[1] = py1; v[3].uv[0] = u0; v[3].uv[1] = v1; v[0].uv[1] = v0;
v[1].pos[0] = px1;
v[1].pos[1] = py0;
v[1].uv[0] = u1;
v[1].uv[1] = v0;
v[2].pos[0] = px1;
v[2].pos[1] = py1;
v[2].uv[0] = u1;
v[2].uv[1] = v1;
v[3].pos[0] = px0;
v[3].pos[1] = py1;
v[3].uv[0] = u0;
v[3].uv[1] = v1;
for (S32 i = 0; i < 4; i++) { for (S32 i = 0; i < 4; i++) {
v[i].col[0] = cr; v[i].col[1] = cg; v[i].col[2] = cb; v[i].col[3] = ca; v[i].col[0] = cr;
v[i].rect_min[0] = rmin_x; v[i].rect_min[1] = rmin_y; v[i].col[1] = cg;
v[i].rect_max[0] = rmax_x; v[i].rect_max[1] = rmax_y; v[i].col[2] = cb;
v[i].corner_radii[0] = cr_tl; v[i].corner_radii[1] = cr_tr; v[i].col[3] = ca;
v[i].corner_radii[2] = cr_br; v[i].corner_radii[3] = cr_bl; v[i].rect_min[0] = rmin_x;
v[i].rect_min[1] = rmin_y;
v[i].rect_max[0] = rmax_x;
v[i].rect_max[1] = rmax_y;
v[i].corner_radii[0] = cr_tl;
v[i].corner_radii[1] = cr_tr;
v[i].corner_radii[2] = cr_br;
v[i].corner_radii[3] = cr_bl;
v[i].border_thickness = border_thickness; v[i].border_thickness = border_thickness;
v[i].softness = softness; v[i].softness = softness;
v[i].mode = mode; v[i].mode = mode;
} }
U32 *idx = &batch->indices[batch->index_count]; U32 *idx = &batch->indices[batch->index_count];
idx[0] = base; idx[1] = base + 1; idx[2] = base + 2; idx[0] = base;
idx[3] = base; idx[4] = base + 2; idx[5] = base + 3; idx[1] = base + 1;
idx[2] = base + 2;
idx[3] = base;
idx[4] = base + 2;
idx[5] = base + 3;
batch->vertex_count += 4; batch->vertex_count += 4;
batch->index_count += 6; batch->index_count += 6;
@@ -1019,8 +1066,7 @@ static void emit_quad_rotated(DrawBatch *batch,
F32 x0, F32 y0, F32 x1, F32 y1, F32 x0, F32 y0, F32 x1, F32 y1,
F32 u0, F32 v0, F32 u1, F32 v1, F32 u0, F32 v0, F32 u1, F32 v1,
F32 cr, F32 cg, F32 cb, F32 ca, F32 cr, F32 cg, F32 cb, F32 ca,
F32 angle_rad) F32 angle_rad) {
{
if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES) if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES)
return; return;
@@ -1037,34 +1083,49 @@ static void emit_quad_rotated(DrawBatch *batch,
v[0].pos[0] = cx + dx0 * cosA - dy0 * sinA; v[0].pos[0] = cx + dx0 * cosA - dy0 * sinA;
v[0].pos[1] = cy + dx0 * sinA + dy0 * cosA; v[0].pos[1] = cy + dx0 * sinA + dy0 * cosA;
v[0].uv[0] = u0; v[0].uv[1] = v0; v[0].uv[0] = u0;
v[0].uv[1] = v0;
v[1].pos[0] = cx + dx1 * cosA - dy0 * sinA; v[1].pos[0] = cx + dx1 * cosA - dy0 * sinA;
v[1].pos[1] = cy + dx1 * sinA + dy0 * cosA; v[1].pos[1] = cy + dx1 * sinA + dy0 * cosA;
v[1].uv[0] = u1; v[1].uv[1] = v0; v[1].uv[0] = u1;
v[1].uv[1] = v0;
v[2].pos[0] = cx + dx1 * cosA - dy1 * sinA; v[2].pos[0] = cx + dx1 * cosA - dy1 * sinA;
v[2].pos[1] = cy + dx1 * sinA + dy1 * cosA; v[2].pos[1] = cy + dx1 * sinA + dy1 * cosA;
v[2].uv[0] = u1; v[2].uv[1] = v1; v[2].uv[0] = u1;
v[2].uv[1] = v1;
v[3].pos[0] = cx + dx0 * cosA - dy1 * sinA; v[3].pos[0] = cx + dx0 * cosA - dy1 * sinA;
v[3].pos[1] = cy + dx0 * sinA + dy1 * cosA; v[3].pos[1] = cy + dx0 * sinA + dy1 * cosA;
v[3].uv[0] = u0; v[3].uv[1] = v1; v[3].uv[0] = u0;
v[3].uv[1] = v1;
for (S32 i = 0; i < 4; i++) { for (S32 i = 0; i < 4; i++) {
v[i].col[0] = cr; v[i].col[1] = cg; v[i].col[2] = cb; v[i].col[3] = ca; v[i].col[0] = cr;
v[i].rect_min[0] = 0; v[i].rect_min[1] = 0; v[i].col[1] = cg;
v[i].rect_max[0] = 0; v[i].rect_max[1] = 0; v[i].col[2] = cb;
v[i].corner_radii[0] = 0; v[i].corner_radii[1] = 0; v[i].col[3] = ca;
v[i].corner_radii[2] = 0; v[i].corner_radii[3] = 0; v[i].rect_min[0] = 0;
v[i].rect_min[1] = 0;
v[i].rect_max[0] = 0;
v[i].rect_max[1] = 0;
v[i].corner_radii[0] = 0;
v[i].corner_radii[1] = 0;
v[i].corner_radii[2] = 0;
v[i].corner_radii[3] = 0;
v[i].border_thickness = 0; v[i].border_thickness = 0;
v[i].softness = 0; v[i].softness = 0;
v[i].mode = 2.0f; v[i].mode = 2.0f;
} }
U32 *idx = &batch->indices[batch->index_count]; U32 *idx = &batch->indices[batch->index_count];
idx[0] = base; idx[1] = base + 1; idx[2] = base + 2; idx[0] = base;
idx[3] = base; idx[4] = base + 2; idx[5] = base + 3; idx[1] = base + 1;
idx[2] = base + 2;
idx[3] = base;
idx[4] = base + 2;
idx[5] = base + 3;
batch->vertex_count += 4; batch->vertex_count += 4;
batch->index_count += 6; batch->index_count += 6;
@@ -1074,8 +1135,7 @@ static void emit_rect(DrawBatch *batch,
F32 x0, F32 y0, F32 x1, F32 y1, F32 x0, F32 y0, F32 x1, F32 y1,
F32 cr, F32 cg, F32 cb, F32 ca, F32 cr, F32 cg, F32 cb, F32 ca,
F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl, F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl,
F32 border_thickness, F32 softness) F32 border_thickness, F32 softness) {
{
emit_quad(batch, x0, y0, x1, y1, emit_quad(batch, x0, y0, x1, y1,
0, 0, 0, 0, 0, 0, 0, 0,
cr, cg, cb, ca, cr, cg, cb, ca,
@@ -1089,8 +1149,7 @@ static void emit_rect_vgradient(DrawBatch *batch,
F32 tr, F32 tg, F32 tb, F32 ta, F32 tr, F32 tg, F32 tb, F32 ta,
F32 br, F32 bg, F32 bb_, F32 ba, F32 br, F32 bg, F32 bb_, F32 ba,
F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl, F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl,
F32 softness) F32 softness) {
{
if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES) if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES)
return; return;
@@ -1100,29 +1159,61 @@ static void emit_rect_vgradient(DrawBatch *batch,
F32 pad = softness + 1.0f; F32 pad = softness + 1.0f;
F32 px0 = x0 - pad, py0 = y0 - pad, px1 = x1 + pad, py1 = y1 + pad; F32 px0 = x0 - pad, py0 = y0 - pad, px1 = x1 + pad, py1 = y1 + pad;
v[0].pos[0] = px0; v[0].pos[1] = py0; v[0].uv[0] = 0; v[0].uv[1] = 0; v[0].pos[0] = px0;
v[1].pos[0] = px1; v[1].pos[1] = py0; v[1].uv[0] = 0; v[1].uv[1] = 0; v[0].pos[1] = py0;
v[2].pos[0] = px1; v[2].pos[1] = py1; v[2].uv[0] = 0; v[2].uv[1] = 0; v[0].uv[0] = 0;
v[3].pos[0] = px0; v[3].pos[1] = py1; v[3].uv[0] = 0; v[3].uv[1] = 0; v[0].uv[1] = 0;
v[1].pos[0] = px1;
v[1].pos[1] = py0;
v[1].uv[0] = 0;
v[1].uv[1] = 0;
v[2].pos[0] = px1;
v[2].pos[1] = py1;
v[2].uv[0] = 0;
v[2].uv[1] = 0;
v[3].pos[0] = px0;
v[3].pos[1] = py1;
v[3].uv[0] = 0;
v[3].uv[1] = 0;
v[0].col[0] = tr; v[0].col[1] = tg; v[0].col[2] = tb; v[0].col[3] = ta; v[0].col[0] = tr;
v[1].col[0] = tr; v[1].col[1] = tg; v[1].col[2] = tb; v[1].col[3] = ta; v[0].col[1] = tg;
v[2].col[0] = br; v[2].col[1] = bg; v[2].col[2] = bb_; v[2].col[3] = ba; v[0].col[2] = tb;
v[3].col[0] = br; v[3].col[1] = bg; v[3].col[2] = bb_; v[3].col[3] = ba; v[0].col[3] = ta;
v[1].col[0] = tr;
v[1].col[1] = tg;
v[1].col[2] = tb;
v[1].col[3] = ta;
v[2].col[0] = br;
v[2].col[1] = bg;
v[2].col[2] = bb_;
v[2].col[3] = ba;
v[3].col[0] = br;
v[3].col[1] = bg;
v[3].col[2] = bb_;
v[3].col[3] = ba;
for (S32 i = 0; i < 4; i++) { for (S32 i = 0; i < 4; i++) {
v[i].rect_min[0] = x0; v[i].rect_min[1] = y0; v[i].rect_min[0] = x0;
v[i].rect_max[0] = x1; v[i].rect_max[1] = y1; v[i].rect_min[1] = y0;
v[i].corner_radii[0] = cr_tl; v[i].corner_radii[1] = cr_tr; v[i].rect_max[0] = x1;
v[i].corner_radii[2] = cr_br; v[i].corner_radii[3] = cr_bl; v[i].rect_max[1] = y1;
v[i].corner_radii[0] = cr_tl;
v[i].corner_radii[1] = cr_tr;
v[i].corner_radii[2] = cr_br;
v[i].corner_radii[3] = cr_bl;
v[i].border_thickness = 0; v[i].border_thickness = 0;
v[i].softness = softness; v[i].softness = softness;
v[i].mode = 0; v[i].mode = 0;
} }
U32 *idx = &batch->indices[batch->index_count]; U32 *idx = &batch->indices[batch->index_count];
idx[0] = base; idx[1] = base + 1; idx[2] = base + 2; idx[0] = base;
idx[3] = base; idx[4] = base + 2; idx[5] = base + 3; idx[1] = base + 1;
idx[2] = base + 2;
idx[3] = base;
idx[4] = base + 2;
idx[5] = base + 3;
batch->vertex_count += 4; batch->vertex_count += 4;
batch->index_count += 6; batch->index_count += 6;
@@ -1130,8 +1221,7 @@ static void emit_rect_vgradient(DrawBatch *batch,
static void emit_text_glyphs(DrawBatch *batch, Renderer *r, static void emit_text_glyphs(DrawBatch *batch, Renderer *r,
Clay_BoundingBox bbox, Clay_Color color, const char *text, S32 text_len, Clay_BoundingBox bbox, Clay_Color color, const char *text, S32 text_len,
U16 font_size) U16 font_size) {
{
if (text_len == 0 || color.a < 0.1f) return; if (text_len == 0 || color.a < 0.1f) return;
F32 cr = color.r / 255.f; F32 cr = color.r / 255.f;
@@ -1179,8 +1269,7 @@ static void emit_text_glyphs(DrawBatch *batch, Renderer *r,
// Flush helper // Flush helper
static void flush_batch(Renderer *r, DrawBatch *batch, U32 buf_idx, static void flush_batch(Renderer *r, DrawBatch *batch, U32 buf_idx,
U32 *flush_index_start, VkDescriptorSet tex_set) U32 *flush_index_start, VkDescriptorSet tex_set) {
{
U32 draw_index_count = batch->index_count - *flush_index_start; U32 draw_index_count = batch->index_count - *flush_index_start;
if (draw_index_count == 0) return; if (draw_index_count == 0) return;
@@ -1406,18 +1495,18 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
VkCommandBuffer cb = fc->command_buffer; VkCommandBuffer cb = fc->command_buffer;
vkResetCommandBuffer(cb, 0); vkResetCommandBuffer(cb, 0);
VkCommandBufferBeginInfo begin_info = {0}; VkCommandBufferBeginInfo begin_info = { 0 };
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cb, &begin_info); vkBeginCommandBuffer(cb, &begin_info);
VkClearValue clear_value = {0}; VkClearValue clear_value = { 0 };
clear_value.color.float32[0] = r->clear_r; clear_value.color.float32[0] = r->clear_r;
clear_value.color.float32[1] = r->clear_g; clear_value.color.float32[1] = r->clear_g;
clear_value.color.float32[2] = r->clear_b; clear_value.color.float32[2] = r->clear_b;
clear_value.color.float32[3] = 1.0f; clear_value.color.float32[3] = 1.0f;
VkRenderPassBeginInfo rp_begin = {0}; VkRenderPassBeginInfo rp_begin = { 0 };
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.renderPass = r->render_pass; rp_begin.renderPass = r->render_pass;
rp_begin.framebuffer = r->framebuffers[image_index]; rp_begin.framebuffer = r->framebuffers[image_index];
@@ -1428,20 +1517,20 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
vkCmdBeginRenderPass(cb, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(cb, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = {0}; VkViewport viewport = { 0 };
viewport.width = (float)r->width; viewport.width = (float)r->width;
viewport.height = (float)r->height; viewport.height = (float)r->height;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
vkCmdSetViewport(cb, 0, 1, &viewport); vkCmdSetViewport(cb, 0, 1, &viewport);
VkRect2D scissor = {0}; VkRect2D scissor = { 0 };
scissor.extent.width = (U32)r->width; scissor.extent.width = (U32)r->width;
scissor.extent.height = (U32)r->height; scissor.extent.height = (U32)r->height;
vkCmdSetScissor(cb, 0, 1, &scissor); vkCmdSetScissor(cb, 0, 1, &scissor);
// Process Clay render commands // Process Clay render commands
if (render_commands.length > 0) { if (render_commands.length > 0) {
DrawBatch batch = {0}; DrawBatch batch = { 0 };
batch.vertices = (UIVertex *)r->vb_mapped[frame_idx]; batch.vertices = (UIVertex *)r->vb_mapped[frame_idx];
batch.indices = (U32 *)r->ib_mapped[frame_idx]; batch.indices = (U32 *)r->ib_mapped[frame_idx];
@@ -1521,7 +1610,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: { case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
VkDescriptorSet heap = bound_texture == 1 ? r->icon_descriptor_set : r->font_descriptor_set; VkDescriptorSet heap = bound_texture == 1 ? r->icon_descriptor_set : r->font_descriptor_set;
flush_batch(r, &batch, frame_idx, &flush_index_start, heap); flush_batch(r, &batch, frame_idx, &flush_index_start, heap);
VkRect2D clip = {0}; VkRect2D clip = { 0 };
clip.offset.x = (S32)Max(bb.x, 0.f); clip.offset.x = (S32)Max(bb.x, 0.f);
clip.offset.y = (S32)Max(bb.y, 0.f); clip.offset.y = (S32)Max(bb.y, 0.f);
clip.extent.width = (U32)Min(bb.width, (F32)r->width - clip.offset.x); clip.extent.width = (U32)Min(bb.width, (F32)r->width - clip.offset.x);
@@ -1534,7 +1623,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: { case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
VkDescriptorSet heap = bound_texture == 1 ? r->icon_descriptor_set : r->font_descriptor_set; VkDescriptorSet heap = bound_texture == 1 ? r->icon_descriptor_set : r->font_descriptor_set;
flush_batch(r, &batch, frame_idx, &flush_index_start, heap); flush_batch(r, &batch, frame_idx, &flush_index_start, heap);
VkRect2D full_scissor = {0}; VkRect2D full_scissor = { 0 };
full_scissor.extent.width = (U32)r->width; full_scissor.extent.width = (U32)r->width;
full_scissor.extent.height = (U32)r->height; full_scissor.extent.height = (U32)r->height;
vkCmdSetScissor(cb, 0, 1, &full_scissor); vkCmdSetScissor(cb, 0, 1, &full_scissor);
@@ -1612,7 +1701,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
// Submit // Submit
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit = {0}; VkSubmitInfo submit = { 0 };
submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit.waitSemaphoreCount = 1; submit.waitSemaphoreCount = 1;
submit.pWaitSemaphores = &r->image_available_sema[frame_idx]; submit.pWaitSemaphores = &r->image_available_sema[frame_idx];
@@ -1624,7 +1713,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
vkQueueSubmit(r->graphics_queue, 1, &submit, fc->fence); vkQueueSubmit(r->graphics_queue, 1, &submit, fc->fence);
// Present // Present
VkPresentInfoKHR present = {0}; VkPresentInfoKHR present = { 0 };
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present.waitSemaphoreCount = 1; present.waitSemaphoreCount = 1;
present.pWaitSemaphores = &r->render_finished_sema[frame_idx]; present.pWaitSemaphores = &r->render_finished_sema[frame_idx];
@@ -1642,7 +1731,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
void renderer_create_icon_atlas(Renderer *r, const U8 *data, S32 w, S32 h) { void renderer_create_icon_atlas(Renderer *r, const U8 *data, S32 w, S32 h) {
// Create image // Create image
VkImageCreateInfo img_ci = {0}; VkImageCreateInfo img_ci = { 0 };
img_ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; img_ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
img_ci.imageType = VK_IMAGE_TYPE_2D; img_ci.imageType = VK_IMAGE_TYPE_2D;
img_ci.format = VK_FORMAT_R8G8B8A8_UNORM; img_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
@@ -1655,18 +1744,18 @@ void renderer_create_icon_atlas(Renderer *r, const U8 *data, S32 w, S32 h) {
img_ci.tiling = VK_IMAGE_TILING_OPTIMAL; img_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
img_ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; img_ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
VmaAllocationCreateInfo alloc_ci = {0}; VmaAllocationCreateInfo alloc_ci = { 0 };
alloc_ci.usage = VMA_MEMORY_USAGE_GPU_ONLY; alloc_ci.usage = VMA_MEMORY_USAGE_GPU_ONLY;
vmaCreateImage(r->allocator, &img_ci, &alloc_ci, &r->icon_image, &r->icon_alloc, NULL); vmaCreateImage(r->allocator, &img_ci, &alloc_ci, &r->icon_image, &r->icon_alloc, NULL);
// Staging buffer // Staging buffer
VkBufferCreateInfo staging_ci = {0}; VkBufferCreateInfo staging_ci = { 0 };
staging_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; staging_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
staging_ci.size = (VkDeviceSize)w * h * 4; staging_ci.size = (VkDeviceSize)w * h * 4;
staging_ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; staging_ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo staging_alloc_ci = {0}; VmaAllocationCreateInfo staging_alloc_ci = { 0 };
staging_alloc_ci.usage = VMA_MEMORY_USAGE_CPU_ONLY; staging_alloc_ci.usage = VMA_MEMORY_USAGE_CPU_ONLY;
staging_alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; staging_alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
@@ -1683,7 +1772,7 @@ void renderer_create_icon_atlas(Renderer *r, const U8 *data, S32 w, S32 h) {
0, VK_ACCESS_TRANSFER_WRITE_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
VkBufferImageCopy region = {0}; VkBufferImageCopy region = { 0 };
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1; region.imageSubresource.layerCount = 1;
region.imageExtent.width = (U32)w; region.imageExtent.width = (U32)w;
@@ -1700,7 +1789,7 @@ void renderer_create_icon_atlas(Renderer *r, const U8 *data, S32 w, S32 h) {
vmaDestroyBuffer(r->allocator, staging_buf, staging_alloc); vmaDestroyBuffer(r->allocator, staging_buf, staging_alloc);
// Image view // Image view
VkImageViewCreateInfo view_ci = {0}; VkImageViewCreateInfo view_ci = { 0 };
view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_ci.image = r->icon_image; view_ci.image = r->icon_image;
view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D; view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
@@ -1711,7 +1800,7 @@ void renderer_create_icon_atlas(Renderer *r, const U8 *data, S32 w, S32 h) {
vkCreateImageView(r->device, &view_ci, NULL, &r->icon_view); vkCreateImageView(r->device, &view_ci, NULL, &r->icon_view);
// Allocate icon descriptor set // Allocate icon descriptor set
VkDescriptorSetAllocateInfo ds_alloc = {0}; VkDescriptorSetAllocateInfo ds_alloc = { 0 };
ds_alloc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; ds_alloc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
ds_alloc.descriptorPool = r->descriptor_pool; ds_alloc.descriptorPool = r->descriptor_pool;
ds_alloc.descriptorSetCount = 1; ds_alloc.descriptorSetCount = 1;
@@ -1728,8 +1817,14 @@ void renderer_resize(Renderer *r, S32 width, S32 height) {
// Clean up old swap chain resources // Clean up old swap chain resources
for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) { for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) {
if (r->framebuffers[i]) { vkDestroyFramebuffer(r->device, r->framebuffers[i], NULL); r->framebuffers[i] = VK_NULL_HANDLE; } if (r->framebuffers[i]) {
if (r->swap_chain_views[i]) { vkDestroyImageView(r->device, r->swap_chain_views[i], NULL); r->swap_chain_views[i] = VK_NULL_HANDLE; } vkDestroyFramebuffer(r->device, r->framebuffers[i], NULL);
r->framebuffers[i] = VK_NULL_HANDLE;
}
if (r->swap_chain_views[i]) {
vkDestroyImageView(r->device, r->swap_chain_views[i], NULL);
r->swap_chain_views[i] = VK_NULL_HANDLE;
}
} }
VkSwapchainKHR old_swap = r->swap_chain; VkSwapchainKHR old_swap = r->swap_chain;
@@ -1755,8 +1850,14 @@ void renderer_set_font_scale(Renderer *r, F32 scale) {
F32 target_size = 22.0f * scale; F32 target_size = 22.0f * scale;
if (fabsf(target_size - r->font_atlas_size) < 0.1f) return; if (fabsf(target_size - r->font_atlas_size) < 0.1f) return;
vkDeviceWaitIdle(r->device); vkDeviceWaitIdle(r->device);
if (r->font_view) { vkDestroyImageView(r->device, r->font_view, NULL); r->font_view = VK_NULL_HANDLE; } if (r->font_view) {
if (r->font_image) { vmaDestroyImage(r->allocator, r->font_image, r->font_alloc); r->font_image = VK_NULL_HANDLE; } vkDestroyImageView(r->device, r->font_view, NULL);
r->font_view = VK_NULL_HANDLE;
}
if (r->font_image) {
vmaDestroyImage(r->allocator, r->font_image, r->font_alloc);
r->font_image = VK_NULL_HANDLE;
}
create_font_atlas(r, target_size); create_font_atlas(r, target_size);
} }

View File

@@ -27,54 +27,54 @@ void ui_set_theme(S32 theme_id) {
switch (theme_id) { switch (theme_id) {
default: default:
case 0: // Dark case 0: // Dark
g_theme.bg_dark = Clay_Color{ 26, 26, 26, 255}; g_theme.bg_dark = Clay_Color{ 26, 26, 26, 255 };
g_theme.bg_medium = Clay_Color{ 36, 36, 36, 255}; g_theme.bg_medium = Clay_Color{ 36, 36, 36, 255 };
g_theme.bg_light = Clay_Color{ 46, 46, 46, 255}; g_theme.bg_light = Clay_Color{ 46, 46, 46, 255 };
g_theme.bg_lighter = Clay_Color{ 54, 54, 54, 255}; g_theme.bg_lighter = Clay_Color{ 54, 54, 54, 255 };
g_theme.border = Clay_Color{ 52, 52, 52, 255}; g_theme.border = Clay_Color{ 52, 52, 52, 255 };
g_theme.text = Clay_Color{220, 220, 220, 255}; g_theme.text = Clay_Color{ 220, 220, 220, 255 };
g_theme.text_dim = Clay_Color{105, 105, 105, 255}; g_theme.text_dim = Clay_Color{ 105, 105, 105, 255 };
g_theme.accent = Clay_Color{ 87, 138, 176, 255}; g_theme.accent = Clay_Color{ 87, 138, 176, 255 };
g_theme.accent_hover = Clay_Color{102, 153, 191, 255}; g_theme.accent_hover = Clay_Color{ 102, 153, 191, 255 };
g_theme.button_text = Clay_Color{224, 224, 224, 255}; g_theme.button_text = Clay_Color{ 224, 224, 224, 255 };
g_theme.disabled_bg = Clay_Color{ 44, 44, 44, 255}; g_theme.disabled_bg = Clay_Color{ 44, 44, 44, 255 };
g_theme.disabled_text = Clay_Color{ 90, 90, 90, 255}; g_theme.disabled_text = Clay_Color{ 90, 90, 90, 255 };
g_theme.header_bg = Clay_Color{ 46, 46, 46, 255}; g_theme.header_bg = Clay_Color{ 46, 46, 46, 255 };
g_theme.title_bar = Clay_Color{ 22, 22, 22, 255}; g_theme.title_bar = Clay_Color{ 22, 22, 22, 255 };
g_theme.scrollbar_bg = Clay_Color{ 22, 22, 22, 255}; g_theme.scrollbar_bg = Clay_Color{ 22, 22, 22, 255 };
g_theme.scrollbar_grab = Clay_Color{ 58, 58, 58, 255}; g_theme.scrollbar_grab = Clay_Color{ 58, 58, 58, 255 };
g_theme.shadow = Clay_Color{ 0, 0, 0, 30}; g_theme.shadow = Clay_Color{ 0, 0, 0, 30 };
g_theme.tab_active_top = Clay_Color{ 70, 120, 160, 255}; g_theme.tab_active_top = Clay_Color{ 70, 120, 160, 255 };
g_theme.tab_active_bottom= Clay_Color{ 30, 55, 80, 255}; g_theme.tab_active_bottom = Clay_Color{ 30, 55, 80, 255 };
g_theme.tab_inactive = Clay_Color{ 40, 40, 40, 255}; g_theme.tab_inactive = Clay_Color{ 40, 40, 40, 255 };
g_theme.tab_inactive_hover= Clay_Color{ 50, 50, 50, 255}; g_theme.tab_inactive_hover = Clay_Color{ 50, 50, 50, 255 };
g_theme.tab_text = Clay_Color{240, 240, 240, 255}; g_theme.tab_text = Clay_Color{ 240, 240, 240, 255 };
g_theme.corner_radius = 4.0f; g_theme.corner_radius = 4.0f;
break; break;
case 1: // Light case 1: // Light
g_theme.bg_dark = Clay_Color{195, 193, 190, 255}; g_theme.bg_dark = Clay_Color{ 195, 193, 190, 255 };
g_theme.bg_medium = Clay_Color{212, 210, 207, 255}; g_theme.bg_medium = Clay_Color{ 212, 210, 207, 255 };
g_theme.bg_light = Clay_Color{225, 223, 220, 255}; g_theme.bg_light = Clay_Color{ 225, 223, 220, 255 };
g_theme.bg_lighter = Clay_Color{232, 230, 227, 255}; g_theme.bg_lighter = Clay_Color{ 232, 230, 227, 255 };
g_theme.border = Clay_Color{178, 176, 173, 255}; g_theme.border = Clay_Color{ 178, 176, 173, 255 };
g_theme.text = Clay_Color{ 35, 33, 30, 255}; g_theme.text = Clay_Color{ 35, 33, 30, 255 };
g_theme.text_dim = Clay_Color{115, 113, 108, 255}; g_theme.text_dim = Clay_Color{ 115, 113, 108, 255 };
g_theme.accent = Clay_Color{ 50, 110, 170, 255}; g_theme.accent = Clay_Color{ 50, 110, 170, 255 };
g_theme.accent_hover = Clay_Color{ 65, 125, 185, 255}; g_theme.accent_hover = Clay_Color{ 65, 125, 185, 255 };
g_theme.button_text = Clay_Color{255, 255, 255, 255}; g_theme.button_text = Clay_Color{ 255, 255, 255, 255 };
g_theme.disabled_bg = Clay_Color{185, 183, 180, 255}; g_theme.disabled_bg = Clay_Color{ 185, 183, 180, 255 };
g_theme.disabled_text = Clay_Color{145, 143, 140, 255}; g_theme.disabled_text = Clay_Color{ 145, 143, 140, 255 };
g_theme.header_bg = Clay_Color{202, 200, 197, 255}; g_theme.header_bg = Clay_Color{ 202, 200, 197, 255 };
g_theme.title_bar = Clay_Color{202, 200, 197, 255}; g_theme.title_bar = Clay_Color{ 202, 200, 197, 255 };
g_theme.scrollbar_bg = Clay_Color{202, 200, 197, 255}; g_theme.scrollbar_bg = Clay_Color{ 202, 200, 197, 255 };
g_theme.scrollbar_grab = Clay_Color{168, 166, 163, 255}; g_theme.scrollbar_grab = Clay_Color{ 168, 166, 163, 255 };
g_theme.shadow = Clay_Color{ 0, 0, 0, 18}; g_theme.shadow = Clay_Color{ 0, 0, 0, 18 };
g_theme.tab_active_top = Clay_Color{ 70, 130, 180, 255}; g_theme.tab_active_top = Clay_Color{ 70, 130, 180, 255 };
g_theme.tab_active_bottom= Clay_Color{ 50, 100, 150, 255}; g_theme.tab_active_bottom = Clay_Color{ 50, 100, 150, 255 };
g_theme.tab_inactive = Clay_Color{205, 203, 200, 255}; g_theme.tab_inactive = Clay_Color{ 205, 203, 200, 255 };
g_theme.tab_inactive_hover= Clay_Color{195, 193, 190, 255}; g_theme.tab_inactive_hover = Clay_Color{ 195, 193, 190, 255 };
g_theme.tab_text = Clay_Color{255, 255, 255, 255}; g_theme.tab_text = Clay_Color{ 255, 255, 255, 255 };
g_theme.corner_radius = 4.0f; g_theme.corner_radius = 4.0f;
break; break;
} }
@@ -97,37 +97,37 @@ void ui_set_accent(S32 accent_id) {
// Dark-mode palettes // Dark-mode palettes
static const AccentColors dark_palettes[] = { static const AccentColors dark_palettes[] = {
// 0: Blue // 0: Blue
{ {87,138,176,255}, {102,153,191,255}, {70,120,160,255}, {30,55,80,255}, {224,224,224,255}, {240,240,240,255} }, { { 87, 138, 176, 255 }, { 102, 153, 191, 255 }, { 70, 120, 160, 255 }, { 30, 55, 80, 255 }, { 224, 224, 224, 255 }, { 240, 240, 240, 255 } },
// 1: Turquoise // 1: Turquoise
{ {60,160,155,255}, {75,175,170,255}, {50,140,135,255}, {25,70,68,255}, {224,224,224,255}, {240,240,240,255} }, { { 60, 160, 155, 255 }, { 75, 175, 170, 255 }, { 50, 140, 135, 255 }, { 25, 70, 68, 255 }, { 224, 224, 224, 255 }, { 240, 240, 240, 255 } },
// 2: Orange // 2: Orange
{ {200,130,50,255}, {215,145,65,255}, {190,120,40,255}, {100,60,20,255}, {240,240,240,255}, {240,240,240,255} }, { { 200, 130, 50, 255 }, { 215, 145, 65, 255 }, { 190, 120, 40, 255 }, { 100, 60, 20, 255 }, { 240, 240, 240, 255 }, { 240, 240, 240, 255 } },
// 3: Purple // 3: Purple
{ {130,100,180,255}, {145,115,195,255}, {120,90,170,255}, {60,45,85,255}, {224,224,224,255}, {240,240,240,255} }, { { 130, 100, 180, 255 }, { 145, 115, 195, 255 }, { 120, 90, 170, 255 }, { 60, 45, 85, 255 }, { 224, 224, 224, 255 }, { 240, 240, 240, 255 } },
// 4: Pink // 4: Pink
{ {185,95,140,255}, {200,110,155,255}, {175,85,130,255}, {88,42,65,255}, {240,240,240,255}, {240,240,240,255} }, { { 185, 95, 140, 255 }, { 200, 110, 155, 255 }, { 175, 85, 130, 255 }, { 88, 42, 65, 255 }, { 240, 240, 240, 255 }, { 240, 240, 240, 255 } },
// 5: Red // 5: Red
{ {190,75,75,255}, {205,90,90,255}, {180,65,65,255}, {90,32,32,255}, {240,240,240,255}, {240,240,240,255} }, { { 190, 75, 75, 255 }, { 205, 90, 90, 255 }, { 180, 65, 65, 255 }, { 90, 32, 32, 255 }, { 240, 240, 240, 255 }, { 240, 240, 240, 255 } },
// 6: Green // 6: Green
{ {80,155,80,255}, {95,170,95,255}, {70,140,70,255}, {35,70,35,255}, {240,240,240,255}, {240,240,240,255} }, { { 80, 155, 80, 255 }, { 95, 170, 95, 255 }, { 70, 140, 70, 255 }, { 35, 70, 35, 255 }, { 240, 240, 240, 255 }, { 240, 240, 240, 255 } },
}; };
// Light-mode palettes (slightly more saturated for contrast on light bg) // Light-mode palettes (slightly more saturated for contrast on light bg)
static const AccentColors light_palettes[] = { static const AccentColors light_palettes[] = {
// 0: Blue // 0: Blue
{ {50,110,170,255}, {65,125,185,255}, {70,130,180,255}, {50,100,150,255}, {255,255,255,255}, {255,255,255,255} }, { { 50, 110, 170, 255 }, { 65, 125, 185, 255 }, { 70, 130, 180, 255 }, { 50, 100, 150, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
// 1: Turquoise // 1: Turquoise
{ {30,140,135,255}, {45,155,150,255}, {40,150,145,255}, {25,115,110,255}, {255,255,255,255}, {255,255,255,255} }, { { 30, 140, 135, 255 }, { 45, 155, 150, 255 }, { 40, 150, 145, 255 }, { 25, 115, 110, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
// 2: Orange // 2: Orange
{ {190,115,25,255}, {205,130,40,255}, {195,120,30,255}, {155,90,15,255}, {255,255,255,255}, {255,255,255,255} }, { { 190, 115, 25, 255 }, { 205, 130, 40, 255 }, { 195, 120, 30, 255 }, { 155, 90, 15, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
// 3: Purple // 3: Purple
{ {110,75,170,255}, {125,90,185,255}, {115,80,175,255}, {85,55,140,255}, {255,255,255,255}, {255,255,255,255} }, { { 110, 75, 170, 255 }, { 125, 90, 185, 255 }, { 115, 80, 175, 255 }, { 85, 55, 140, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
// 4: Pink // 4: Pink
{ {175,70,125,255}, {190,85,140,255}, {180,75,130,255}, {140,50,100,255}, {255,255,255,255}, {255,255,255,255} }, { { 175, 70, 125, 255 }, { 190, 85, 140, 255 }, { 180, 75, 130, 255 }, { 140, 50, 100, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
// 5: Red // 5: Red
{ {185,55,55,255}, {200,70,70,255}, {190,60,60,255}, {150,40,40,255}, {255,255,255,255}, {255,255,255,255} }, { { 185, 55, 55, 255 }, { 200, 70, 70, 255 }, { 190, 60, 60, 255 }, { 150, 40, 40, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
// 6: Green // 6: Green
{ {55,140,55,255}, {70,155,70,255}, {60,145,60,255}, {40,110,40,255}, {255,255,255,255}, {255,255,255,255} }, { { 55, 140, 55, 255 }, { 70, 155, 70, 255 }, { 60, 145, 60, 255 }, { 40, 110, 40, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } },
}; };
S32 idx = accent_id; S32 idx = accent_id;
@@ -163,10 +163,10 @@ static UI_Context *g_measure_ctx = nullptr;
static Clay_Dimensions clay_measure_text(Clay_StringSlice text, Clay_TextElementConfig *config, void *user_data) { static Clay_Dimensions clay_measure_text(Clay_StringSlice text, Clay_TextElementConfig *config, void *user_data) {
UI_Context *ctx = (UI_Context *)user_data; UI_Context *ctx = (UI_Context *)user_data;
if (!ctx || !ctx->measure_text_fn || text.length == 0) { if (!ctx || !ctx->measure_text_fn || text.length == 0) {
return Clay_Dimensions{0, (F32)config->fontSize}; return Clay_Dimensions{ 0, (F32)config->fontSize };
} }
Vec2F32 result = ctx->measure_text_fn(text.chars, text.length, (F32)config->fontSize, ctx->measure_text_user_data); 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}; return Clay_Dimensions{ result.x, result.y };
} }
//////////////////////////////// ////////////////////////////////
@@ -184,7 +184,7 @@ UI_Context *ui_create(F32 viewport_w, F32 viewport_h) {
err_handler.userData = ctx; err_handler.userData = ctx;
ctx->clay_ctx = Clay_Initialize(clay_arena, ctx->clay_ctx = Clay_Initialize(clay_arena,
Clay_Dimensions{viewport_w, viewport_h}, Clay_Dimensions{ viewport_w, viewport_h },
err_handler); err_handler);
Clay_SetMeasureTextFunction(clay_measure_text, ctx); Clay_SetMeasureTextFunction(clay_measure_text, ctx);
@@ -200,13 +200,12 @@ void ui_destroy(UI_Context *ctx) {
void ui_begin_frame(UI_Context *ctx, F32 viewport_w, F32 viewport_h, void ui_begin_frame(UI_Context *ctx, F32 viewport_w, F32 viewport_h,
Vec2F32 mouse_pos, B32 mouse_down, Vec2F32 mouse_pos, B32 mouse_down,
Vec2F32 scroll_delta, F32 dt) Vec2F32 scroll_delta, F32 dt) {
{
g_measure_ctx = ctx; g_measure_ctx = ctx;
Clay_SetCurrentContext(ctx->clay_ctx); Clay_SetCurrentContext(ctx->clay_ctx);
Clay_SetLayoutDimensions(Clay_Dimensions{viewport_w, viewport_h}); Clay_SetLayoutDimensions(Clay_Dimensions{ viewport_w, viewport_h });
Clay_SetPointerState(Clay_Vector2{mouse_pos.x, mouse_pos.y}, mouse_down != 0); Clay_SetPointerState(Clay_Vector2{ mouse_pos.x, mouse_pos.y }, mouse_down != 0);
Clay_UpdateScrollContainers(false, Clay_Vector2{scroll_delta.x, scroll_delta.y}, dt); Clay_UpdateScrollContainers(false, Clay_Vector2{ scroll_delta.x, scroll_delta.y }, dt);
Clay_BeginLayout(); Clay_BeginLayout();
} }

View File

@@ -23,7 +23,7 @@ Clay_Color piano_velocity_color(S32 velocity) {
g = 175.0f + s * (50.0f - 175.0f); g = 175.0f + s * (50.0f - 175.0f);
b = 80.0f + s * (40.0f - 80.0f); b = 80.0f + s * (40.0f - 80.0f);
} }
return Clay_Color{r, g, b, 255}; return Clay_Color{ r, g, b, 255 };
} }
void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h) { void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h) {
@@ -32,8 +32,7 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
} }) {
) {
// Compute black key size proportional to white keys // Compute black key size proportional to white keys
F32 black_key_h = avail_h * PIANO_BLACK_H_PCT; F32 black_key_h = avail_h * PIANO_BLACK_H_PCT;
if (black_key_h < uis(20)) black_key_h = uis(20); if (black_key_h < uis(20)) black_key_h = uis(20);
@@ -54,16 +53,14 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
} else if (mouse_held) { } else if (mouse_held) {
bg = g_theme.accent; bg = g_theme.accent;
} else { } else {
bg = Clay_Color{240, 240, 240, 255}; bg = Clay_Color{ 240, 240, 240, 255 };
} }
CLAY(CLAY_IDI("PKey", note), CLAY(CLAY_IDI("PKey", note),
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
}, },
.backgroundColor = bg, .backgroundColor = bg, .border = { .color = { 190, 190, 190, 255 }, .width = { .right = 1 } }, ) {}
.border = { .color = {190, 190, 190, 255}, .width = { .right = 1 } },
) {}
} }
// Black keys (floating, attached to left white key) // Black keys (floating, attached to left white key)
@@ -79,7 +76,7 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
} else if (mouse_held) { } else if (mouse_held) {
bg = g_theme.accent; bg = g_theme.accent;
} else { } else {
bg = Clay_Color{25, 25, 30, 255}; bg = Clay_Color{ 25, 25, 30, 255 };
} }
CLAY(CLAY_IDI("PKey", note), CLAY(CLAY_IDI("PKey", note),
@@ -89,9 +86,7 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.height = CLAY_SIZING_FIXED(black_key_h), .height = CLAY_SIZING_FIXED(black_key_h),
}, },
}, },
.backgroundColor = bg, .backgroundColor = bg, .cornerRadius = { .topLeft = 0, .topRight = 0, .bottomLeft = uis(2), .bottomRight = uis(2) }, .floating = {
.cornerRadius = { .topLeft = 0, .topRight = 0, .bottomLeft = uis(2), .bottomRight = uis(2) },
.floating = {
.parentId = parent_wkey.id, .parentId = parent_wkey.id,
.zIndex = 100, .zIndex = 100,
.attachPoints = { .attachPoints = {
@@ -99,8 +94,7 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.parent = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_TOP,
}, },
.attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID, .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID,
}, }, ) {}
) {}
} }
} }
} }

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "ui/ui_core.h"
#include "midi/midi.h" #include "midi/midi.h"
#include "ui/ui_core.h"
#define PIANO_FIRST_NOTE 21 // A0 #define PIANO_FIRST_NOTE 21 // A0
#define PIANO_LAST_NOTE 108 // C8 #define PIANO_LAST_NOTE 108 // C8

View File

@@ -23,7 +23,10 @@ PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer
// Find free slot // Find free slot
PopupWindow *popup = nullptr; PopupWindow *popup = nullptr;
for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++) { for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++) {
if (!g_popups[i].alive) { popup = &g_popups[i]; break; } if (!g_popups[i].alive) {
popup = &g_popups[i];
break;
}
} }
if (!popup) return nullptr; if (!popup) return nullptr;
@@ -137,8 +140,7 @@ void popup_do_frame(PopupWindow *popup, F32 dt) {
.childGap = uip(8), .childGap = uip(8),
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
}, },
.backgroundColor = g_theme.bg_medium, .backgroundColor = g_theme.bg_medium, ) {
) {
if (popup->content_fn) { if (popup->content_fn) {
popup->content_fn(popup->content_user_data); popup->content_fn(popup->content_user_data);
} }

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "ui/ui_core.h"
#include "ui/ui_widgets.h"
#include "platform/platform.h" #include "platform/platform.h"
#include "renderer/renderer.h" #include "renderer/renderer.h"
#include "ui/ui_core.h"
#include "ui/ui_widgets.h"
#define MAX_POPUP_WINDOWS 4 #define MAX_POPUP_WINDOWS 4

View File

@@ -5,10 +5,10 @@
// AFTER a CLAY() block, use Clay_PointerOver(elementId). // AFTER a CLAY() block, use Clay_PointerOver(elementId).
#include "ui/ui_widgets.h" #include "ui/ui_widgets.h"
#include <string.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <string.h>
UI_WidgetState g_wstate = {}; UI_WidgetState g_wstate = {};
@@ -78,13 +78,11 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
CLAY(shadow_eid, CLAY(shadow_eid,
.layout = { .layout = {
.sizing = { .sizing = {
.width = CLAY_SIZING_FIXED(bb.width + expand*2), .width = CLAY_SIZING_FIXED(bb.width + expand * 2),
.height = CLAY_SIZING_FIXED(bb.height + expand*2), .height = CLAY_SIZING_FIXED(bb.height + expand * 2),
}, },
}, },
.backgroundColor = {0, 0, 0, per_layer}, .backgroundColor = { 0, 0, 0, per_layer }, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand), .floating = {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand),
.floating = {
.offset = { bb.x - expand + ox, bb.y - expand + oy }, .offset = { bb.x - expand + ox, bb.y - expand + oy },
.zIndex = z, .zIndex = z,
.attachPoints = { .attachPoints = {
@@ -92,19 +90,16 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
.parent = CLAY_ATTACH_POINT_LEFT_TOP, .parent = CLAY_ATTACH_POINT_LEFT_TOP,
}, },
.attachTo = CLAY_ATTACH_TO_ROOT, .attachTo = CLAY_ATTACH_TO_ROOT,
} }) {}
) {}
} else { } else {
CLAY(shadow_eid, CLAY(shadow_eid,
.layout = { .layout = {
.sizing = { .sizing = {
.width = CLAY_SIZING_FIXED(bb.width + expand*2), .width = CLAY_SIZING_FIXED(bb.width + expand * 2),
.height = CLAY_SIZING_FIXED(bb.height + expand*2), .height = CLAY_SIZING_FIXED(bb.height + expand * 2),
}, },
}, },
.backgroundColor = {0, 0, 0, per_layer}, .backgroundColor = { 0, 0, 0, per_layer }, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand), .floating = {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand),
.floating = {
.offset = { -expand + ox, -expand + oy }, .offset = { -expand + ox, -expand + oy },
.parentId = parent_id, .parentId = parent_id,
.zIndex = z, .zIndex = z,
@@ -113,8 +108,7 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
.parent = parent_attach, .parent = parent_attach,
}, },
.attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID, .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID,
} }) {}
) {}
} }
} }
} }
@@ -183,7 +177,7 @@ static void ensure_widget_text_configs() {
// Selected text: white on accent background (background set on parent element) // Selected text: white on accent background (background set on parent element)
g_widget_text_config_sel = {}; g_widget_text_config_sel = {};
g_widget_text_config_sel.textColor = Clay_Color{255, 255, 255, 255}; g_widget_text_config_sel.textColor = Clay_Color{ 255, 255, 255, 255 };
g_widget_text_config_sel.fontSize = FONT_SIZE_NORMAL; g_widget_text_config_sel.fontSize = FONT_SIZE_NORMAL;
g_widget_text_config_sel.wrapMode = CLAY_TEXT_WRAP_NONE; g_widget_text_config_sel.wrapMode = CLAY_TEXT_WRAP_NONE;
@@ -234,8 +228,7 @@ void ui_icon(UI_IconID icon, F32 size, Clay_Color color) {
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size) }, .sizing = { .width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size) },
}, },
.custom = { .customData = data } .custom = { .customData = data }) {}
) {}
} }
//////////////////////////////// ////////////////////////////////
@@ -247,8 +240,7 @@ void ui_label(const char *id, const char *text) {
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.padding = { 0, 0, uip(2), uip(2) }, .padding = { 0, 0, uip(2), uip(2) },
} }) {
) {
CLAY_TEXT(clay_str(text), &g_widget_text_config); CLAY_TEXT(clay_str(text), &g_widget_text_config);
} }
} }
@@ -263,8 +255,8 @@ B32 ui_button(const char *id, const char *text) {
B32 hovered = Clay_PointerOver(eid); B32 hovered = Clay_PointerOver(eid);
Clay_Color base = hovered ? g_theme.accent_hover : g_theme.accent; Clay_Color base = hovered ? g_theme.accent_hover : g_theme.accent;
Clay_Color top = {(F32)Min((S32)base.r+12,255), (F32)Min((S32)base.g+12,255), (F32)Min((S32)base.b+12,255), base.a}; Clay_Color top = { (F32)Min((S32)base.r + 12, 255), (F32)Min((S32)base.g + 12, 255), (F32)Min((S32)base.b + 12, 255), base.a };
Clay_Color bot = {(F32)Max((S32)base.r-15,0), (F32)Max((S32)base.g-15,0), (F32)Max((S32)base.b-15,0), base.a}; Clay_Color bot = { (F32)Max((S32)base.r - 15, 0), (F32)Max((S32)base.g - 15, 0), (F32)Max((S32)base.b - 15, 0), base.a };
CustomGradientData *grad = alloc_gradient(top, bot); CustomGradientData *grad = alloc_gradient(top, bot);
CLAY(eid, CLAY(eid,
@@ -273,10 +265,7 @@ B32 ui_button(const char *id, const char *text) {
.padding = { uip(12), uip(12), uip(1), 0 }, .padding = { uip(12), uip(12), uip(1), 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
}, },
.backgroundColor = base, .backgroundColor = base, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .custom = { .customData = grad }, ) {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.custom = { .customData = grad },
) {
CLAY_TEXT(clay_str(text), &g_widget_text_config_btn); CLAY_TEXT(clay_str(text), &g_widget_text_config_btn);
} }
@@ -299,8 +288,7 @@ B32 ui_checkbox(const char *id, const char *label, B32 *value) {
.childGap = uip(8), .childGap = uip(8),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
} }) {
) {
// Box // Box
Clay_Color box_bg = *value ? g_theme.accent : g_theme.bg_dark; Clay_Color box_bg = *value ? g_theme.accent : g_theme.bg_dark;
if (hovered) { if (hovered) {
@@ -311,10 +299,7 @@ B32 ui_checkbox(const char *id, const char *label, B32 *value) {
.sizing = { .width = CLAY_SIZING_FIXED(WIDGET_CHECKBOX_SIZE), .height = CLAY_SIZING_FIXED(WIDGET_CHECKBOX_SIZE) }, .sizing = { .width = CLAY_SIZING_FIXED(WIDGET_CHECKBOX_SIZE), .height = CLAY_SIZING_FIXED(WIDGET_CHECKBOX_SIZE) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}, },
.backgroundColor = box_bg, .backgroundColor = box_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }) {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
if (*value) { if (*value) {
ui_icon(UI_ICON_CHECK, WIDGET_CHECKBOX_SIZE * 0.75f, g_theme.button_text); ui_icon(UI_ICON_CHECK, WIDGET_CHECKBOX_SIZE * 0.75f, g_theme.button_text);
} }
@@ -344,8 +329,7 @@ B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selecte
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(4), .childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
} }) {
) {
for (S32 i = 0; i < count; i++) { for (S32 i = 0; i < count; i++) {
B32 is_selected = (*selected == i); B32 is_selected = (*selected == i);
Clay_ElementId row_id = WIDI(id, i + 100); Clay_ElementId row_id = WIDI(id, i + 100);
@@ -357,8 +341,7 @@ B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selecte
.childGap = uip(8), .childGap = uip(8),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
} }) {
) {
// Radio circle // Radio circle
Clay_Color dot_bg = is_selected ? g_theme.accent : g_theme.bg_dark; Clay_Color dot_bg = is_selected ? g_theme.accent : g_theme.bg_dark;
if (row_hovered) { if (row_hovered) {
@@ -369,18 +352,13 @@ B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selecte
.sizing = { .width = CLAY_SIZING_FIXED(WIDGET_RADIO_OUTER), .height = CLAY_SIZING_FIXED(WIDGET_RADIO_OUTER) }, .sizing = { .width = CLAY_SIZING_FIXED(WIDGET_RADIO_OUTER), .height = CLAY_SIZING_FIXED(WIDGET_RADIO_OUTER) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}, },
.backgroundColor = dot_bg, .backgroundColor = dot_bg, .cornerRadius = CLAY_CORNER_RADIUS(uis(8)), .border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }) {
.cornerRadius = CLAY_CORNER_RADIUS(uis(8)),
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
if (is_selected) { if (is_selected) {
CLAY(WIDI(id, i + 300), CLAY(WIDI(id, i + 300),
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(WIDGET_RADIO_INNER), .height = CLAY_SIZING_FIXED(WIDGET_RADIO_INNER) }, .sizing = { .width = CLAY_SIZING_FIXED(WIDGET_RADIO_INNER), .height = CLAY_SIZING_FIXED(WIDGET_RADIO_INNER) },
}, },
.backgroundColor = g_theme.button_text, .backgroundColor = g_theme.button_text, .cornerRadius = CLAY_CORNER_RADIUS(uis(4))) {}
.cornerRadius = CLAY_CORNER_RADIUS(uis(4))
) {}
} }
} }
@@ -420,8 +398,13 @@ void ui_text_input_reset_display_bufs() {
static void text_input_get_sel(S32 *lo, S32 *hi) { static void text_input_get_sel(S32 *lo, S32 *hi) {
S32 a = g_wstate.sel_start; S32 a = g_wstate.sel_start;
S32 b = g_wstate.sel_end; S32 b = g_wstate.sel_end;
if (a <= b) { *lo = a; *hi = b; } if (a <= b) {
else { *lo = b; *hi = a; } *lo = a;
*hi = b;
} else {
*lo = b;
*hi = a;
}
} }
// Helper: true if there's an active selection // Helper: true if there's an active selection
@@ -560,7 +543,10 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
S32 clip_len = (S32)strlen(clip); S32 clip_len = (S32)strlen(clip);
// Filter to single line (stop at newline) // Filter to single line (stop at newline)
for (S32 i = 0; i < clip_len; i++) { for (S32 i = 0; i < clip_len; i++) {
if (clip[i] == '\n' || clip[i] == '\r') { clip_len = i; break; } if (clip[i] == '\n' || clip[i] == '\r') {
clip_len = i;
break;
}
} }
S32 space = buf_size - 1 - len; S32 space = buf_size - 1 - len;
if (clip_len > space) clip_len = space; if (clip_len > space) clip_len = space;
@@ -608,7 +594,8 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
break; break;
case PKEY_LEFT: case PKEY_LEFT:
if (text_input_has_sel()) { if (text_input_has_sel()) {
S32 lo, hi; text_input_get_sel(&lo, &hi); S32 lo, hi;
text_input_get_sel(&lo, &hi);
g_wstate.cursor_pos = lo; g_wstate.cursor_pos = lo;
} else if (g_wstate.cursor_pos > 0) { } else if (g_wstate.cursor_pos > 0) {
g_wstate.cursor_pos--; g_wstate.cursor_pos--;
@@ -619,7 +606,8 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
break; break;
case PKEY_RIGHT: case PKEY_RIGHT:
if (text_input_has_sel()) { if (text_input_has_sel()) {
S32 lo, hi; text_input_get_sel(&lo, &hi); S32 lo, hi;
text_input_get_sel(&lo, &hi);
g_wstate.cursor_pos = hi; g_wstate.cursor_pos = hi;
} else if (g_wstate.cursor_pos < len) { } else if (g_wstate.cursor_pos < len) {
g_wstate.cursor_pos++; g_wstate.cursor_pos++;
@@ -678,7 +666,10 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
// our ID was just added above. Find it and advance to next. // our ID was just added above. Find it and advance to next.
S32 my_idx = -1; S32 my_idx = -1;
for (S32 i = 0; i < g_wstate.text_input_count; i++) { 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 (g_wstate.text_input_ids[i] == eid.id) {
my_idx = i;
break;
}
} }
if (my_idx >= 0) { if (my_idx >= 0) {
// Focus next (wrapping). But we might not have all inputs registered // Focus next (wrapping). But we might not have all inputs registered
@@ -721,8 +712,8 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
Clay_Color border_color = is_focused ? g_theme.accent : g_theme.border; Clay_Color border_color = is_focused ? g_theme.accent : g_theme.border;
// Inset effect: darker top, lighter bottom (recessed look) // Inset effect: darker top, lighter bottom (recessed look)
Clay_Color inset_top = {(F32)Max((S32)bg.r-8,0), (F32)Max((S32)bg.g-8,0), (F32)Max((S32)bg.b-8,0), bg.a}; Clay_Color inset_top = { (F32)Max((S32)bg.r - 8, 0), (F32)Max((S32)bg.g - 8, 0), (F32)Max((S32)bg.b - 8, 0), bg.a };
Clay_Color inset_bot = {(F32)Min((S32)bg.r+3,255), (F32)Min((S32)bg.g+3,255), (F32)Min((S32)bg.b+3,255), bg.a}; Clay_Color inset_bot = { (F32)Min((S32)bg.r + 3, 255), (F32)Min((S32)bg.g + 3, 255), (F32)Min((S32)bg.b + 3, 255), bg.a };
CustomGradientData *inset_grad = alloc_gradient(inset_top, inset_bot); CustomGradientData *inset_grad = alloc_gradient(inset_top, inset_bot);
CLAY(eid, CLAY(eid,
@@ -732,11 +723,7 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
}, },
.backgroundColor = bg, .backgroundColor = bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .custom = { .customData = inset_grad }, .border = { .color = border_color, .width = { 1, 1, 1, 1 } }, ) {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.custom = { .customData = inset_grad },
.border = { .color = border_color, .width = { 1, 1, 1, 1 } },
) {
if (len == 0 && !is_focused) { if (len == 0 && !is_focused) {
// Placeholder // Placeholder
CLAY_TEXT(CLAY_STRING("..."), &g_widget_text_config_dim); CLAY_TEXT(CLAY_STRING("..."), &g_widget_text_config_dim);
@@ -759,8 +746,7 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
}, },
.backgroundColor = g_theme.accent .backgroundColor = g_theme.accent) {
) {
CLAY_TEXT(clay_str(dbuf_sel), &g_widget_text_config_sel); CLAY_TEXT(clay_str(dbuf_sel), &g_widget_text_config_sel);
} }
} }
@@ -826,12 +812,15 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
while (lo < hi) { while (lo < hi) {
S32 mid = (lo + hi + 1) / 2; S32 mid = (lo + hi + 1) / 2;
Vec2F32 seg = ui_measure_text(current_label, mid, FONT_SIZE_NORMAL); Vec2F32 seg = ui_measure_text(current_label, mid, FONT_SIZE_NORMAL);
if (seg.x <= target_w) lo = mid; else hi = mid - 1; if (seg.x <= target_w) lo = mid;
else hi = mid - 1;
} }
if (lo + 3 < (S32)sizeof(dd_trunc_buf)) { if (lo + 3 < (S32)sizeof(dd_trunc_buf)) {
memcpy(dd_trunc_buf, current_label, lo); memcpy(dd_trunc_buf, current_label, lo);
dd_trunc_buf[lo] = '.'; dd_trunc_buf[lo+1] = '.'; dd_trunc_buf[lo+2] = '.'; dd_trunc_buf[lo] = '.';
dd_trunc_buf[lo+3] = '\0'; dd_trunc_buf[lo + 1] = '.';
dd_trunc_buf[lo + 2] = '.';
dd_trunc_buf[lo + 3] = '\0';
display_label = dd_trunc_buf; display_label = dd_trunc_buf;
} }
} }
@@ -840,7 +829,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
Clay_Color bg = is_open ? g_theme.bg_dark : g_theme.bg_medium; Clay_Color bg = is_open ? g_theme.bg_dark : g_theme.bg_medium;
if (header_hovered && !is_open) bg = g_theme.bg_lighter; if (header_hovered && !is_open) bg = g_theme.bg_lighter;
Clay_Color dd_top = {(F32)Min((S32)bg.r+6,255), (F32)Min((S32)bg.g+6,255), (F32)Min((S32)bg.b+6,255), bg.a}; Clay_Color dd_top = { (F32)Min((S32)bg.r + 6, 255), (F32)Min((S32)bg.g + 6, 255), (F32)Min((S32)bg.b + 6, 255), bg.a };
CustomGradientData *dd_grad = alloc_gradient(dd_top, bg); CustomGradientData *dd_grad = alloc_gradient(dd_top, bg);
CLAY(eid, CLAY(eid,
@@ -850,16 +839,11 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
}, },
.backgroundColor = bg, .backgroundColor = bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .custom = { .customData = dd_grad }, .border = { .color = is_open ? g_theme.accent : g_theme.border, .width = { 1, 1, 1, 1 } }, ) {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.custom = { .customData = dd_grad },
.border = { .color = is_open ? g_theme.accent : g_theme.border, .width = { 1, 1, 1, 1 } },
) {
CLAY(text_eid, CLAY(text_eid,
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
} }) {
) {
CLAY_TEXT(clay_str(display_label), &g_widget_text_config); CLAY_TEXT(clay_str(display_label), &g_widget_text_config);
} }
@@ -867,8 +851,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(uis(20)), .height = CLAY_SIZING_FIXED(uis(20)) }, .sizing = { .width = CLAY_SIZING_FIXED(uis(20)), .height = CLAY_SIZING_FIXED(uis(20)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
} }) {
) {
ui_icon(UI_ICON_CHEVRON_DOWN, uis(12), g_theme.text_dim); ui_icon(UI_ICON_CHEVRON_DOWN, uis(12), g_theme.text_dim);
} }
} }
@@ -902,9 +885,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.sizing = { .width = CLAY_SIZING_FIT(.min = header_width), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIT(.min = header_width), .height = CLAY_SIZING_FIT() },
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
}, },
.backgroundColor = g_theme.bg_dark, .backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .floating = {
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.floating = {
.parentId = eid.id, .parentId = eid.id,
.zIndex = 2000, .zIndex = 2000,
.attachPoints = { .attachPoints = {
@@ -913,8 +894,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
}, },
.attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID, .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID,
}, },
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }, .border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }, ) {
) {
for (S32 i = 0; i < count; i++) { for (S32 i = 0; i < count; i++) {
B32 is_item_selected = (*selected == i); B32 is_item_selected = (*selected == i);
Clay_ElementId item_id = WIDI(id, i + 600); Clay_ElementId item_id = WIDI(id, i + 600);
@@ -924,11 +904,18 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
if (item_hovered) item_bg = g_theme.bg_lighter; if (item_hovered) item_bg = g_theme.bg_lighter;
Clay_TextElementConfig *item_text = (is_item_selected && !item_hovered) Clay_TextElementConfig *item_text = (is_item_selected && !item_hovered)
? &g_widget_text_config_btn : &g_widget_text_config; ? &g_widget_text_config_btn
: &g_widget_text_config;
Clay_CornerRadius item_radius = {}; Clay_CornerRadius item_radius = {};
if (i == 0) { item_radius.topLeft = CORNER_RADIUS; item_radius.topRight = CORNER_RADIUS; } if (i == 0) {
if (i == count - 1) { item_radius.bottomLeft = CORNER_RADIUS; item_radius.bottomRight = CORNER_RADIUS; } item_radius.topLeft = CORNER_RADIUS;
item_radius.topRight = CORNER_RADIUS;
}
if (i == count - 1) {
item_radius.bottomLeft = CORNER_RADIUS;
item_radius.bottomRight = CORNER_RADIUS;
}
CLAY(item_id, CLAY(item_id,
.layout = { .layout = {
@@ -936,9 +923,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.padding = { uip(8), uip(8), 0, 0 }, .padding = { uip(8), uip(8), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
}, },
.backgroundColor = item_bg, .backgroundColor = item_bg, .cornerRadius = item_radius) {
.cornerRadius = item_radius
) {
CLAY_TEXT(clay_str(options[i]), item_text); CLAY_TEXT(clay_str(options[i]), item_text);
} }
@@ -955,7 +940,10 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
// Check if any item was clicked (already handled above) // Check if any item was clicked (already handled above)
B32 clicked_item = 0; B32 clicked_item = 0;
for (S32 i = 0; i < count; i++) { for (S32 i = 0; i < count; i++) {
if (Clay_PointerOver(WIDI(id, i + 600))) { clicked_item = 1; break; } if (Clay_PointerOver(WIDI(id, i + 600))) {
clicked_item = 1;
break;
}
} }
if (!clicked_item) { if (!clicked_item) {
g_wstate.open_dropdown_id = 0; g_wstate.open_dropdown_id = 0;
@@ -985,9 +973,7 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
.padding = { 0, 0, 0, 0 }, .padding = { 0, 0, 0, 0 },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
}, },
.backgroundColor = g_theme.bg_medium, .backgroundColor = g_theme.bg_medium, .border = { .color = g_theme.border, .width = { .bottom = 1 } }, ) {
.border = { .color = g_theme.border, .width = { .bottom = 1 } },
) {
for (S32 i = 0; i < count; i++) { for (S32 i = 0; i < count; i++) {
Clay_ElementId tab_eid = Clay__HashStringWithOffset(id_str, (U32)i, 0); Clay_ElementId tab_eid = Clay__HashStringWithOffset(id_str, (U32)i, 0);
B32 is_active = (i == *selected); B32 is_active = (i == *selected);
@@ -1002,9 +988,7 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
.padding = { TAB_PADDING_H, TAB_PADDING_H, 0, uip(6) }, .padding = { TAB_PADDING_H, TAB_PADDING_H, 0, uip(6) },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
}, },
.cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 }, .cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 }, .custom = { .customData = &g_tab_gradient }, ) {
.custom = { .customData = &g_tab_gradient },
) {
CLAY_TEXT(lbl_str, &g_widget_text_config_tab); CLAY_TEXT(lbl_str, &g_widget_text_config_tab);
} }
} else { } else {
@@ -1015,9 +999,7 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
.padding = { TAB_PADDING_H, TAB_PADDING_H, 0, uip(6) }, .padding = { TAB_PADDING_H, TAB_PADDING_H, 0, uip(6) },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
}, },
.backgroundColor = bg, .backgroundColor = bg, .cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 }, ) {
.cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 },
) {
CLAY_TEXT(lbl_str, &g_widget_text_config_tab_inactive); CLAY_TEXT(lbl_str, &g_widget_text_config_tab_inactive);
} }
} }
@@ -1049,10 +1031,14 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (*esel0 > elen) *esel0 = elen; if (*esel0 > elen) *esel0 = elen;
if (*esel1 > elen) *esel1 = elen; if (*esel1 > elen) *esel1 = elen;
#define KE_HAS_SEL() (*esel0 != *esel1) #define KE_HAS_SEL() (*esel0 != *esel1)
#define KE_SEL_LO() (*esel0 < *esel1 ? *esel0 : *esel1) #define KE_SEL_LO() (*esel0 < *esel1 ? *esel0 : *esel1)
#define KE_SEL_HI() (*esel0 < *esel1 ? *esel1 : *esel0) #define KE_SEL_HI() (*esel0 < *esel1 ? *esel1 : *esel0)
#define KE_CLEAR_SEL() do { *esel0 = *ecur; *esel1 = *ecur; } while(0) #define KE_CLEAR_SEL() \
do { \
*esel0 = *ecur; \
*esel1 = *ecur; \
} while (0)
auto ke_delete_sel = [&]() -> S32 { auto ke_delete_sel = [&]() -> S32 {
S32 lo = KE_SEL_LO(), hi = KE_SEL_HI(); S32 lo = KE_SEL_LO(), hi = KE_SEL_HI();
@@ -1068,13 +1054,19 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (ctrl) { if (ctrl) {
if (key == PKEY_A) { if (key == PKEY_A) {
*esel0 = 0; *esel1 = elen; *ecur = elen; continue; *esel0 = 0;
*esel1 = elen;
*ecur = elen;
continue;
} }
if (key == PKEY_C) { if (key == PKEY_C) {
if (KE_HAS_SEL()) { if (KE_HAS_SEL()) {
S32 lo = KE_SEL_LO(), hi = KE_SEL_HI(); S32 lo = KE_SEL_LO(), hi = KE_SEL_HI();
char tmp[32]; S32 n = hi - lo; if (n > 31) n = 31; char tmp[32];
memcpy(tmp, &ebuf[lo], n); tmp[n] = '\0'; S32 n = hi - lo;
if (n > 31) n = 31;
memcpy(tmp, &ebuf[lo], n);
tmp[n] = '\0';
platform_clipboard_set(tmp); platform_clipboard_set(tmp);
} }
continue; continue;
@@ -1082,8 +1074,11 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (key == PKEY_X) { if (key == PKEY_X) {
if (KE_HAS_SEL()) { if (KE_HAS_SEL()) {
S32 lo = KE_SEL_LO(), hi = KE_SEL_HI(); S32 lo = KE_SEL_LO(), hi = KE_SEL_HI();
char tmp[32]; S32 n = hi - lo; if (n > 31) n = 31; char tmp[32];
memcpy(tmp, &ebuf[lo], n); tmp[n] = '\0'; S32 n = hi - lo;
if (n > 31) n = 31;
memcpy(tmp, &ebuf[lo], n);
tmp[n] = '\0';
platform_clipboard_set(tmp); platform_clipboard_set(tmp);
elen = ke_delete_sel(); elen = ke_delete_sel();
} }
@@ -1094,7 +1089,8 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (clip) { if (clip) {
if (KE_HAS_SEL()) elen = ke_delete_sel(); if (KE_HAS_SEL()) elen = ke_delete_sel();
S32 clip_len = (S32)strlen(clip); S32 clip_len = (S32)strlen(clip);
char filtered[32]; S32 flen = 0; char filtered[32];
S32 flen = 0;
for (S32 i = 0; i < clip_len && flen < 30; i++) { for (S32 i = 0; i < clip_len && flen < 30; i++) {
char c = clip[i]; char c = clip[i];
if ((c >= '0' && c <= '9') || c == '.' || c == '-') if ((c >= '0' && c <= '9') || c == '.' || c == '-')
@@ -1105,7 +1101,8 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (flen > 0) { if (flen > 0) {
memmove(&ebuf[*ecur + flen], &ebuf[*ecur], elen - *ecur + 1); memmove(&ebuf[*ecur + flen], &ebuf[*ecur], elen - *ecur + 1);
memcpy(&ebuf[*ecur], filtered, flen); memcpy(&ebuf[*ecur], filtered, flen);
*ecur += flen; elen += flen; *ecur += flen;
elen += flen;
} }
KE_CLEAR_SEL(); KE_CLEAR_SEL();
} }
@@ -1114,29 +1111,40 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
continue; continue;
} }
if (key == PKEY_RETURN) { commit = 1; } if (key == PKEY_RETURN) {
else if (key == PKEY_ESCAPE) { cancel = 1; } commit = 1;
else if (key == PKEY_BACKSPACE) { } else if (key == PKEY_ESCAPE) {
if (KE_HAS_SEL()) { elen = ke_delete_sel(); } cancel = 1;
else if (*ecur > 0) { } else if (key == PKEY_BACKSPACE) {
if (KE_HAS_SEL()) {
elen = ke_delete_sel();
} else if (*ecur > 0) {
memmove(&ebuf[*ecur - 1], &ebuf[*ecur], elen - *ecur + 1); memmove(&ebuf[*ecur - 1], &ebuf[*ecur], elen - *ecur + 1);
(*ecur)--; elen--; (*ecur)--;
elen--;
} }
KE_CLEAR_SEL(); KE_CLEAR_SEL();
} else if (key == PKEY_DELETE) { } else if (key == PKEY_DELETE) {
if (KE_HAS_SEL()) { elen = ke_delete_sel(); } if (KE_HAS_SEL()) {
else if (*ecur < elen) { elen = ke_delete_sel();
} else if (*ecur < elen) {
memmove(&ebuf[*ecur], &ebuf[*ecur + 1], elen - *ecur); memmove(&ebuf[*ecur], &ebuf[*ecur + 1], elen - *ecur);
elen--; elen--;
} }
KE_CLEAR_SEL(); KE_CLEAR_SEL();
} else if (key == PKEY_LEFT) { } else if (key == PKEY_LEFT) {
if (KE_HAS_SEL()) { *ecur = KE_SEL_LO(); } if (KE_HAS_SEL()) {
else if (*ecur > 0) { (*ecur)--; } *ecur = KE_SEL_LO();
} else if (*ecur > 0) {
(*ecur)--;
}
KE_CLEAR_SEL(); KE_CLEAR_SEL();
} else if (key == PKEY_RIGHT) { } else if (key == PKEY_RIGHT) {
if (KE_HAS_SEL()) { *ecur = KE_SEL_HI(); } if (KE_HAS_SEL()) {
else if (*ecur < elen) { (*ecur)++; } *ecur = KE_SEL_HI();
} else if (*ecur < elen) {
(*ecur)++;
}
KE_CLEAR_SEL(); KE_CLEAR_SEL();
} }
} }
@@ -1149,17 +1157,19 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (KE_HAS_SEL()) elen = ke_delete_sel(); if (KE_HAS_SEL()) elen = ke_delete_sel();
if (elen < 30) { if (elen < 30) {
memmove(&ebuf[*ecur + 1], &ebuf[*ecur], elen - *ecur + 1); memmove(&ebuf[*ecur + 1], &ebuf[*ecur], elen - *ecur + 1);
ebuf[*ecur] = (char)ch; (*ecur)++; elen++; ebuf[*ecur] = (char)ch;
(*ecur)++;
elen++;
} }
KE_CLEAR_SEL(); KE_CLEAR_SEL();
} }
} }
} }
#undef KE_HAS_SEL #undef KE_HAS_SEL
#undef KE_SEL_LO #undef KE_SEL_LO
#undef KE_SEL_HI #undef KE_SEL_HI
#undef KE_CLEAR_SEL #undef KE_CLEAR_SEL
if (commit) { if (commit) {
char *end = nullptr; char *end = nullptr;
@@ -1168,7 +1178,10 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
F32 lo = is_signed ? -max_val : 0.0f; F32 lo = is_signed ? -max_val : 0.0f;
if (parsed < lo) parsed = lo; if (parsed < lo) parsed = lo;
if (parsed > max_val) parsed = max_val; if (parsed > max_val) parsed = max_val;
if (parsed != *value) { *value = parsed; *changed = 1; } if (parsed != *value) {
*value = parsed;
*changed = 1;
}
} }
g_wstate.knob_edit_id = 0; g_wstate.knob_edit_id = 0;
return 1; return 1;
@@ -1205,7 +1218,7 @@ static void value_edit_render(U32 hash, F32 width) {
edit_cfg.wrapMode = CLAY_TEXT_WRAP_NONE; edit_cfg.wrapMode = CLAY_TEXT_WRAP_NONE;
static Clay_TextElementConfig edit_sel_cfg = {}; static Clay_TextElementConfig edit_sel_cfg = {};
edit_sel_cfg.textColor = Clay_Color{255, 255, 255, 255}; edit_sel_cfg.textColor = Clay_Color{ 255, 255, 255, 255 };
edit_sel_cfg.fontSize = FONT_SIZE_SMALL; edit_sel_cfg.fontSize = FONT_SIZE_SMALL;
edit_sel_cfg.wrapMode = CLAY_TEXT_WRAP_NONE; edit_sel_cfg.wrapMode = CLAY_TEXT_WRAP_NONE;
@@ -1216,31 +1229,30 @@ static void value_edit_render(U32 hash, F32 width) {
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT, .layoutDirection = CLAY_LEFT_TO_RIGHT,
}, },
.backgroundColor = g_theme.bg_dark, .backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(uis(2)), .border = { .color = g_theme.accent, .width = { 1, 1, 1, 1 } }) {
.cornerRadius = CLAY_CORNER_RADIUS(uis(2)),
.border = { .color = g_theme.accent, .width = { 1, 1, 1, 1 } }
) {
if (has_sel) { if (has_sel) {
if (sel_lo > 0) { if (sel_lo > 0) {
S32 n = sel_lo; S32 n = sel_lo;
memcpy(ke_dbuf_before, ebuf, n); ke_dbuf_before[n] = '\0'; memcpy(ke_dbuf_before, ebuf, n);
ke_dbuf_before[n] = '\0';
Clay_String s_before = { .length = n, .chars = ke_dbuf_before }; Clay_String s_before = { .length = n, .chars = ke_dbuf_before };
CLAY_TEXT(s_before, &edit_cfg); CLAY_TEXT(s_before, &edit_cfg);
} }
{ {
S32 n = sel_hi - sel_lo; S32 n = sel_hi - sel_lo;
memcpy(ke_dbuf_sel, &ebuf[sel_lo], n); ke_dbuf_sel[n] = '\0'; memcpy(ke_dbuf_sel, &ebuf[sel_lo], n);
ke_dbuf_sel[n] = '\0';
Clay_String s_sel = { .length = n, .chars = ke_dbuf_sel }; Clay_String s_sel = { .length = n, .chars = ke_dbuf_sel };
CLAY(CLAY_IDI("ValEditSel", (S32)hash), CLAY(CLAY_IDI("ValEditSel", (S32)hash),
.layout = { .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() } }, .layout = { .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() } },
.backgroundColor = g_theme.accent .backgroundColor = g_theme.accent) {
) {
CLAY_TEXT(s_sel, &edit_sel_cfg); CLAY_TEXT(s_sel, &edit_sel_cfg);
} }
} }
if (sel_hi < elen) { if (sel_hi < elen) {
S32 n = elen - sel_hi; S32 n = elen - sel_hi;
memcpy(ke_dbuf_after, &ebuf[sel_hi], n); ke_dbuf_after[n] = '\0'; memcpy(ke_dbuf_after, &ebuf[sel_hi], n);
ke_dbuf_after[n] = '\0';
Clay_String s_after = { .length = n, .chars = ke_dbuf_after }; Clay_String s_after = { .length = n, .chars = ke_dbuf_after };
CLAY_TEXT(s_after, &edit_cfg); CLAY_TEXT(s_after, &edit_cfg);
} }
@@ -1272,7 +1284,10 @@ static void value_edit_click_away(Clay_ElementId eid, F32 *value, F32 max_val, B
F32 lo = is_signed ? -max_val : 0.0f; F32 lo = is_signed ? -max_val : 0.0f;
if (parsed < lo) parsed = lo; if (parsed < lo) parsed = lo;
if (parsed > max_val) parsed = max_val; if (parsed > max_val) parsed = max_val;
if (parsed != *value) { *value = parsed; *changed = 1; } if (parsed != *value) {
*value = parsed;
*changed = 1;
}
} }
g_wstate.knob_edit_id = 0; g_wstate.knob_edit_id = 0;
} }
@@ -1296,8 +1311,11 @@ static void value_edit_enter(U32 hash, F32 value, B32 is_signed) {
// Normalize a value to [0,1] range. // Normalize a value to [0,1] range.
static F32 value_normalize(F32 value, F32 max_val, B32 is_signed) { static F32 value_normalize(F32 value, F32 max_val, B32 is_signed) {
F32 n; F32 n;
if (is_signed) { n = (value + max_val) / (2.0f * max_val); } if (is_signed) {
else { n = value / max_val; } n = (value + max_val) / (2.0f * max_val);
} else {
n = value / max_val;
}
if (n < 0.0f) n = 0.0f; if (n < 0.0f) n = 0.0f;
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
return n; return n;
@@ -1307,8 +1325,11 @@ static F32 value_normalize(F32 value, F32 max_val, B32 is_signed) {
static char *value_format_text(F32 value, B32 is_signed, S32 *out_len) { static char *value_format_text(F32 value, B32 is_signed, S32 *out_len) {
if (g_knob_text_buf_count >= UI_MAX_KNOB_TEXT_BUFS) return nullptr; if (g_knob_text_buf_count >= UI_MAX_KNOB_TEXT_BUFS) return nullptr;
char *buf = g_knob_text_bufs[g_knob_text_buf_count++]; char *buf = g_knob_text_bufs[g_knob_text_buf_count++];
if (is_signed) { *out_len = snprintf(buf, 32, "%+.1f", value); } if (is_signed) {
else { *out_len = snprintf(buf, 32, "%.1f", value); } *out_len = snprintf(buf, 32, "%+.1f", value);
} else {
*out_len = snprintf(buf, 32, "%.1f", value);
}
return buf; return buf;
} }
@@ -1347,7 +1368,10 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
F32 lo = is_signed ? -max_val : 0.0f; F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo; if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val; if (new_val > max_val) new_val = max_val;
if (new_val != *value) { *value = new_val; changed = 1; } if (new_val != *value) {
*value = new_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
angle_rad = (-135.0f + normalized * 270.0f) * deg_to_rad; angle_rad = (-135.0f + normalized * 270.0f) * deg_to_rad;
} }
@@ -1373,8 +1397,7 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.childGap = WIDGET_KNOB_LABEL_GAP, .childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
} }) {
) {
Clay_ElementId knob_eid = CLAY_IDI("KnobBg", (S32)knob_hash); Clay_ElementId knob_eid = CLAY_IDI("KnobBg", (S32)knob_hash);
B32 hovered = Clay_PointerOver(knob_eid); B32 hovered = Clay_PointerOver(knob_eid);
@@ -1383,9 +1406,7 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.sizing = { .width = CLAY_SIZING_FIXED(knob_size), .height = CLAY_SIZING_FIXED(knob_size) }, .sizing = { .width = CLAY_SIZING_FIXED(knob_size), .height = CLAY_SIZING_FIXED(knob_size) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}, },
.backgroundColor = g_theme.bg_dark, .backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(knob_size / 2.0f)) {
.cornerRadius = CLAY_CORNER_RADIUS(knob_size / 2.0f)
) {
if (g_rotated_icon_pool_count < UI_MAX_ROTATED_ICONS_PER_FRAME) { if (g_rotated_icon_pool_count < UI_MAX_ROTATED_ICONS_PER_FRAME) {
S32 ri_idx = g_rotated_icon_pool_count; S32 ri_idx = g_rotated_icon_pool_count;
CustomRotatedIconData *rdata = &g_rotated_icon_pool[g_rotated_icon_pool_count++]; CustomRotatedIconData *rdata = &g_rotated_icon_pool[g_rotated_icon_pool_count++];
@@ -1399,8 +1420,7 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(icon_size), .height = CLAY_SIZING_FIXED(icon_size) }, .sizing = { .width = CLAY_SIZING_FIXED(icon_size), .height = CLAY_SIZING_FIXED(icon_size) },
}, },
.custom = { .customData = rdata } .custom = { .customData = rdata }) {}
) {}
} }
} }
@@ -1412,7 +1432,10 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
kd->last_click_frame = g_frame_number; kd->last_click_frame = g_frame_number;
if (is_double_click) { if (is_double_click) {
if (*value != default_val) { *value = default_val; changed = 1; } if (*value != default_val) {
*value = default_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
angle_rad = (-135.0f + normalized * 270.0f) * deg_to_rad; angle_rad = (-135.0f + normalized * 270.0f) * deg_to_rad;
kd->last_click_id = 0; kd->last_click_id = 0;
@@ -1442,8 +1465,7 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.sizing = { .width = CLAY_SIZING_FIXED(knob_size), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIXED(knob_size), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) }, .padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
} }) {
) {
CLAY_TEXT(val_str, &knob_val_cfg); CLAY_TEXT(val_str, &knob_val_cfg);
} }
@@ -1492,7 +1514,10 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
F32 lo = is_signed ? -max_val : 0.0f; F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo; if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val; if (new_val > max_val) new_val = max_val;
if (new_val != *value) { *value = new_val; changed = 1; } if (new_val != *value) {
*value = new_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
} }
@@ -1520,8 +1545,7 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.childGap = WIDGET_KNOB_LABEL_GAP, .childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
} }) {
) {
// Label // Label
CLAY_TEXT(clay_str(label), &g_widget_text_config_dim); CLAY_TEXT(clay_str(label), &g_widget_text_config_dim);
@@ -1533,16 +1557,13 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(thumb_h) }, .sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(thumb_h) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
} }) {
) {
// Visible track (centered inside hit area) // Visible track (centered inside hit area)
CLAY(CLAY_IDI("SlHTrack", (S32)hash), CLAY(CLAY_IDI("SlHTrack", (S32)hash),
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) }, .sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) },
}, },
.backgroundColor = g_theme.bg_dark, .backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)) {
.cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)
) {
// Fill bar // Fill bar
F32 fill_w = normalized * track_w; F32 fill_w = normalized * track_w;
if (fill_w < 1.0f) fill_w = 1.0f; if (fill_w < 1.0f) fill_w = 1.0f;
@@ -1550,9 +1571,7 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(fill_w), .height = CLAY_SIZING_GROW() }, .sizing = { .width = CLAY_SIZING_FIXED(fill_w), .height = CLAY_SIZING_GROW() },
}, },
.backgroundColor = fill_color, .backgroundColor = fill_color, .cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)) {}
.cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)
) {}
} }
// Floating icon thumb (attached to hit area) // Floating icon thumb (attached to hit area)
@@ -1579,8 +1598,7 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.attachTo = CLAY_ATTACH_TO_PARENT, .attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, },
.custom = { .customData = idata }, .custom = { .customData = idata }, ) {}
) {}
} }
} }
@@ -1592,7 +1610,10 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
kd->last_click_frame = g_frame_number; kd->last_click_frame = g_frame_number;
if (is_double_click) { if (is_double_click) {
if (*value != default_val) { *value = default_val; changed = 1; } if (*value != default_val) {
*value = default_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
kd->last_click_id = 0; kd->last_click_id = 0;
} else { } else {
@@ -1621,8 +1642,7 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) }, .padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
} }) {
) {
CLAY_TEXT(val_str, &sl_val_cfg); CLAY_TEXT(val_str, &sl_val_cfg);
} }
@@ -1668,7 +1688,10 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
F32 lo = is_signed ? -max_val : 0.0f; F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo; if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val; if (new_val > max_val) new_val = max_val;
if (new_val != *value) { *value = new_val; changed = 1; } if (new_val != *value) {
*value = new_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
} }
@@ -1696,8 +1719,7 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.childGap = WIDGET_KNOB_LABEL_GAP, .childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
} }) {
) {
// Label // Label
CLAY_TEXT(clay_str(label), &g_widget_text_config_dim); CLAY_TEXT(clay_str(label), &g_widget_text_config_dim);
@@ -1709,17 +1731,14 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(thumb_w), .height = CLAY_SIZING_FIXED(track_h) }, .sizing = { .width = CLAY_SIZING_FIXED(thumb_w), .height = CLAY_SIZING_FIXED(track_h) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
} }) {
) {
// Visible track (centered inside hit area) // Visible track (centered inside hit area)
CLAY(CLAY_IDI("SlVTrack", (S32)hash), CLAY(CLAY_IDI("SlVTrack", (S32)hash),
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) }, .sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) },
.childAlignment = { .y = CLAY_ALIGN_Y_BOTTOM }, .childAlignment = { .y = CLAY_ALIGN_Y_BOTTOM },
}, },
.backgroundColor = g_theme.bg_dark, .backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)) {
.cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)
) {
// Fill bar (from bottom) // Fill bar (from bottom)
F32 fill_h = normalized * track_h; F32 fill_h = normalized * track_h;
if (fill_h < 1.0f) fill_h = 1.0f; if (fill_h < 1.0f) fill_h = 1.0f;
@@ -1727,9 +1746,7 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(fill_h) }, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(fill_h) },
}, },
.backgroundColor = fill_color, .backgroundColor = fill_color, .cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)) {}
.cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)
) {}
} }
// Floating icon thumb (attached to hit area) // Floating icon thumb (attached to hit area)
@@ -1756,8 +1773,7 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.attachTo = CLAY_ATTACH_TO_PARENT, .attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, },
.custom = { .customData = idata }, .custom = { .customData = idata }, ) {}
) {}
} }
} }
@@ -1769,7 +1785,10 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
kd->last_click_frame = g_frame_number; kd->last_click_frame = g_frame_number;
if (is_double_click) { if (is_double_click) {
if (*value != default_val) { *value = default_val; changed = 1; } if (*value != default_val) {
*value = default_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
kd->last_click_id = 0; kd->last_click_id = 0;
} else { } else {
@@ -1798,8 +1817,7 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) }, .padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
} }) {
) {
CLAY_TEXT(val_str, &sl_val_cfg); CLAY_TEXT(val_str, &sl_val_cfg);
} }
@@ -1845,7 +1863,10 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
F32 lo = is_signed ? -max_val : 0.0f; F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo; if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val; if (new_val > max_val) new_val = max_val;
if (new_val != *value) { *value = new_val; changed = 1; } if (new_val != *value) {
*value = new_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
} }
@@ -1876,8 +1897,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.childGap = WIDGET_KNOB_LABEL_GAP, .childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM, .layoutDirection = CLAY_TOP_TO_BOTTOM,
} }) {
) {
// Label // Label
CLAY_TEXT(clay_str(label), &g_widget_text_config_dim); CLAY_TEXT(clay_str(label), &g_widget_text_config_dim);
@@ -1889,16 +1909,13 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(cap_w), .height = CLAY_SIZING_FIXED(track_h) }, .sizing = { .width = CLAY_SIZING_FIXED(cap_w), .height = CLAY_SIZING_FIXED(track_h) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
} }) {
) {
// Visible track (centered inside hit area, empty) // Visible track (centered inside hit area, empty)
CLAY(CLAY_IDI("FdrTrack", (S32)hash), CLAY(CLAY_IDI("FdrTrack", (S32)hash),
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) }, .sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) },
}, },
.backgroundColor = g_theme.bg_dark, .backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)) {}
.cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)
) {}
// Tick marks on both sides of the track // Tick marks on both sides of the track
for (S32 i = 0; i <= num_ticks; i++) { for (S32 i = 0; i <= num_ticks; i++) {
@@ -1911,8 +1928,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(tw), .height = CLAY_SIZING_FIXED(tick_h) }, .sizing = { .width = CLAY_SIZING_FIXED(tw), .height = CLAY_SIZING_FIXED(tick_h) },
}, },
.backgroundColor = g_theme.text_dim, .backgroundColor = g_theme.text_dim, .floating = {
.floating = {
.offset = { .offset = {
.x = track_left - tw, .x = track_left - tw,
.y = tick_y, .y = tick_y,
@@ -1924,16 +1940,14 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH, .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
.attachTo = CLAY_ATTACH_TO_PARENT, .attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, }, ) {}
) {}
// Right tick // Right tick
CLAY(CLAY_IDI("FdrTkR", (S32)(hash * 100 + i)), CLAY(CLAY_IDI("FdrTkR", (S32)(hash * 100 + i)),
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(tw), .height = CLAY_SIZING_FIXED(tick_h) }, .sizing = { .width = CLAY_SIZING_FIXED(tw), .height = CLAY_SIZING_FIXED(tick_h) },
}, },
.backgroundColor = g_theme.text_dim, .backgroundColor = g_theme.text_dim, .floating = {
.floating = {
.offset = { .offset = {
.x = track_left + track_w, .x = track_left + track_w,
.y = tick_y, .y = tick_y,
@@ -1945,8 +1959,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH, .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
.attachTo = CLAY_ATTACH_TO_PARENT, .attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, }, ) {}
) {}
} }
// Floating fader cap (RGBA icon from asset SVG) // Floating fader cap (RGBA icon from asset SVG)
@@ -1954,7 +1967,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
CustomIconData *idata = &g_icon_pool[g_icon_pool_count++]; CustomIconData *idata = &g_icon_pool[g_icon_pool_count++];
idata->type = CUSTOM_RENDER_ICON; idata->type = CUSTOM_RENDER_ICON;
idata->icon_id = (S32)UI_ICON_FADER; idata->icon_id = (S32)UI_ICON_FADER;
idata->color = Clay_Color{255, 255, 255, 255}; idata->color = Clay_Color{ 255, 255, 255, 255 };
F32 cap_y = (1.0f - normalized) * (track_h - cap_h); F32 cap_y = (1.0f - normalized) * (track_h - cap_h);
@@ -1972,8 +1985,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.attachTo = CLAY_ATTACH_TO_PARENT, .attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, },
.custom = { .customData = idata }, .custom = { .customData = idata }, ) {}
) {}
// Color tint overlay on top of fader cap // Color tint overlay on top of fader cap
Clay_Color tint = g_theme.accent; Clay_Color tint = g_theme.accent;
@@ -1983,9 +1995,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.layout = { .layout = {
.sizing = { .width = CLAY_SIZING_FIXED(cap_w), .height = CLAY_SIZING_FIXED(cap_h) }, .sizing = { .width = CLAY_SIZING_FIXED(cap_w), .height = CLAY_SIZING_FIXED(cap_h) },
}, },
.backgroundColor = tint, .backgroundColor = tint, .cornerRadius = CLAY_CORNER_RADIUS(cap_corner), .floating = {
.cornerRadius = CLAY_CORNER_RADIUS(cap_corner),
.floating = {
.offset = { .x = 0, .y = cap_y }, .offset = { .x = 0, .y = cap_y },
.attachPoints = { .attachPoints = {
.element = CLAY_ATTACH_POINT_LEFT_TOP, .element = CLAY_ATTACH_POINT_LEFT_TOP,
@@ -1994,8 +2004,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH, .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
.attachTo = CLAY_ATTACH_TO_PARENT, .attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, }, ) {}
) {}
} }
} }
@@ -2007,7 +2016,10 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
kd->last_click_frame = g_frame_number; kd->last_click_frame = g_frame_number;
if (is_double_click) { if (is_double_click) {
if (*value != default_val) { *value = default_val; changed = 1; } if (*value != default_val) {
*value = default_val;
changed = 1;
}
normalized = value_normalize(*value, max_val, is_signed); normalized = value_normalize(*value, max_val, is_signed);
kd->last_click_id = 0; kd->last_click_id = 0;
} else { } else {
@@ -2036,8 +2048,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() }, .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) }, .padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER },
} }) {
) {
CLAY_TEXT(val_str, &fdr_val_cfg); CLAY_TEXT(val_str, &fdr_val_cfg);
} }

View File

@@ -6,9 +6,9 @@
// The caller owns all data — the widget layer only stores transient UI state // The caller owns all data — the widget layer only stores transient UI state
// like which text field is focused or which dropdown is open. // like which text field is focused or which dropdown is open.
#include "platform/platform.h"
#include "ui/ui_core.h" #include "ui/ui_core.h"
#include "ui/ui_icons.h" #include "ui/ui_icons.h"
#include "platform/platform.h"
//////////////////////////////// ////////////////////////////////
// Widget state (global, managed by widget layer) // Widget state (global, managed by widget layer)