diff --git a/src/gpu/gpu_core.h b/src/gpu/gpu_core.h index f092870e..ef35ad65 100644 --- a/src/gpu/gpu_core.h +++ b/src/gpu/gpu_core.h @@ -493,4 +493,4 @@ void GPU_YieldOnSwapchain(GPU_Swapchain *swapchain); * 2. Blits `texture` into position `dst` in the backbuffer * 3. Presents the backbuffer * 4. Returns the value that the Direct queue fence will reach once GPU completes blitting (`texture` shouldn't be released while blit is in flight) */ -i64 GPU_PresentSwapchain(GPU_Swapchain *swapchain, GPU_Resource *texture, i32 vsync, Vec2I32 backbuffer_size, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1); +i64 GPU_PresentSwapchain(GPU_Swapchain *swapchain, GPU_Resource *texture, i32 vsync, Vec2I32 backbuffer_size, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1, Vec4 clear_color); diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index e9e8965e..4c9444b7 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -1960,7 +1960,7 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V return &swapchain->buffers[backbuffer_index]; } -i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1) +i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1, Vec4 clear_color) { GPU_D12_SharedState *g = &GPU_D12_shared_state; @@ -1986,8 +1986,7 @@ i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *text /* Clear */ { - f32 clear_color[4] = ZI; - ID3D12GraphicsCommandList_ClearRenderTargetView(rcl, dst->rtv_descriptor->handle, clear_color, 0, 0); + ID3D12GraphicsCommandList_ClearRenderTargetView(rcl, dst->rtv_descriptor->handle, (f32 *)&clear_color, 0, 0); } { @@ -2194,7 +2193,7 @@ void GPU_YieldOnSwapchain(GPU_Swapchain *gpu_swapchain) } } -i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture, i32 vsync, Vec2I32 backbuffer_size, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1) +i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture, i32 vsync, Vec2I32 backbuffer_size, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1, Vec4 clear_color) { GPU_D12_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain; GPU_D12_Resource *texture = (GPU_D12_Resource *)gpu_texture; @@ -2214,7 +2213,7 @@ i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture if (is_blitable) { /* Blit */ - fence_target = GPU_D12_BlitToSwapchain(swapchain_buffer, texture, dst_p0, dst_p1, src_p0, src_p1); + fence_target = GPU_D12_BlitToSwapchain(swapchain_buffer, texture, dst_p0, dst_p1, src_p0, src_p1, clear_color); u32 present_flags = 0; if (GPU_D12_TearingIsAllowed && vsync == 0) diff --git a/src/gpu/gpu_dx12/gpu_dx12.h b/src/gpu/gpu_dx12/gpu_dx12.h index 4050a94a..8f50cb97 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.h +++ b/src/gpu/gpu_dx12/gpu_dx12.h @@ -380,7 +380,7 @@ u64 GPU_D12_EndRawCommandList(GPU_D12_RawCommandList *cl); void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain); GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution); -i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1); +i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture, Vec2I32 dst_p0, Vec2I32 dst_p1, Vec2I32 src_p0, Vec2I32 src_p1, Vec4 clear_color); //////////////////////////////////////////////////////////// //~ Sync job diff --git a/src/proto/pp_sim/pp_sim_core.c b/src/proto/pp_sim/pp_sim_core.c index 959d3076..2ee996b9 100644 --- a/src/proto/pp_sim/pp_sim_core.c +++ b/src/proto/pp_sim/pp_sim_core.c @@ -48,6 +48,117 @@ b32 S_IsEntNil(S_Ent *ent) return ent == 0 || ent == &S_nil_ent; } +b32 S_MatchEntKey(S_EntKey a, S_EntKey b) +{ + return a.v.hi == b.v.hi && a.v.lo == b.v.lo; +} + +//////////////////////////////////////////////////////////// +//~ Lookup helpers + +S_Ent *S_EntFromKey(S_World *world, S_EntKey key) +{ + S_Ent *ent = &S_nil_ent; + if (!S_IsKeyNil(key)) + { + S_EntLookupNode *n = world->ent_bins[key.v.lo % world->ent_bins_count]; + for (; n; n = n->next) + { + if (S_MatchEntKey(n->ent->key, key)) + { + ent = n->ent; + break; + } + } + } + return ent; +} + +//////////////////////////////////////////////////////////// +//~ Snapshot helpers + +S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) +{ + TempArena scratch = BeginScratch(arena); + S_World *world = PushStruct(arena, S_World); + + /* Copy ents */ + world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count); + CopyStructs(world->ents, snapshot->ents, snapshot->ents_count); + world->ents_count = snapshot->ents_count; + world->tick = snapshot->tick; + + /* Init lookup */ + world->ent_bins_count = 4096; + world->ent_bins = PushStructs(arena, S_EntLookupNode *, world->ent_bins_count); + for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) + { + S_Ent *ent = &world->ents[ent_idx]; + S_EntKey key = ent->key; + S_EntLookupNode *n = PushStruct(arena, S_EntLookupNode); + n->ent = ent; + S_EntLookupNode **bin = &world->ent_bins[ent->key.v.lo % world->ent_bins_count]; + SllStackPush(*bin, n); + } + + /* Sort tree */ + { + i64 ents_count = world->ents_count; + S_Ent **ents_pre = PushStructsNoZero(arena, S_Ent *, ents_count); + S_Ent **ents_post = PushStructsNoZero(arena, S_Ent *, ents_count); + { + Struct(EntNode) { EntNode *next; b32 visited; S_Ent *ent; }; + EntNode *first_dfs = 0; + i64 pre_idx = 0; + i64 post_idx = 0; + { + EntNode *n = PushStruct(scratch.arena, EntNode); + for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) + { + S_Ent *ent = &world->ents[ent_idx]; + if (S_MatchEntKey(ent->key, S_RootEntKey)) + { + n->ent = ent; + break; + } + } + SllStackPush(first_dfs, n); + } + while (first_dfs) + { + EntNode *n = first_dfs; + S_Ent *ent = n->ent; + if (!n->visited) + { + /* Push children to dfs stack */ + for (S_Ent *child = S_EntFromKey(world, ent->first); !S_IsEntNil(child); child = S_EntFromKey(world, child->prev)) + { + EntNode *child_n = PushStruct(scratch.arena, EntNode); + child_n->ent = child; + SllStackPush(first_dfs, child_n); + } + ent->pre_idx = pre_idx++; + ents_pre[ent->pre_idx] = ent; + n->visited = 1; + } + else + { + SllStackPop(first_dfs); + ent->post_idx = post_idx++; + ents_post[ent->post_idx] = ent; + } + } + Assert(pre_idx == ents_count); + Assert(post_idx == ents_count); + world->ents_pre = ents_pre; + world->ents_post = ents_post; + } + } + + EndScratch(scratch); + return world; +} + //////////////////////////////////////////////////////////// //~ Sim worker @@ -58,24 +169,34 @@ JobDef(S_SimWorker, sig, job_id) Arena *perm = PermArena(); //- World data - Arena *ents_arena = AcquireArena(Gibi(64)); - S_Ent *ents = ArenaFirst(ents_arena, S_Ent); - i64 tick = 0; + Arena *world_arena = AcquireArena(Gibi(64)); + S_World *world = 0; - /* Create root ent */ { - S_Ent *root_ent = PushStruct(ents_arena, S_Ent); - *root_ent = S_nil_ent; - root_ent->key = S_RootEntKey; - } + S_Snapshot *empty_ss = PushStruct(frame_arena, S_Snapshot); + { + empty_ss->ents = PushStructs(frame_arena, S_Ent, 1024); + /* Create root ent */ + S_Ent *root_ent = &empty_ss->ents[empty_ss->ents_count++]; + { + *root_ent = S_nil_ent; + root_ent->key = S_RootEntKey; + } + /* Create test ent */ + S_Ent *test_ent = &empty_ss->ents[empty_ss->ents_count++]; + { + *test_ent = S_nil_ent; + test_ent->shape.points_count = 1; + test_ent->shape.radius = 0.25; + test_ent->key = ((S_EntKey) { .v.hi = 0x66444f20b7e41f3d, .v.lo = 0x5a2df684b9430943 }); - /* Create test ent */ - { - S_Ent *test_ent = PushStruct(ents_arena, S_Ent); - *test_ent = S_nil_ent; - test_ent->parent = S_RootEntKey; - test_ent->shape.points_count = 1; - test_ent->shape.radius = 0.25; + test_ent->parent = root_ent->key; + root_ent->first = test_ent->key; + root_ent->last = test_ent->key; + ++root_ent->count; + } + } + world = S_WorldFromSnapshot(world_arena, empty_ss); } ////////////////////////////// @@ -127,17 +248,18 @@ JobDef(S_SimWorker, sig, job_id) LockTicketMutex(&shared->output_back_tm); { S_OutputState *output = &shared->output_states[shared->output_back_idx]; - S_WorldNode *world_node = PushStruct(output->arena, S_WorldNode); - S_World *world = &world_node->world; - SllQueuePush(output->first_world_node, output->last_world_node, world_node); - ++output->worlds_count; - world->ents_count = ArenaCount(ents_arena, S_Ent); - world->tick = tick; - world->ents = PushStructsNoZero(output->arena, S_Ent, world->ents_count); - for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) + S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode); + S_Snapshot *snapshot = &snapshot_node->snapshot; + SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); + ++output->snapshots_count; + snapshot->ents_count = world->ents_count; + snapshot->tick = world->tick; + snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count); + for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx) { - S_Ent *ent = &ents[ent_idx]; - world->ents[ent_idx] = *ent; + S_Ent *src = &world->ents[ent_idx]; + S_Ent *dst = &snapshot->ents[ent_idx]; + *dst = *src; } } UnlockTicketMutex(&shared->output_back_tm); @@ -155,7 +277,7 @@ JobDef(S_SimWorker, sig, job_id) i64 frame_end_ns = TimeNs(); - ++tick; + ++world->tick; ////////////////////////////// //- Sleep diff --git a/src/proto/pp_sim/pp_sim_core.h b/src/proto/pp_sim/pp_sim_core.h index bf07a981..bf904962 100644 --- a/src/proto/pp_sim/pp_sim_core.h +++ b/src/proto/pp_sim/pp_sim_core.h @@ -35,19 +35,32 @@ Enum(S_EntProp) Struct(S_Ent) { + //- Tree data S_EntKey parent; S_EntKey first; S_EntKey last; S_EntKey next; S_EntKey prev; + i64 count; + //- Persistent data S_EntKey key; S_Shape shape; + + //- Per-world data + i64 pre_idx; + i64 post_idx; } extern Readonly S_nil_ent; ////////////////////////////// -//- Ent list +//- Ent containers + +Struct(S_EntArray) +{ + i64 count; + S_Ent *ents; +}; Struct(S_EntListNode) { @@ -62,28 +75,40 @@ Struct(S_EntList) u64 count; }; -//////////////////////////////////////////////////////////// -//~ Lookup types - -Struct(S_EntLookupBin) +Struct(S_EntLookupNode) { - i32 _; + S_EntLookupNode *next; + S_Ent *ent; }; //////////////////////////////////////////////////////////// //~ World types Struct(S_World) +{ + i64 tick; + + S_Ent *ents; + i64 ents_count; + + S_EntLookupNode **ent_bins; + i64 ent_bins_count; + + S_Ent **ents_pre; + S_Ent **ents_post; +}; + +Struct(S_Snapshot) { i64 tick; S_Ent *ents; i64 ents_count; }; -Struct(S_WorldNode) +Struct(S_SnapshotNode) { - S_WorldNode *next; - S_World world; + S_SnapshotNode *next; + S_Snapshot snapshot; }; //////////////////////////////////////////////////////////// @@ -124,9 +149,9 @@ Struct(S_InputState) Struct(S_OutputState) { Arena *arena; - S_WorldNode *first_world_node; - S_WorldNode *last_world_node; - u64 worlds_count; + S_SnapshotNode *first_snapshot_node; + S_SnapshotNode *last_snapshot_node; + u64 snapshots_count; }; Struct(S_SharedState) @@ -158,6 +183,17 @@ void S_Shutdown(void); b32 S_IsKeyNil(S_EntKey key); b32 S_IsEntNil(S_Ent *ent); +b32 S_MatchEntKey(S_EntKey a, S_EntKey b); + +//////////////////////////////////////////////////////////// +//~ Lookup helpers + +S_Ent *S_EntFromKey(S_World *world, S_EntKey key); + +//////////////////////////////////////////////////////////// +//~ Snapshot helpers + +S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot); //////////////////////////////////////////////////////////// //~ Sim worker diff --git a/src/proto/pp_vis/pp_vis.lay b/src/proto/pp_vis/pp_vis.lay index 9cb37a96..f8efb368 100644 --- a/src/proto/pp_vis/pp_vis.lay +++ b/src/proto/pp_vis/pp_vis.lay @@ -15,14 +15,21 @@ //- Api @IncludeC pp_vis_widgets.h +@IncludeC pp_vis_draw.h @IncludeC pp_vis_core.h +@IncludeGpu pp_vis_draw.h //- Impl @IncludeC pp_vis_widgets.c @IncludeC pp_vis_core.c +@IncludeGpu pp_vis_draw.gpu //- Embeds @EmbedDir V_Resources pp_vis_res +//- Shaders +@VertexShader V_DQuadVS +@PixelShader V_DQuadPS + //- Startup @Startup V_Startup diff --git a/src/proto/pp_vis/pp_vis_core.c b/src/proto/pp_vis/pp_vis_core.c index 82c03bfe..0da286f2 100644 --- a/src/proto/pp_vis/pp_vis_core.c +++ b/src/proto/pp_vis/pp_vis_core.c @@ -32,17 +32,22 @@ JobDef(V_VisWorker, sig, job_id) Arena *frame_arena = AcquireArena(Gibi(64)); Arena *perm = PermArena(); - i64 gpu_fence_target = 0; - u64 frame_gen = 0; + ////////////////////////////// + //- State - Struct(VisPersist) + Fence *gpu_fence = GPU_FenceFromQueue(GPU_QueueKind_Direct); + i64 gpu_fence_target = 0; + i64 frame_gen = 0; + GPU_Resource *draw_target = 0; + + Struct(Persist) { V_CommandsWidget commands_widget; b32 ui_debug; b32 show_command_palette; b32 show_console; }; - VisPersist persist = ZI; + Persist persist = ZI; String window_restore = ZI; Button held_buttons[Button_Count] = ZI; @@ -87,7 +92,7 @@ JobDef(V_VisWorker, sig, job_id) BB_Reader br = BB_ReaderFromBuff(&bb); String swap_str = BB_ReadString(scratch.arena, &br); - if (swap_str.len == sizeof(VisPersist)) + if (swap_str.len == sizeof(Persist)) { CopyBytes(&persist, swap_str.text, swap_str.len); } @@ -102,14 +107,8 @@ JobDef(V_VisWorker, sig, job_id) - - Arena *ents_arena = AcquireArena(Gibi(64)); - S_Ent *ents = ArenaFirst(ents_arena, S_Ent); - i64 tick = 0; - - - - + Arena *world_arena = AcquireArena(Gibi(64)); + S_World *world = PushStruct(world_arena, S_World); b32 shutdown = 0; while (!shutdown) @@ -120,11 +119,13 @@ JobDef(V_VisWorker, sig, job_id) //- Begin vis frame UI_FrameFlag ui_frame_flags = 0; + Vec4 swapchain_color = V_GetWidgetTheme().window_background_color; 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); + UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color); WND_Frame window_frame = ui_frame.window_frame; Vec2 ui_cursor = ui_frame.cursor_pos; + Vec2I32 draw_size = window_frame.monitor_size; /* Restore window */ { @@ -142,8 +143,8 @@ JobDef(V_VisWorker, sig, job_id) UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(Width, UI_GROW(1, 0)); UI_Push(Height, UI_GROW(1, 0)); - UI_Push(Parent, UI_BuildColumnEx(UI_KeyF("AAH"))); - + UI_Key vis_box = UI_KeyF("vis box"); + UI_Push(Parent, UI_BuildColumnEx(vis_box)); ////////////////////////////// //- Pop sim output @@ -160,6 +161,12 @@ JobDef(V_VisWorker, sig, job_id) } UnlockTicketMutex(&sim_shared->output_back_tm); + if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > world->tick) + { + ResetArena(world_arena); + world = S_WorldFromSnapshot(world_arena, &sim_output->last_snapshot_node->snapshot); + } + ////////////////////////////// //- Process controller events vis cmds @@ -329,13 +336,53 @@ JobDef(V_VisWorker, sig, job_id) ////////////////////////////// //- Render + /* Acquire draw target */ { - + if (draw_target && !MatchVec2I32(draw_size, GPU_GetTextureSize2D(draw_target))) + { + YieldOnFence(gpu_fence, gpu_fence_target); + GPU_ReleaseResource(draw_target, GPU_ReleaseFlag_None); + draw_target = 0; + } + if (!draw_target) + { + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Texture2D; + desc.flags = GPU_ResourceFlag_Writable | GPU_ResourceFlag_Renderable; + desc.texture.format = GPU_Format_R16G16B16A16_Float; + desc.clear_color = LinearFromSrgb(swapchain_color); + draw_target = GPU_AcquireResource(desc); + } } + GPU_CommandList *cl = GPU_BeginCommandList(GPU_QueueKind_Direct); + { + /* Prep draw target */ + { + GPU_TransitionToRenderable(cl, draw_target, 0); + GPU_ClearRenderable(cl, draw_target); + } + + /* Prep shapes pass */ + { + + } + + /* Shapes pass */ + { + } + + /* Transition draw target for UI composition */ + { + GPU_TransitionToReadable(cl, draw_target); + } + } + gpu_fence_target = GPU_EndCommandList(cl); + ////////////////////////////// //- End vis frame + UI_SetRawTexture(vis_box, draw_target, VEC2(0, 0), VEC2(1, 1)); gpu_fence_target = UI_EndFrame(ui_frame); ++frame_gen; diff --git a/src/proto/pp_vis/pp_vis_draw.gpu b/src/proto/pp_vis/pp_vis_draw.gpu new file mode 100644 index 00000000..fba4842c --- /dev/null +++ b/src/proto/pp_vis/pp_vis_draw.gpu @@ -0,0 +1,49 @@ +ConstantBuffer V_dquad_sig : register (b0); + +//////////////////////////////////////////////////////////// +//~ Quad + +Struct(V_DQuadPS_Input) +{ + + Semantic(Vec4, sv_position); + Semantic(nointerpolation u32, quad_idx); +}; + +Struct(V_DQuadPS_Output) +{ + Semantic(Vec4, sv_target0); +}; + +//- Vertex shader + +V_DQuadPS_Input VSDef(V_DQuadVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid)) +{ + ConstantBuffer sig = V_dquad_sig; + StructuredBuffer quads = UniformResourceFromRid(sig.quads); + V_DQuad quad = quads[sv_instanceid]; + + Vec2 rect_uv = RectUvFromVertexId(sv_vertexid); + // Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv); + // Vec2 screen_vert = lerp(quad.p0, quad.p1, rect_uv); + Vec2 screen_vert = 0; + + V_DQuadPS_Input result; + result.sv_position = Vec4(NdcFromViewport(sig.viewport_size, screen_vert).xy, 0, 1); + result.quad_idx = sv_instanceid; + return result; +} + +//- Pixel shader +V_DQuadPS_Output PSDef(V_DQuadPS, V_DQuadPS_Input input) +{ + ConstantBuffer sig = V_dquad_sig; + StructuredBuffer quads = UniformResourceFromRid(sig.quads); + V_DQuad quad = quads[input.quad_idx]; + + Vec4 final_color = 0; + + V_DQuadPS_Output output; + output.sv_target0 = final_color; + return output; +} diff --git a/src/proto/pp_vis/pp_vis_draw.h b/src/proto/pp_vis/pp_vis_draw.h new file mode 100644 index 00000000..3686f49d --- /dev/null +++ b/src/proto/pp_vis/pp_vis_draw.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////// +//~ Quad types + +Struct(V_DQuadSig) +{ + /* ----------------------------------------------------- */ + Vec2I32 viewport_size; /* 02 consts */ + StructuredBufferRid quads; /* 01 consts */ + SamplerStateRid sampler; /* 01 consts */ + /* ----------------------------------------------------- */ + b32 debug_enabled; /* 01 consts */ + u32 _pad0; /* 01 consts (padding) */ + u32 _pad1; /* 01 consts (padding) */ + u32 _pad2; /* 01 consts (padding) */ + /* ----------------------------------------------------- */ +}; +AssertRootConst(V_DQuadSig, 8); + +Enum(V_DQuadFlag) +{ + V_DQuadFlag_None = 0, + V_DQuadFlag_DrawGrid = (1 << 0), +}; + +Struct(V_DQuad) +{ + V_DQuadFlag flags; +}; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 6a84c4eb..4565cd81 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -376,31 +376,48 @@ UI_Key UI_BuildBoxEx(UI_Key key) { UI_State *g = &UI_state; UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode); + n->cmd.kind = UI_CmdKind_BuildBox; { - n->cmd.key = key; - n->cmd.parent = UI_UseTop(Parent); - n->cmd.flags = UI_UseTop(Flags); - n->cmd.pref_size[Axis_X] = UI_UseTop(Width); - n->cmd.pref_size[Axis_Y] = UI_UseTop(Height); - n->cmd.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); - n->cmd.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY); - n->cmd.child_layout_axis = UI_UseTop(ChildLayoutAxis); - n->cmd.background_color = UI_UseTop(BackgroundColor); - n->cmd.border_color = UI_UseTop(BorderColor); - n->cmd.debug_color = UI_UseTop(DebugColor); - n->cmd.tint = UI_UseTop(Tint); - n->cmd.border = UI_UseTop(Border); - n->cmd.font_resource = UI_UseTop(Font); - n->cmd.font_size = UI_UseTop(FontSize); - n->cmd.rounding = UI_UseTop(Rounding); - n->cmd.text = UI_UseTop(Text); - n->cmd.floating_pos = UI_UseTop(FloatingPos); + n->cmd.box.key = key; + n->cmd.box.parent = UI_UseTop(Parent); + n->cmd.box.flags = UI_UseTop(Flags); + n->cmd.box.pref_size[Axis_X] = UI_UseTop(Width); + n->cmd.box.pref_size[Axis_Y] = UI_UseTop(Height); + n->cmd.box.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); + n->cmd.box.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY); + n->cmd.box.child_layout_axis = UI_UseTop(ChildLayoutAxis); + n->cmd.box.background_color = UI_UseTop(BackgroundColor); + n->cmd.box.border_color = UI_UseTop(BorderColor); + n->cmd.box.debug_color = UI_UseTop(DebugColor); + n->cmd.box.tint = UI_UseTop(Tint); + n->cmd.box.border = UI_UseTop(Border); + n->cmd.box.font_resource = UI_UseTop(Font); + n->cmd.box.font_size = UI_UseTop(FontSize); + n->cmd.box.rounding = UI_UseTop(Rounding); + n->cmd.box.text = UI_UseTop(Text); + n->cmd.box.floating_pos = UI_UseTop(FloatingPos); } ++g->bframe.cmds_count; SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n); return key; } + +void UI_SetRawTexture(UI_Key key, GPU_Resource *texture, Vec2 uv0, Vec2 uv1) +{ + UI_State *g = &UI_state; + UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode); + n->cmd.kind = UI_CmdKind_SetRawTexture; + { + n->cmd.set_raw_texture.key = key; + n->cmd.set_raw_texture.texture = texture; + n->cmd.set_raw_texture.uv0 = uv0; + n->cmd.set_raw_texture.uv1 = uv1; + } + ++g->bframe.cmds_count; + SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n); +} + //////////////////////////////////////////////////////////// //~ Report @@ -421,7 +438,7 @@ UI_Report UI_ReportFromKey(UI_Key key) //////////////////////////////////////////////////////////// //~ Begin frame -UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) +UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) { UI_State *g = &UI_state; UI_Frame result = ZI; @@ -474,6 +491,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) } g->bframe.frame_flags = frame_flags; + g->bframe.swapchain_color = swapchain_color; ////////////////////////////// //- Begin window frame @@ -509,7 +527,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) for (u64 pre_index = g->boxes_count; pre_index-- > 0;) { UI_Box *box = g->eframe.boxes_pre[pre_index]; - if (hovered_box == 0 && box->cmd.flags & UI_BoxFlag_Interactable) + if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable) { b32 is_cursor_in_box = 0; { @@ -713,104 +731,125 @@ i64 UI_EndFrame(UI_Frame frame) ////////////////////////////// //- Process commands + /* FIXME: Reset raw texture data */ + g->boxes_count = 0; for (UI_CmdNode *cmd_node = g->bframe.first_cmd_node; cmd_node; cmd_node = cmd_node->next) { UI_Cmd cmd = cmd_node->cmd; - UI_Key key = cmd.key; - if (key.hash == 0) + switch (cmd.kind) { - key = UI_TransKey(); - } - - b32 is_root = g->eframe.root_box == 0; - UI_Box *parent = 0; - if (!is_root) - { - parent = UI_BoxFromKey(cmd.parent); - if (!parent) + case UI_CmdKind_BuildBox: { - parent = g->eframe.root_box; - } - } - - /* Allocate box */ - UI_Box *box = 0; - { - UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins]; - for (UI_Box *tmp = bin->first; tmp && !box; tmp = tmp->next_in_bin) - { - if (tmp->key.hash == key.hash) + UI_Key key = cmd.box.key; + if (key.hash == 0) { - box = tmp; + key = UI_TransKey(); } - } - if (box) - { - /* Remove box from old parent */ - if (box->parent) + + b32 is_root = g->eframe.root_box == 0; + UI_Box *parent = 0; + if (!is_root) { - DllQueueRemove(box->parent->first, box->parent->last, box); - --box->parent->count; + parent = UI_BoxFromKey(cmd.box.parent); + if (!parent) + { + parent = g->eframe.root_box; + } } - } - else + + /* Allocate box */ + UI_Box *box = 0; + { + UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins]; + for (UI_Box *tmp = bin->first; tmp && !box; tmp = tmp->next_in_bin) + { + if (tmp->key.hash == key.hash) + { + box = tmp; + } + } + if (box) + { + /* Remove box from old parent */ + if (box->parent) + { + DllQueueRemove(box->parent->first, box->parent->last, box); + --box->parent->count; + } + } + else + { + box = g->first_free_box; + if (box) + { + SllStackPop(g->first_free_box); + ZeroStruct(box); + } + else + { + box = PushStruct(g->box_arena, UI_Box); + } + DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); + } + } + ++g->boxes_count; + + /* Reset box */ + UI_Box old_box = *box; + { + ZeroStruct(box); + box->next_in_bin = old_box.next_in_bin; + box->prev_in_bin = old_box.prev_in_bin; + box->report = old_box.report; + } + box->key = key; + box->last_updated_tick = g->eframe.tick; + + /* Update box */ + { + box->desc = cmd.box; + + /* Insert box into parent */ + if (parent) + { + DllQueuePush(parent->first, parent->last, box); + box->parent = parent; + ++parent->count; + } + + /* Prefetch font */ + if (box->desc.text.len > 0) + { + box->font = F_LoadFontAsync(box->desc.font_resource, box->desc.font_size); + if (box->font) + { + box->glyph_run = F_RunFromString(g->eframe.layout_arena, box->font, box->desc.text); + } + } + } + + if (is_root) + { + g->eframe.root_box = box; + } + } break; + + case UI_CmdKind_SetRawTexture: { - box = g->first_free_box; + UI_Key key = cmd.set_raw_texture.key; + UI_Box *box = UI_BoxFromKey(key); if (box) { - SllStackPop(g->first_free_box); - ZeroStruct(box); + box->raw_texture = cmd.set_raw_texture.texture; + box->raw_texture_uv0 = cmd.set_raw_texture.uv0; + box->raw_texture_uv1 = cmd.set_raw_texture.uv1; } - else - { - box = PushStruct(g->box_arena, UI_Box); - } - DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); - } - } - ++g->boxes_count; - - /* Reset box */ - UI_Box old_box = *box; - { - ZeroStruct(box); - box->next_in_bin = old_box.next_in_bin; - box->prev_in_bin = old_box.prev_in_bin; - box->report = old_box.report; - } - box->key = key; - box->last_updated_tick = g->eframe.tick; - - /* Update box */ - { - box->cmd = cmd; - - /* Insert box into parent */ - if (parent) - { - DllQueuePush(parent->first, parent->last, box); - box->parent = parent; - ++parent->count; - } - - /* Prefetch font */ - if (box->cmd.text.len > 0) - { - box->font = F_LoadFontAsync(box->cmd.font_resource, box->cmd.font_size); - if (box->font) - { - box->glyph_run = F_RunFromString(g->eframe.layout_arena, box->font, box->cmd.text); - } - } + } break; } - if (is_root) - { - g->eframe.root_box = box; - } } ////////////////////////////// @@ -855,7 +894,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Push floating children to dfs stack */ for (UI_Box *child = box->last; child; child = child->prev) { - if (AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) + if (AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { BoxNode *child_n = PushStruct(scratch.arena, BoxNode); child_n->box = child; @@ -865,7 +904,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Push non-floating children to dfs stack */ for (UI_Box *child = box->last; child; child = child->prev) { - if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { BoxNode *child_n = PushStruct(scratch.arena, BoxNode); child_n->box = child; @@ -893,12 +932,12 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_pre[pre_index]; for (Axis axis = 0; axis < Axis_CountXY; ++axis) { - UI_Size pref_size = box->cmd.pref_size[axis]; + UI_Size pref_size = box->desc.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Pixel) { box->solved_dims[axis] = pref_size.v; } - else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->cmd.flags, UI_BoxFlag_DrawText)) + else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) { /* TODO: Distinguish between baseline alignment & visual alignment */ f32 text_size = 0; @@ -929,16 +968,16 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_pre[pre_index]; if (box->parent) { - Axis axis = box->parent->cmd.child_layout_axis; - UI_Size pref_size = box->cmd.pref_size[axis]; + Axis axis = box->parent->desc.child_layout_axis; + UI_Size pref_size = box->desc.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Grow) { f32 match_size = 0; b32 found_match = 0; for (UI_Box *ancestor = box->parent; ancestor != 0 && !found_match; ancestor = ancestor->parent) { - UI_Size ancestor_size = ancestor->cmd.pref_size[axis]; - if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->cmd.flags, UI_BoxFlag_DrawText))) + UI_Size ancestor_size = ancestor->desc.pref_size[axis]; + if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))) { /* Match independent ancestor */ match_size = ancestor->solved_dims[axis]; @@ -956,15 +995,15 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_post[post_index]; for (Axis axis = 0; axis < Axis_CountXY; ++axis) { - UI_Size pref_size = box->cmd.pref_size[axis]; - if (pref_size.kind == UI_SizeKind_Shrink && !AnyBit(box->cmd.flags, UI_BoxFlag_DrawText)) + UI_Size pref_size = box->desc.pref_size[axis]; + if (pref_size.kind == UI_SizeKind_Shrink && !AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) { f32 accum = 0; for (UI_Box *child = box->first; child; child = child->next) { - if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { - if (axis == box->cmd.child_layout_axis) + if (axis == box->desc.child_layout_axis) { accum += child->solved_dims[axis]; } @@ -985,8 +1024,8 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_pre[pre_index]; if (box->parent) { - Axis axis = !box->parent->cmd.child_layout_axis; - UI_Size pref_size = box->cmd.pref_size[axis]; + Axis axis = !box->parent->desc.child_layout_axis; + UI_Size pref_size = box->desc.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Grow) { box->solved_dims[axis] = box->parent->solved_dims[axis] * pref_size.v; @@ -1007,12 +1046,12 @@ i64 UI_EndFrame(UI_Frame frame) f32 flex_accum = 0; for (UI_Box *child = box->first; child; child = child->next) { - if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { f32 size = child->solved_dims[axis]; - f32 strictness = child->cmd.pref_size[axis].strictness; + f32 strictness = child->desc.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); - if (axis == box->cmd.child_layout_axis) + if (axis == box->desc.child_layout_axis) { size_accum += size; flex_accum += flex; @@ -1030,13 +1069,13 @@ i64 UI_EndFrame(UI_Frame frame) f32 adjusted_size_accum = 0; for (UI_Box *child = box->first; child; child = child->next) { - if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { f32 size = child->solved_dims[axis]; - f32 strictness = child->cmd.pref_size[axis].strictness; + f32 strictness = child->desc.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); f32 new_size = size; - if (axis == box->cmd.child_layout_axis) + if (axis == box->desc.child_layout_axis) { f32 chopoff = MinF32(flex, violation * (flex / flex_accum)); new_size = size - chopoff; @@ -1059,12 +1098,12 @@ i64 UI_EndFrame(UI_Frame frame) /* Solve floating violations */ for (UI_Box *child = box->first; child; child = child->next) { - if (AnyBit(child->cmd.flags, UI_BoxFlag_Floating) && !AnyBit(child->cmd.flags, UI_BoxFlag_NoFloatingClamp)) + if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp)) { f32 size = child->solved_dims[axis]; if (size > box_size) { - f32 strictness = child->cmd.pref_size[axis].strictness; + f32 strictness = child->desc.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); child->solved_dims[axis] = MaxF32(size - flex, box_size); } @@ -1081,8 +1120,8 @@ i64 UI_EndFrame(UI_Frame frame) /* Initialize layout cursor based on alignment */ { - Axis axis = box->cmd.child_layout_axis; - UI_AxisAlignment alignment = box->cmd.child_alignment[axis]; + Axis axis = box->desc.child_layout_axis; + UI_AxisAlignment alignment = box->desc.child_alignment[axis]; f32 box_size = box->solved_dims[axis]; f32 size_accum = box->final_children_size_accum[axis]; switch(alignment) @@ -1106,11 +1145,11 @@ i64 UI_EndFrame(UI_Frame frame) Vec2 final_pos = ZI; /* Floating box position */ - if (AnyBit(box->cmd.flags, UI_BoxFlag_Floating)) + if (AnyBit(box->desc.flags, UI_BoxFlag_Floating)) { - Vec2 offset = box->cmd.floating_pos; + Vec2 offset = box->desc.floating_pos; final_pos = AddVec2(parent->p0, offset); - if (!AnyBit(box->cmd.flags, UI_BoxFlag_NoFloatingClamp)) + if (!AnyBit(box->desc.flags, UI_BoxFlag_NoFloatingClamp)) { { f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->p1.x); @@ -1129,13 +1168,13 @@ i64 UI_EndFrame(UI_Frame frame) f32 offset[2] = ZI; /* Calculate offset in layout direction */ { - Axis axis = parent->cmd.child_layout_axis; + Axis axis = parent->desc.child_layout_axis; offset[axis] = layout_cursor; } /* Calculate offset in non-layout direction (based on alignment) */ { - Axis axis = !parent->cmd.child_layout_axis; - UI_AxisAlignment alignment = parent->cmd.child_alignment[axis]; + Axis axis = !parent->desc.child_layout_axis; + UI_AxisAlignment alignment = parent->desc.child_alignment[axis]; switch(alignment) { default: break; @@ -1155,7 +1194,7 @@ i64 UI_EndFrame(UI_Frame frame) } final_pos.x = parent->p0.x + offset[0]; final_pos.y = parent->p0.y + offset[1]; - parent->layout_cursor += dims_arr[parent->cmd.child_layout_axis]; + parent->layout_cursor += dims_arr[parent->desc.child_layout_axis]; } /* Submit position */ @@ -1167,7 +1206,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Rounding */ { - UI_Round rounding = box->cmd.rounding; + UI_Round rounding = box->desc.rounding; Vec2 half_dims = MulVec2(SubVec2(box->p1, box->p0), 0.5); f32 min_half_dims = MinF32(half_dims.x, half_dims.y); f32 final_rounding_tl = 0; @@ -1194,7 +1233,7 @@ i64 UI_EndFrame(UI_Frame frame) } break; } - if (parent && !AllBits(box->cmd.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) + if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) { Vec2 vtl = SubVec2(VEC2(parent->p0.x, parent->p0.y), VEC2(box->p0.x, box->p0.y)); Vec2 vtr = SubVec2(VEC2(parent->p1.x, parent->p0.y), VEC2(box->p1.x, box->p0.y)); @@ -1225,7 +1264,7 @@ i64 UI_EndFrame(UI_Frame frame) { UI_Box *box = boxes_pre[pre_index]; b32 is_visible = 1; - is_visible = is_visible && (box->cmd.tint.w != 0); + is_visible = is_visible && (box->desc.tint.w != 0); is_visible = is_visible && (box->p1.x > box->p0.x); is_visible = is_visible && (box->p1.y > box->p0.y); if (is_visible || AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug)) @@ -1233,32 +1272,32 @@ i64 UI_EndFrame(UI_Frame frame) /* Box rect */ { UI_DRect *rect = PushStruct(g->eframe.rects_arena, UI_DRect); - rect->flags |= UI_DRectFlag_DrawTexture * !!(box->cmd.background_texture != 0); + rect->flags |= UI_DRectFlag_DrawTexture * !!(box->raw_texture != 0); rect->p0 = box->p0; rect->p1 = box->p1; rect->tex_uv0 = VEC2(0, 0); rect->tex_uv1 = VEC2(1, 1); - rect->background_lin = LinearFromSrgb(box->cmd.background_color); - rect->border_lin = LinearFromSrgb(box->cmd.border_color); - rect->debug_lin = LinearFromSrgb(box->cmd.debug_color); - rect->tint_lin = LinearFromSrgb(box->cmd.tint); - rect->border = box->cmd.border; + rect->background_lin = LinearFromSrgb(box->desc.background_color); + rect->border_lin = LinearFromSrgb(box->desc.border_color); + rect->debug_lin = LinearFromSrgb(box->desc.debug_color); + rect->tint_lin = LinearFromSrgb(box->desc.tint); + rect->border = box->desc.border; rect->tl_rounding = box->rounding_tl; rect->tr_rounding = box->rounding_tr; rect->br_rounding = box->rounding_br; rect->bl_rounding = box->rounding_bl; /* Texture */ - if (box->cmd.background_texture != 0) + if (box->raw_texture != 0) { - rect->tex = GPU_Texture2DRidFromResource(box->cmd.background_texture); - rect->tex_uv0 = box->cmd.background_texture_uv0; - rect->tex_uv1 = box->cmd.background_texture_uv1; + rect->tex = GPU_Texture2DRidFromResource(box->raw_texture); + rect->tex_uv0 = box->raw_texture_uv0; + rect->tex_uv1 = box->raw_texture_uv1; } } /* Text rects */ - if (AnyBit(box->cmd.flags, UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font) + if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font) { Texture2DRid tex_rid = GPU_Texture2DRidFromResource(box->font->texture); Vec2 inv_font_image_size = VEC2(1.0f / (f32)box->font->image_width, 1.0f / (f32)box->font->image_height); @@ -1268,7 +1307,7 @@ i64 UI_EndFrame(UI_Frame frame) b32 should_truncate = run.count > 0 && (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) > max_baseline; /* Truncate run */ - if (should_truncate && !AnyBit(box->cmd.flags, UI_BoxFlag_NoTextTruncation)) + if (should_truncate && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation)) { /* Get elipses run */ F_Run trunc_run = F_RunFromString(scratch.arena, box->font, Lit("...")); @@ -1305,8 +1344,8 @@ i64 UI_EndFrame(UI_Frame frame) run.rects = new_rects; } - UI_AxisAlignment x_alignment = box->cmd.child_alignment[Axis_X]; - UI_AxisAlignment y_alignment = box->cmd.child_alignment[Axis_Y]; + UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X]; + UI_AxisAlignment y_alignment = box->desc.child_alignment[Axis_Y]; if (should_truncate) { x_alignment = UI_AxisAlignment_Start; @@ -1373,8 +1412,8 @@ i64 UI_EndFrame(UI_Frame frame) rect->p0 = AddVec2(baseline, VEC2(rr.pos, 0)); rect->p0 = AddVec2(rect->p0, rr.offset); rect->p1 = AddVec2(rect->p0, glyph_size); - rect->debug_lin = LinearFromSrgb(box->cmd.debug_color); - rect->tint_lin = LinearFromSrgb(box->cmd.tint); + rect->debug_lin = LinearFromSrgb(box->desc.debug_color); + rect->tint_lin = LinearFromSrgb(box->desc.tint); rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size); rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size); rect->tex = tex_rid; @@ -1467,7 +1506,7 @@ i64 UI_EndFrame(UI_Frame frame) Vec2I32 dst_p1 = VEC2I32(0, 0); Vec2I32 src_p0 = VEC2I32(0, 0); Vec2I32 src_p1 = draw_size; - g->eframe.gpu_submit_fence_target = GPU_PresentSwapchain(g->eframe.swapchain, g->eframe.render_target, AnyBit(g->bframe.frame_flags, UI_FrameFlag_Vsync), backbuffer_size, dst_p0, dst_p1, src_p0, src_p1); + g->eframe.gpu_submit_fence_target = GPU_PresentSwapchain(g->eframe.swapchain, g->eframe.render_target, AnyBit(g->bframe.frame_flags, UI_FrameFlag_Vsync), backbuffer_size, dst_p0, dst_p1, src_p0, src_p1, LinearFromSrgb(g->bframe.swapchain_color)); } WND_EndFrame(frame.window_frame); diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index d99bcbaa..2300fe4a 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -194,17 +194,20 @@ Struct(UI_Report) //////////////////////////////////////////////////////////// //~ Command types -Struct(UI_Cmd) +Enum(UI_CmdKind) +{ + UI_CmdKind_None, + UI_CmdKind_BuildBox, + UI_CmdKind_SetRawTexture, +}; + +Struct(UI_BoxDesc) { UI_BoxFlag flags; UI_Key key; UI_Key parent; - GPU_Resource *background_texture; - Vec2 background_texture_uv0; - Vec2 background_texture_uv1; - UI_Size pref_size[Axis_CountXY]; UI_Round rounding; Vec4 background_color; @@ -220,6 +223,22 @@ Struct(UI_Cmd) UI_AxisAlignment child_alignment[Axis_CountXY]; }; +Struct(UI_Cmd) +{ + UI_CmdKind kind; + union + { + UI_BoxDesc box; + struct + { + UI_Key key; + GPU_Resource *texture; + Vec2 uv0; + Vec2 uv1; + } set_raw_texture; + }; +}; + Struct(UI_CmdNode) { UI_CmdNode *next; @@ -248,7 +267,10 @@ Struct(UI_Box) u64 count; //- Cmd data - UI_Cmd cmd; + UI_BoxDesc desc; + GPU_Resource *raw_texture; + Vec2 raw_texture_uv0; + Vec2 raw_texture_uv1; //- Pre-layout data u64 pre_index; @@ -333,6 +355,7 @@ Struct(UI_State) UI_Key active_box; /* Cmds */ + Vec4 swapchain_color; UI_FrameFlag frame_flags; UI_CmdNode *first_cmd_node; UI_CmdNode *last_cmd_node; @@ -449,6 +472,8 @@ UI_Style UI_PopStyle(UI_StyleDesc desc); UI_Key UI_BuildBoxEx(UI_Key key); #define UI_BuildBox() UI_BuildBoxEx(UI_TransKey()) +void UI_SetRawTexture(UI_Key key, GPU_Resource *texture, Vec2 uv0, Vec2 uv1); + //////////////////////////////////////////////////////////// //~ Report @@ -457,7 +482,7 @@ UI_Report UI_ReportFromKey(UI_Key key); //////////////////////////////////////////////////////////// //~ Begin frame -UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags); +UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color); //////////////////////////////////////////////////////////// //~ Frame helpers