From 52128ff772e24a3b10a8447ec0411cd0e5e0c648 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 6 Nov 2025 22:17:14 -0600 Subject: [PATCH] prototyping --- src/base/base_math.c | 61 +++-- src/base/base_math.h | 11 +- src/proto/pp.lay | 30 +++ src/proto/pp_ent.c | 14 ++ src/proto/pp_ent.h | 31 +++ src/proto/pp_game.c | 233 ++++++++++++++++++ src/proto/pp_game.h | 69 ++++++ src/proto/pp_res/font/fixedsys.ttf | 3 + src/proto/pp_res/font/roboto-med.ttf | 3 + src/proto/pp_res/icon.ico | Bin 0 -> 4286 bytes src/proto/pp_res/sound/test.mp3 | 3 + src/proto/pp_res/sprite/blood.ase | 3 + src/proto/pp_res/sprite/box.ase | 3 + src/proto/pp_res/sprite/box_rounded.ase | 3 + src/proto/pp_res/sprite/bullet.ase | 3 + src/proto/pp_res/sprite/crosshair.ase | 3 + src/proto/pp_res/sprite/gun.ase | 3 + src/proto/pp_res/sprite/tile.ase | 3 + src/proto/pp_res/sprite/tim.ase | 3 + src/proto/pp_widgets.c | 312 ++++++++++++++++++++++++ src/proto/pp_widgets.h | 46 ++++ src/ui/ui_common.c | 40 ++- src/ui/ui_core.c | 10 +- src/ui/ui_core.h | 14 +- 24 files changed, 868 insertions(+), 36 deletions(-) create mode 100644 src/proto/pp.lay create mode 100644 src/proto/pp_ent.c create mode 100644 src/proto/pp_ent.h create mode 100644 src/proto/pp_game.c create mode 100644 src/proto/pp_game.h create mode 100644 src/proto/pp_res/font/fixedsys.ttf create mode 100644 src/proto/pp_res/font/roboto-med.ttf create mode 100644 src/proto/pp_res/icon.ico create mode 100644 src/proto/pp_res/sound/test.mp3 create mode 100644 src/proto/pp_res/sprite/blood.ase create mode 100644 src/proto/pp_res/sprite/box.ase create mode 100644 src/proto/pp_res/sprite/box_rounded.ase create mode 100644 src/proto/pp_res/sprite/bullet.ase create mode 100644 src/proto/pp_res/sprite/crosshair.ase create mode 100644 src/proto/pp_res/sprite/gun.ase create mode 100644 src/proto/pp_res/sprite/tile.ase create mode 100644 src/proto/pp_res/sprite/tim.ase create mode 100644 src/proto/pp_widgets.c create mode 100644 src/proto/pp_widgets.h diff --git a/src/base/base_math.c b/src/base/base_math.c index b8f25139..c9fa6e73 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -800,26 +800,44 @@ i64 LerpU64(u64 val0, u64 val1, f64 t) //////////////////////////////////////////////////////////// //~ Color operations -Vec4 Vec4NormFromU32(u32 v) +Vec4 LinearFromSrgb(Vec4 srgb) { - Vec4 result; - result.x = ((v >> 0) & 0xFF) / 255.0; - result.y = ((v >> 8) & 0xFF) / 255.0; - result.z = ((v >> 16) & 0xFF) / 255.0; - result.w = ((v >> 24) & 0xFF) / 255.0; + Vec4 result = ZI; + result.x = PowF32(AbsF32(srgb.x), 2.2); + result.y = PowF32(AbsF32(srgb.y), 2.2); + result.z = PowF32(AbsF32(srgb.z), 2.2); + result.w = srgb.w; return result; } -u32 LerpSrgbU32(u32 v0, u32 v1, f32 t) +Vec4 SrgbFromLinear(Vec4 linear) { - Vec4 norm0 = Vec4NormFromU32(v0); - Vec4 norm1 = Vec4NormFromU32(v1); - Vec4 norm = ZI; - norm.x = LerpF32(norm0.x, norm1.x, t); - norm.y = LerpF32(norm0.y, norm1.y, t); - norm.z = LerpF32(norm0.z, norm1.z, t); - norm.w = LerpF32(norm0.w, norm1.w, t); - return Rgba32F(norm.x, norm.y, norm.z, norm.w); + Vec4 result = ZI; + result.x = PowF32(linear.x, 1.0 / 2.2); + result.y = PowF32(linear.y, 1.0 / 2.2); + result.z = PowF32(linear.z, 1.0 / 2.2); + result.w = linear.w; + return result; +} + +Vec4 LinearFromSrgbU32(u32 srgb) +{ + return LinearFromSrgb(Vec4NormFromU32(srgb)); +} + +u32 BlendSrgbU32(u32 v0, u32 v1, f32 t) +{ + Vec4 v0_l = LinearFromSrgbU32(v0); + Vec4 v1_l = LinearFromSrgbU32(v1); + Vec4 blend_l = ZI; + { + blend_l.x = LerpF32(v0_l.x, v1_l.x, t); + blend_l.y = LerpF32(v0_l.y, v1_l.y, t); + blend_l.z = LerpF32(v0_l.z, v1_l.z, t); + blend_l.w = LerpF32(v0_l.w, v1_l.w, t); + } + Vec4 srgb_v4 = SrgbFromLinear(blend_l); + return Rgba32F(srgb_v4.x, srgb_v4.y, srgb_v4.z, srgb_v4.w); } //////////////////////////////////////////////////////////// @@ -1071,6 +1089,19 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b) return VEC2I32(a.x - b.x, a.y - b.y); } +//////////////////////////////////////////////////////////// +//~ Vec4 operations + +Vec4 Vec4NormFromU32(u32 v) +{ + Vec4 result; + result.x = ((v >> 0) & 0xFF) / 255.0; + result.y = ((v >> 8) & 0xFF) / 255.0; + result.z = ((v >> 16) & 0xFF) / 255.0; + result.w = ((v >> 24) & 0xFF) / 255.0; + return result; +} + //////////////////////////////////////////////////////////// //~ Xform operations diff --git a/src/base/base_math.h b/src/base/base_math.h index dcd3ff5b..b52452bd 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -259,8 +259,10 @@ i64 LerpU64(u64 val0, u64 val1, f64 t); //////////////////////////////////////////////////////////// //~ Color operations -Vec4 Vec4NormFromU32(u32 v); -u32 LerpSrgbU32(u32 v0, u32 v1, f32 t); +Vec4 LinearFromSrgb(Vec4 srgb); +Vec4 SrgbFromLinear(Vec4 linear); +Vec4 LinearFromSrgbU32(u32 srgb); +u32 BlendSrgbU32(u32 v0, u32 v1, f32 t); //////////////////////////////////////////////////////////// //~ Vec2 operations @@ -328,6 +330,11 @@ Vec2I32 NegVec2I32(Vec2I32 a); Vec2I32 AddVec2I32(Vec2I32 a, Vec2I32 b); Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b); +//////////////////////////////////////////////////////////// +//~ Vec4 operations + +Vec4 Vec4NormFromU32(u32 v); + //////////////////////////////////////////////////////////// //~ Xform operations diff --git a/src/proto/pp.lay b/src/proto/pp.lay new file mode 100644 index 00000000..65363a92 --- /dev/null +++ b/src/proto/pp.lay @@ -0,0 +1,30 @@ +@Layer proto + +//- Dependencies +@Dep gpu +@Dep sprite +@Dep font +@Dep collider +@Dep net +@Dep mixer +@Dep rendertest +@Dep playback +@Dep platform +@Dep window +@Dep ui + +//- Api +@IncludeC pp_ent.h +@IncludeC pp_widgets.h +@IncludeC pp_game.h + +//- Impl +@IncludeC pp_ent.c +@IncludeC pp_widgets.c +@IncludeC pp_game.c + +//- Embeds +@EmbedDir PP_Resources pp_res + +//- Startup +@Startup PP_Startup diff --git a/src/proto/pp_ent.c b/src/proto/pp_ent.c new file mode 100644 index 00000000..e0ce3fde --- /dev/null +++ b/src/proto/pp_ent.c @@ -0,0 +1,14 @@ +Readonly PP_Ent PP_nil_ent = ZI; + +//////////////////////////////////////////////////////////// +//~ Nil helpers + +b32 PP_IsKeyNil(PP_EntKey key) +{ + return key.v == 0; +} + +b32 PP_IsEntNil(PP_Ent *ent) +{ + return ent == 0 || ent == &PP_nil_ent; +} diff --git a/src/proto/pp_ent.h b/src/proto/pp_ent.h new file mode 100644 index 00000000..628e6698 --- /dev/null +++ b/src/proto/pp_ent.h @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////// +//~ Key types + +#define PP_NilKey ((PP_Key) { 0 }) + +Struct(PP_EntKey) +{ + u64 v; +}; + +//////////////////////////////////////////////////////////// +//~ Property types + +Enum(PP_EntProp) +{ + PP_EntProp_None, +}; + +//////////////////////////////////////////////////////////// +//~ Ent types + +Struct(PP_Ent) +{ + i32 _; +} extern Readonly PP_nil_ent; + +//////////////////////////////////////////////////////////// +//~ Nil helpers + +b32 PP_IsKeyNil(PP_EntKey key); +b32 PP_IsEntNil(PP_Ent *ent); diff --git a/src/proto/pp_game.c b/src/proto/pp_game.c new file mode 100644 index 00000000..bb680a10 --- /dev/null +++ b/src/proto/pp_game.c @@ -0,0 +1,233 @@ +PP_SharedState PP_shared_state = ZI; + +//////////////////////////////////////////////////////////// +//~ Startup + +void PP_Startup(void) +{ + PP_SharedState *shared = &PP_shared_state; + + /* Initialize shared state */ + for (u64 i = 0; i < countof(shared->v2s); ++i) + { + PP_VisToSimState *v2s = &shared->v2s[i]; + v2s->arena = AcquireArena(Gibi(64)); + } + + /* Create job pools */ + JobPoolId sim_pool = InitJobPool(1, Lit("Sim"), JobPoolPriority_Simulation); + JobPoolId vis_pool = InitJobPool(1, Lit("Vis"), JobPoolPriority_Graphics); + + /* Start jobs */ + shared->workers_count += RunJob(PP_SimWorker, .pool = sim_pool, .fence = &shared->worker_completion_fence); + shared->workers_count += RunJob(PP_VisWorker, .pool = vis_pool, .fence = &shared->worker_completion_fence); + OnExit(&PP_Shutdown); +} + +void PP_Shutdown(void) +{ + PP_SharedState *shared = &PP_shared_state; + Atomic32Set(&shared->shutdown, 1); + YieldOnFence(&shared->worker_completion_fence, shared->workers_count); +} + +//////////////////////////////////////////////////////////// +//~ Sim worker + +JobDef(PP_SimWorker, sig, job_id) +{ + PP_SharedState *shared = &PP_shared_state; + Arena *frame_arena = AcquireArena(Gibi(64)); + Arena *perm = PermArena(); + + ////////////////////////////// + //- Begin sim loop + + b32 shutdown = 0; + while (!shutdown) + { + ResetArena(frame_arena); + + ////////////////////////////// + //- Begin sim frame + + i64 frame_begin_ns = TimeNs(); + + ////////////////////////////// + //- Swap & pop v2s + + PP_VisToSimState *v2s = 0; + { + i32 v2s_front_idx = Atomic32Fetch(&shared->v2s_front_idx); + v2s = &shared->v2s[v2s_front_idx]; + i32 new_v2s_front_idx = v2s_front_idx + 1; + if (new_v2s_front_idx >= countof(shared->v2s)) + { + new_v2s_front_idx = 0; + } + LockTicketMutex(&v2s->tm); + { + Atomic32Set(&shared->v2s_front_idx, new_v2s_front_idx); + } + UnlockTicketMutex(&v2s->tm); + } + + ////////////////////////////// + //- End sim frame + + /* Reset v2s */ + { + Arena *arena = v2s->arena; + ResetArena(arena); + ZeroStruct(v2s); + v2s->arena = arena; + } + + shutdown = Atomic32Fetch(&shared->shutdown); + + i64 frame_end_ns = TimeNs(); + + ////////////////////////////// + //- Sleep + + { + i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + P_SleepFrame(frame_begin_ns, step_dt_ns); + } + } +} + +//////////////////////////////////////////////////////////// +//~ Vis worker + +JobDef(PP_VisWorker, sig, job_id) +{ + PP_SharedState *shared = &PP_shared_state; + Arena *frame_arena = AcquireArena(Gibi(64)); + Arena *perm = PermArena(); + + i64 gpu_fence_target = 0; + u64 frame_gen = 0; + + Struct(VisPersist) + { + PP_ListerWidget lister; + b32 ui_debug; + }; + VisPersist persist = ZI; + String window_restore = ZI; + + ////////////////////////////// + //- Swap in + + if (IsSwappedIn()) + { + TempArena scratch = BeginScratchNoConflict(); + { + String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_vis")); + BB_Buff bb = BB_BuffFromString(swap_encoded); + BB_Reader br = BB_ReaderFromBuff(&bb); + + String swap_str = BB_ReadString(scratch.arena, &br); + if (swap_str.len == sizeof(VisPersist)) + { + CopyBytes(&persist, swap_str.text, swap_str.len); + } + + window_restore = BB_ReadString(perm, &br); + } + EndScratch(scratch); + } + + ////////////////////////////// + //- Begin vis loop + + b32 shutdown = 0; + while (!shutdown) + { + ResetArena(frame_arena); + + ////////////////////////////// + //- Begin vis frame + + + UI_FrameFlag ui_frame_flags = 0; + ui_frame_flags |= UI_FrameFlag_Debug * !!persist.ui_debug; + ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; + UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags); + WND_Frame window_frame = ui_frame.window_frame; + Vec2 ui_cursor = ui_frame.cursor_pos; + + /* Restore window */ + if (frame_gen == 0) + { + WND_PushCmd(window_frame, .kind = WND_CmdKind_Restore, .restore = window_restore); + } + + /* Set widget theme */ + PP_WidgetTheme theme = PP_GetWidgetTheme(); + PP_PushWidgetThemeStyles(theme); + + ////////////////////////////// + //- Build console + + { + b32 minimized = 1; + PP_BuildDebugConsoleWidget(minimized); + } + + ////////////////////////////// + //- Build lister + + PP_BeginListerWidget(&persist.lister); + { + if (PP_BuildListerButton(&persist.lister, Lit("Debug UI")).m1_presses > 0) + { + persist.ui_debug = !persist.ui_debug; + } + if (PP_BuildListerButton(&persist.lister, Lit("Fullscreen")).m1_presses > 0) + { + b32 new = !window_frame.fullscreen; + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = new); + LogInfoF("Toggled fullscreen: %F", FmtSint(new)); + } + if (PP_BuildListerButton(&persist.lister, Lit("Topmost")).m1_presses > 0) + { + b32 new = !window_frame.forced_top; + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = new); + LogInfoF("Toggled topmost: %F", FmtSint(new)); + } + } + PP_EndListerWidget(&persist.lister); + + ////////////////////////////// + //- Submit sim commands + + + ////////////////////////////// + //- End vis frame + + gpu_fence_target = UI_EndFrame(ui_frame); + + ++frame_gen; + shutdown = Atomic32Fetch(&shared->shutdown); + } + + ////////////////////////////// + //- Swap out + + if (IsSwappingOut()) + { + TempArena scratch = BeginScratchNoConflict(); + u64 max_size = Mebi(64); + u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size); + BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes)); + { + BB_Writer bw = BB_WriterFromBuff(&bb); + BB_WriteString(&bw, StringFromStruct(&persist)); + BB_WriteString(&bw, window_restore); + WriteSwappedState(Lit("pp_vis"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw))); + } + EndScratch(scratch); + } +} diff --git a/src/proto/pp_game.h b/src/proto/pp_game.h new file mode 100644 index 00000000..d0e068d8 --- /dev/null +++ b/src/proto/pp_game.h @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////// +//~ Sim cmd types + +Enum(PP_SimCmdKind) +{ + PP_SimCmdKind_None, + + PP_SimCmdKind_Count, +}; + +Struct(PP_SimCmd) +{ + PP_SimCmd *next; +}; + +//////////////////////////////////////////////////////////// +//~ Vis cmd types + +Enum(PP_VisCmdKind) +{ + PP_VisCmdKind_None, + PP_VisCmdKind_Count, +}; + +Struct(PP_VisCmd) +{ + PP_VisCmd *next; +}; + +//////////////////////////////////////////////////////////// +//~ State types + +#define PP_VisToSimStatesCount 2 + +Struct(PP_VisToSimState) +{ + TicketMutex tm; + Arena *arena; + PP_SimCmd *first_cmd; + PP_SimCmd *last_cmd; +}; + +Struct(PP_SharedState) +{ + Atomic32 shutdown; + Fence worker_completion_fence; + i64 workers_count; + + //- Vis -> Sim + Atomic32 v2s_front_idx; + PP_VisToSimState v2s[PP_VisToSimStatesCount]; + +} extern PP_shared_state; + +//////////////////////////////////////////////////////////// +//~ Startup + +void PP_Startup(void); +void PP_Shutdown(void); + +//////////////////////////////////////////////////////////// +//~ Sim worker + +JobDecl(PP_SimWorker, EmptySig); + +//////////////////////////////////////////////////////////// +//~ Vis worker + +JobDecl(PP_VisWorker, EmptySig); diff --git a/src/proto/pp_res/font/fixedsys.ttf b/src/proto/pp_res/font/fixedsys.ttf new file mode 100644 index 00000000..89c4c856 --- /dev/null +++ b/src/proto/pp_res/font/fixedsys.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3f8e1da97b722a42477ee9a72f953eb2bc7c2195df5e2b6b7d4781dd3f8b2cc +size 570256 diff --git a/src/proto/pp_res/font/roboto-med.ttf b/src/proto/pp_res/font/roboto-med.ttf new file mode 100644 index 00000000..02435fc5 --- /dev/null +++ b/src/proto/pp_res/font/roboto-med.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8559132c89ad51d8a2ba5b171887a44a7ba93776e205f553573de228e64b45f8 +size 162588 diff --git a/src/proto/pp_res/icon.ico b/src/proto/pp_res/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ab6dc4ff9d4257f5ede2f2838a9d2ad3922a21c2 GIT binary patch literal 4286 zcmd^6F%H5&3=0!06LUwN!5bKm_!w{CH++Fdz`%fxOC?KHb#YI!nx%(=Tc?R@*KAjR z!(jezkAvCK%ucl`W#?MXkEiyObGhD1PbnH~*0t~7&-e~goL>7gY=_e8@xHeH-0Son z*NR6r8|4o^L%-)6Fb_%(J|oQV4~-UrQ#`WSp6vY@wnOPfxr5(=|DJE4WXxufbA(&S zA0Ar>j%BFyqTIn}=)2ZZDIVD@d`6hz9~vzL$2=&#rQFe1G}vsEJNOL$&}bnz=0WKp z-z8Ku*er66FvCAIS_qDLPnum_buttons = 0; + + UI_Push(Tag, HashF("lister")); + UI_Key titlebar_key = UI_KeyF("lister title bar"); + + u32 window_background_color = theme.window_background_color; + u32 window_border_color = theme.window_border_color; + u32 titlebar_color = 0; + u32 titlebar_border_color = 0; + u32 divider_color = theme.divider_color; + { + UI_Report rep = UI_ReportFromKey(titlebar_key); + if (rep.m1_held) + { + lister->pos = SubVec2(cursor_pos, rep.last_m1_offset); + } + window_border_color = BlendSrgbU32(window_border_color, Rgb32F(0.5, 0.5, 0.5), rep.hot); + } + + UI_Push(BackgroundColor, window_background_color); + UI_Push(BorderColor, window_border_color); + UI_Push(Border, theme.window_border); + // UI_Push(Rounding, UI_RPIX(15)); + UI_Push(Rounding, UI_RPIX(15)); + UI_Push(Width, UI_PIX(theme.window_width, 0)); + UI_Push(Height, UI_FIT(0)); + UI_Push(ChildLayoutAxis, Axis_Y); + UI_Push(FloatingPos, lister->pos); + UI_SetNext(Flags, UI_BoxFlag_Floating); + UI_PushCP(UI_BuildBox(UI_KeyF("lister"))); + { + /* Title bar */ + UI_PushCP(0); + { + UI_Push(BackgroundColor, titlebar_color); + UI_Push(BorderColor, titlebar_border_color); + UI_Push(Rounding, UI_RPIX(0)); + UI_Push(ChildLayoutAxis, Axis_X); + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(Height, UI_FNT(2, 1)); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildBox(titlebar_key)); + { + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(BorderColor, 0); + + /* Left title box */ + UI_BuildRow(UI_NilKey); + + /* Title box */ + UI_SetNext(FontSize, theme.window_title_font_size); + UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(Width, UI_FIT(1)); + UI_SetNext(Text, Lit("Lister")); + UI_SetNext(Flags, UI_BoxFlag_DrawText); + UI_BuildBox(UI_NilKey); + + /* Right title box */ + UI_BuildRow(UI_NilKey); + } + UI_PopCP(); + } + UI_PopCP(); + } + + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_PushCP(UI_BuildRow(UI_NilKey)); + { + f32 padding = theme.window_border; + UI_BuildSpacer(UI_PIX(padding, 1)); + { + UI_SetNext(Tint, 0); + UI_SetNext(Rounding, 0); + UI_SetNext(Width, UI_FILL(1, 0)); + UI_PushCP(UI_BuildColumn(UI_NilKey)); + } + } +} + +UI_Report PP_BuildListerButton(PP_ListerWidget *lister, String text) +{ + PP_WidgetTheme theme = PP_GetWidgetTheme(); + UI_BuildDivider(UI_PIX(1, 1), theme.divider_color); + + UI_Key btn_key = UI_KeyF("btn%F", FmtSint(lister->num_buttons)); + UI_Report rep = UI_ReportFromKey(btn_key); + + u32 hovered_color = Rgb32(0x10, 0x3c, 0x4c); + u32 pressed_color = Alpha32F(hovered_color, 0.25); + + f32 hot = rep.hot; + f32 active = rep.active; + f32 hovered = rep.hovered; + + u32 color = theme.window_background_color; + u32 border_color = 0; + color = BlendSrgbU32(color, hovered_color, hot); + color = BlendSrgbU32(color, pressed_color, active * hovered); + border_color = BlendSrgbU32(border_color, Rgb32(0x00, 0x79, 0xa6), hot); + + UI_SetNext(Rounding, 0); + UI_SetNext(Tint, 0); + UI_PushCP(UI_BuildRow(UI_NilKey)); + { + + UI_SetNext(BorderColor, border_color); + UI_SetNext(BackgroundColor, color); + UI_SetNext(Rounding, UI_RPIX(5)); + UI_SetNext(Width, UI_FILL(1, 0)); + UI_SetNext(Height, UI_FNT(1.5, 1)); + UI_SetNext(ChildAlignment, UI_Alignment_Left); + UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildRow(btn_key)); + { + UI_BuildSpacer(UI_PIX(20, 1)); + UI_BuildLabel(text); + } + UI_PopCP(); + } + UI_PopCP(); + + ++lister->num_buttons; + return rep; +} + + +void PP_EndListerWidget(PP_ListerWidget *lister) +{ + PP_WidgetTheme theme = PP_GetWidgetTheme(); + f32 padding = theme.window_border; + UI_BuildSpacer(UI_PIX(padding, 1)); + UI_PopCP(); + UI_BuildSpacer(UI_PIX(padding, 1)); + UI_PopCP(); + UI_PopCP(); +} + +//////////////////////////////////////////////////////////// +//~ Debug console widgets + +UI_Box *PP_BuildDebugConsoleWidget(b32 minimized) +{ + /* TODO: Remove this whole thing */ + __prof; + TempArena scratch = BeginScratchNoConflict(); + + // i32 console_level = minimized ? LogLevel_Success : LogLevel_Debug; + i32 console_level = LogLevel_Debug; + + u32 colors[LogLevel_Count][2] = ZI; + SetBytes(colors, 0xFF, sizeof(colors)); + /* Debug colors */ + colors[LogLevel_Debug][0] = Rgb32F(0.4, 0.1, 0.4); + colors[LogLevel_Debug][1] = Rgb32F(0.5, 0.2, 0.5); + /* Info colors */ + colors[LogLevel_Info][0] = Rgb32F(0.4, 0.4, 0.4); + colors[LogLevel_Info][1] = Rgb32F(0.5, 0.5, 0.5); + /* Success colors */ + colors[LogLevel_Success][0] = Rgb32F(0.1, 0.3, 0.1); + colors[LogLevel_Success][1] = Rgb32F(0.2, 0.4, 0.2); + /* Warning colors */ + colors[LogLevel_Warning][0] = Rgb32F(0.4, 0.4, 0.1); + colors[LogLevel_Warning][1] = Rgb32F(0.5, 0.5, 0.2); + /* Error colors */ + colors[LogLevel_Error][0] = Rgb32F(0.4, 0.1, 0.1); + colors[LogLevel_Error][1] = Rgb32F(0.5, 0.2, 0.2); + + i64 max_time_ns = I64Max; + i64 fade_time_ns = max_time_ns; + if (minimized) + { + max_time_ns = NsFromSeconds(10); + fade_time_ns = max_time_ns; + } + f32 fade_curve = 0.5; + + i64 now_ns = TimeNs(); + UI_Box *console_box = 0; + { + UI_SetNext(Border, 0); + if (minimized) + { + UI_SetNext(BackgroundColor, 0); + UI_SetNext(Width, UI_PIX(500, 0)); + UI_SetNext(Height, UI_FIT(1)); + } + else + { + UI_SetNext(BackgroundColor, Rgba32F(1, 1, 1, 0.02)); + UI_SetNext(Width, UI_FILL(1, 0)); + UI_SetNext(Height, UI_FIT(1)); + } + console_box = UI_BuildColumn(UI_KeyF("Console box")); + UI_PushCP(console_box); + { + /* Gather display logs */ + u64 max = 20; + u64 display_count = 0; + LogEvent *display_logs = PushStructs(scratch.arena, LogEvent, max); + { + b32 done = 0; + if (minimized) + { + max = 5; + } + LogEventsArray logs = GetLogEvents(); + for (u64 i = logs.count; i-- > 0 && display_count < max && !done;) + { + LogEvent ev = logs.logs[i]; + if (ev.time_ns > (now_ns - max_time_ns)) + { + if (ev.level <= console_level) + { + display_logs[display_count] = ev; + ++display_count; + } + } + else + { + done = 1; + } + } + } + /* Display logs in reverse */ + for (u64 i = display_count; i-- > 0;) + { + LogEvent log = display_logs[i]; + f32 opacity = 0.75; + f32 lin = 1.0 - ClampF64((f64)(now_ns - log.time_ns) / (f64)fade_time_ns, 0, 1); + opacity *= PowF32(lin, fade_curve); + String text = log.msg; + if (!minimized) + { + DateTime datetime = log.datetime; + text = StringF( + scratch.arena, + "[%F:%F:%F.%F] %F", + FmtUintZ(datetime.hour, 2), + FmtUintZ(datetime.minute, 2), + FmtUintZ(datetime.second, 2), + FmtUintZ(datetime.milliseconds, 3), + FmtString(text)); + } + UI_PushCP(0); + { + UI_Push(Tint, Alpha32F(0xFFFFFFFF, opacity)); + { + u32 color = colors[log.level][log.level_id % 2]; + UI_Push(BackgroundColor, color); + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(Height, UI_FNT(1.5, 1)); + UI_Push(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1)); + UI_Push(Rounding, UI_RPIX(0)); + UI_Push(Border, 1); + UI_Push(ChildAlignment, UI_Alignment_Left); + UI_PushCP(UI_BuildRow(UI_NilKey)); + { + // UI_SetNext(Height, UI_PIX(100, 0)); + UI_BuildSpacer(UI_PIX(10, 0)); + UI_Push(BackgroundColor, 0); + UI_Push(Border, 0); + UI_Push(Text, text); + UI_Push(Width, UI_FILL(1, 0)); + UI_Push(Height, UI_FIT(1)); + UI_Push(Flags, UI_BoxFlag_DrawText); + UI_BuildBox(UI_NilKey); + } + UI_PopCP(); + } + } + UI_PopCP(); + } + } + UI_PopCP(); + } + + EndScratch(scratch); + return console_box; +} diff --git a/src/proto/pp_widgets.h b/src/proto/pp_widgets.h new file mode 100644 index 00000000..84c93f9c --- /dev/null +++ b/src/proto/pp_widgets.h @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////// +//~ Theme types + +Struct(PP_WidgetTheme) +{ + ResourceKey font; + f32 font_size; + f32 window_title_font_size; + + u32 window_background_color; + u32 window_border_color; + f32 window_border; + f32 window_padding; + f32 window_width; + + + u32 divider_color; +}; + +//////////////////////////////////////////////////////////// +//~ Lister types + +Struct(PP_ListerWidget) +{ + /* Persistent state */ + Vec2 pos; + + /* Per-build state */ + i64 num_buttons; +}; + +//////////////////////////////////////////////////////////// +//~ Theme helpers + +PP_WidgetTheme PP_GetWidgetThemeStyles(void); +void PP_PushWidgetTheme(PP_WidgetTheme theme); + +//////////////////////////////////////////////////////////// +//~ Lister widgets + +/* FIXME */ + +//////////////////////////////////////////////////////////// +//~ Debug console widgets + +UI_Box *PP_BuildDebugConsoleWidget(b32 minimized); diff --git a/src/ui/ui_common.c b/src/ui/ui_common.c index 179aeba0..f67475c3 100644 --- a/src/ui/ui_common.c +++ b/src/ui/ui_common.c @@ -2,11 +2,25 @@ //~ Label helpers UI_Box *UI_BuildLabel(String text) { - UI_SetNext(Width, UI_FIT(0)); - UI_SetNext(Height, UI_FIT(1)); - UI_SetNext(Text, text); - UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_Box *box = UI_BuildBox(UI_NilKey); + UI_Box *parent = UI_UseTop(Parent); + ResourceKey font = UI_UseTop(Font); + f32 font_size = UI_UseTop(FontSize); + u32 tint = UI_UseTop(Tint); + + UI_Box *box = 0; + UI_PushEmptyStack(); + { + UI_SetNext(Tint, tint); + UI_SetNext(Parent, parent); + UI_SetNext(Font, font); + UI_SetNext(FontSize, font_size); + UI_SetNext(Width, UI_FIT(0)); + UI_SetNext(Height, UI_FIT(1)); + UI_SetNext(Text, text); + UI_SetNext(Flags, UI_BoxFlag_DrawText); + box = UI_BuildBox(UI_NilKey); + } + UI_PopStack(); return box; } @@ -31,12 +45,12 @@ UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...) UI_Box *UI_BuildSpacer(UI_Size size) { UI_Box *box = 0; - UI_Box *old_parent = UI_UseTop(Parent); - Axis axis = old_parent->child_layout_axis; + UI_Box *parent = UI_UseTop(Parent); + Axis axis = parent->child_layout_axis; UI_PushEmptyStack(); { UI_Push(Tint, 0); - UI_Push(Parent, old_parent); + UI_Push(Parent, parent); UI_Push(AxisSize, UI_FILL(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); box = UI_BuildBox(UI_NilKey); @@ -48,13 +62,13 @@ UI_Box *UI_BuildSpacer(UI_Size size) UI_Box *UI_BuildDivider(UI_Size size, u32 color) { UI_Box *box = 0; - UI_Box *old_parent = UI_UseTop(Parent); - u32 old_tint = UI_UseTop(Tint); - Axis axis = old_parent->child_layout_axis; + UI_Box *parent = UI_UseTop(Parent); + u32 tint = UI_UseTop(Tint); + Axis axis = parent->child_layout_axis; UI_PushEmptyStack(); { - UI_Push(Parent, old_parent); - UI_Push(Tint, old_tint); + UI_Push(Parent, parent); + UI_Push(Tint, tint); UI_Push(BackgroundColor, color); UI_Push(AxisSize, UI_FILL(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 0a94afbe..e18543da 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -82,7 +82,6 @@ UI_Box *UI_FrontBoxFromKey(UI_Key key) return front_box; } - //////////////////////////////////////////////////////////// //~ String helpers @@ -718,6 +717,15 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) return frame; } +//////////////////////////////////////////////////////////// +//~ Frame helpers + +Vec2 UI_GetCursorPos(void) +{ + UI_SharedState *g = &UI_shared_state; + return g->cursor_pos; +} + //////////////////////////////////////////////////////////// //~ End frame diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 36297524..3e5fa21d 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -181,9 +181,9 @@ Struct(UI_Report) f32 hot; f32 active; - b32 m1_downs; - b32 m1_ups; - b32 m1_presses; + i32 m1_downs; + i32 m1_ups; + i32 m1_presses; Vec2 last_m1_offset; /* Where was this box last rendered in screen coordinates */ @@ -420,7 +420,11 @@ UI_Report UI_ReportFromKey(UI_Key key); UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags); //////////////////////////////////////////////////////////// -//~ End build +//~ Frame helpers + +Vec2 UI_GetCursorPos(void); + +//////////////////////////////////////////////////////////// +//~ End frame -GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size); i64 UI_EndFrame(UI_Frame frame);