prep vis renderer

This commit is contained in:
jacob 2025-11-12 18:37:24 -06:00
parent 030d9ad6a8
commit fe34752146
11 changed files with 572 additions and 220 deletions

View File

@ -493,4 +493,4 @@ void GPU_YieldOnSwapchain(GPU_Swapchain *swapchain);
* 2. Blits `texture` into position `dst` in the backbuffer * 2. Blits `texture` into position `dst` in the backbuffer
* 3. Presents 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) */ * 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);

View File

@ -1960,7 +1960,7 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V
return &swapchain->buffers[backbuffer_index]; 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; 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 */ /* Clear */
{ {
f32 clear_color[4] = ZI; ID3D12GraphicsCommandList_ClearRenderTargetView(rcl, dst->rtv_descriptor->handle, (f32 *)&clear_color, 0, 0);
ID3D12GraphicsCommandList_ClearRenderTargetView(rcl, dst->rtv_descriptor->handle, 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_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain;
GPU_D12_Resource *texture = (GPU_D12_Resource *)gpu_texture; 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) if (is_blitable)
{ {
/* Blit */ /* 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; u32 present_flags = 0;
if (GPU_D12_TearingIsAllowed && vsync == 0) if (GPU_D12_TearingIsAllowed && vsync == 0)

View File

@ -380,7 +380,7 @@ u64 GPU_D12_EndRawCommandList(GPU_D12_RawCommandList *cl);
void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain); void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain);
GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution); 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 //~ Sync job

View File

@ -48,6 +48,117 @@ b32 S_IsEntNil(S_Ent *ent)
return ent == 0 || ent == &S_nil_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 //~ Sim worker
@ -58,24 +169,34 @@ JobDef(S_SimWorker, sig, job_id)
Arena *perm = PermArena(); Arena *perm = PermArena();
//- World data //- World data
Arena *ents_arena = AcquireArena(Gibi(64)); Arena *world_arena = AcquireArena(Gibi(64));
S_Ent *ents = ArenaFirst(ents_arena, S_Ent); S_World *world = 0;
i64 tick = 0;
/* Create root ent */
{ {
S_Ent *root_ent = PushStruct(ents_arena, S_Ent); S_Snapshot *empty_ss = PushStruct(frame_arena, S_Snapshot);
*root_ent = S_nil_ent; {
root_ent->key = S_RootEntKey; 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 */ test_ent->parent = root_ent->key;
{ root_ent->first = test_ent->key;
S_Ent *test_ent = PushStruct(ents_arena, S_Ent); root_ent->last = test_ent->key;
*test_ent = S_nil_ent; ++root_ent->count;
test_ent->parent = S_RootEntKey; }
test_ent->shape.points_count = 1; }
test_ent->shape.radius = 0.25; world = S_WorldFromSnapshot(world_arena, empty_ss);
} }
////////////////////////////// //////////////////////////////
@ -127,17 +248,18 @@ JobDef(S_SimWorker, sig, job_id)
LockTicketMutex(&shared->output_back_tm); LockTicketMutex(&shared->output_back_tm);
{ {
S_OutputState *output = &shared->output_states[shared->output_back_idx]; S_OutputState *output = &shared->output_states[shared->output_back_idx];
S_WorldNode *world_node = PushStruct(output->arena, S_WorldNode); S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode);
S_World *world = &world_node->world; S_Snapshot *snapshot = &snapshot_node->snapshot;
SllQueuePush(output->first_world_node, output->last_world_node, world_node); SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
++output->worlds_count; ++output->snapshots_count;
world->ents_count = ArenaCount(ents_arena, S_Ent); snapshot->ents_count = world->ents_count;
world->tick = tick; snapshot->tick = world->tick;
world->ents = PushStructsNoZero(output->arena, S_Ent, world->ents_count); snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx) for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)
{ {
S_Ent *ent = &ents[ent_idx]; S_Ent *src = &world->ents[ent_idx];
world->ents[ent_idx] = *ent; S_Ent *dst = &snapshot->ents[ent_idx];
*dst = *src;
} }
} }
UnlockTicketMutex(&shared->output_back_tm); UnlockTicketMutex(&shared->output_back_tm);
@ -155,7 +277,7 @@ JobDef(S_SimWorker, sig, job_id)
i64 frame_end_ns = TimeNs(); i64 frame_end_ns = TimeNs();
++tick; ++world->tick;
////////////////////////////// //////////////////////////////
//- Sleep //- Sleep

View File

@ -35,19 +35,32 @@ Enum(S_EntProp)
Struct(S_Ent) Struct(S_Ent)
{ {
//- Tree data
S_EntKey parent; S_EntKey parent;
S_EntKey first; S_EntKey first;
S_EntKey last; S_EntKey last;
S_EntKey next; S_EntKey next;
S_EntKey prev; S_EntKey prev;
i64 count;
//- Persistent data
S_EntKey key; S_EntKey key;
S_Shape shape; S_Shape shape;
//- Per-world data
i64 pre_idx;
i64 post_idx;
} extern Readonly S_nil_ent; } extern Readonly S_nil_ent;
////////////////////////////// //////////////////////////////
//- Ent list //- Ent containers
Struct(S_EntArray)
{
i64 count;
S_Ent *ents;
};
Struct(S_EntListNode) Struct(S_EntListNode)
{ {
@ -62,28 +75,40 @@ Struct(S_EntList)
u64 count; u64 count;
}; };
//////////////////////////////////////////////////////////// Struct(S_EntLookupNode)
//~ Lookup types
Struct(S_EntLookupBin)
{ {
i32 _; S_EntLookupNode *next;
S_Ent *ent;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ World types //~ World types
Struct(S_World) 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; i64 tick;
S_Ent *ents; S_Ent *ents;
i64 ents_count; i64 ents_count;
}; };
Struct(S_WorldNode) Struct(S_SnapshotNode)
{ {
S_WorldNode *next; S_SnapshotNode *next;
S_World world; S_Snapshot snapshot;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -124,9 +149,9 @@ Struct(S_InputState)
Struct(S_OutputState) Struct(S_OutputState)
{ {
Arena *arena; Arena *arena;
S_WorldNode *first_world_node; S_SnapshotNode *first_snapshot_node;
S_WorldNode *last_world_node; S_SnapshotNode *last_snapshot_node;
u64 worlds_count; u64 snapshots_count;
}; };
Struct(S_SharedState) Struct(S_SharedState)
@ -158,6 +183,17 @@ void S_Shutdown(void);
b32 S_IsKeyNil(S_EntKey key); b32 S_IsKeyNil(S_EntKey key);
b32 S_IsEntNil(S_Ent *ent); 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 //~ Sim worker

View File

@ -15,14 +15,21 @@
//- Api //- Api
@IncludeC pp_vis_widgets.h @IncludeC pp_vis_widgets.h
@IncludeC pp_vis_draw.h
@IncludeC pp_vis_core.h @IncludeC pp_vis_core.h
@IncludeGpu pp_vis_draw.h
//- Impl //- Impl
@IncludeC pp_vis_widgets.c @IncludeC pp_vis_widgets.c
@IncludeC pp_vis_core.c @IncludeC pp_vis_core.c
@IncludeGpu pp_vis_draw.gpu
//- Embeds //- Embeds
@EmbedDir V_Resources pp_vis_res @EmbedDir V_Resources pp_vis_res
//- Shaders
@VertexShader V_DQuadVS
@PixelShader V_DQuadPS
//- Startup //- Startup
@Startup V_Startup @Startup V_Startup

View File

@ -32,17 +32,22 @@ JobDef(V_VisWorker, sig, job_id)
Arena *frame_arena = AcquireArena(Gibi(64)); Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena(); 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; V_CommandsWidget commands_widget;
b32 ui_debug; b32 ui_debug;
b32 show_command_palette; b32 show_command_palette;
b32 show_console; b32 show_console;
}; };
VisPersist persist = ZI; Persist persist = ZI;
String window_restore = ZI; String window_restore = ZI;
Button held_buttons[Button_Count] = ZI; Button held_buttons[Button_Count] = ZI;
@ -87,7 +92,7 @@ JobDef(V_VisWorker, sig, job_id)
BB_Reader br = BB_ReaderFromBuff(&bb); BB_Reader br = BB_ReaderFromBuff(&bb);
String swap_str = BB_ReadString(scratch.arena, &br); 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); CopyBytes(&persist, swap_str.text, swap_str.len);
} }
@ -102,14 +107,8 @@ JobDef(V_VisWorker, sig, job_id)
Arena *world_arena = AcquireArena(Gibi(64));
Arena *ents_arena = AcquireArena(Gibi(64)); S_World *world = PushStruct(world_arena, S_World);
S_Ent *ents = ArenaFirst(ents_arena, S_Ent);
i64 tick = 0;
b32 shutdown = 0; b32 shutdown = 0;
while (!shutdown) while (!shutdown)
@ -120,11 +119,13 @@ JobDef(V_VisWorker, sig, job_id)
//- Begin vis frame //- Begin vis frame
UI_FrameFlag ui_frame_flags = 0; 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_Debug * !!persist.ui_debug;
ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; 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; WND_Frame window_frame = ui_frame.window_frame;
Vec2 ui_cursor = ui_frame.cursor_pos; Vec2 ui_cursor = ui_frame.cursor_pos;
Vec2I32 draw_size = window_frame.monitor_size;
/* Restore window */ /* Restore window */
{ {
@ -142,8 +143,8 @@ JobDef(V_VisWorker, sig, job_id)
UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(ChildLayoutAxis, Axis_Y);
UI_Push(Width, UI_GROW(1, 0)); UI_Push(Width, UI_GROW(1, 0));
UI_Push(Height, 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 //- Pop sim output
@ -160,6 +161,12 @@ JobDef(V_VisWorker, sig, job_id)
} }
UnlockTicketMutex(&sim_shared->output_back_tm); 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 //- Process controller events vis cmds
@ -329,13 +336,53 @@ JobDef(V_VisWorker, sig, job_id)
////////////////////////////// //////////////////////////////
//- Render //- 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 //- End vis frame
UI_SetRawTexture(vis_box, draw_target, VEC2(0, 0), VEC2(1, 1));
gpu_fence_target = UI_EndFrame(ui_frame); gpu_fence_target = UI_EndFrame(ui_frame);
++frame_gen; ++frame_gen;

View File

@ -0,0 +1,49 @@
ConstantBuffer<V_DQuadSig> 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<V_DQuadSig> sig = V_dquad_sig;
StructuredBuffer<V_DQuad> 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<V_DQuadSig> sig = V_dquad_sig;
StructuredBuffer<V_DQuad> 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;
}

View File

@ -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;
};

View File

@ -376,31 +376,48 @@ UI_Key UI_BuildBoxEx(UI_Key key)
{ {
UI_State *g = &UI_state; UI_State *g = &UI_state;
UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode); UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode);
n->cmd.kind = UI_CmdKind_BuildBox;
{ {
n->cmd.key = key; n->cmd.box.key = key;
n->cmd.parent = UI_UseTop(Parent); n->cmd.box.parent = UI_UseTop(Parent);
n->cmd.flags = UI_UseTop(Flags); n->cmd.box.flags = UI_UseTop(Flags);
n->cmd.pref_size[Axis_X] = UI_UseTop(Width); n->cmd.box.pref_size[Axis_X] = UI_UseTop(Width);
n->cmd.pref_size[Axis_Y] = UI_UseTop(Height); n->cmd.box.pref_size[Axis_Y] = UI_UseTop(Height);
n->cmd.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); n->cmd.box.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX);
n->cmd.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY); n->cmd.box.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY);
n->cmd.child_layout_axis = UI_UseTop(ChildLayoutAxis); n->cmd.box.child_layout_axis = UI_UseTop(ChildLayoutAxis);
n->cmd.background_color = UI_UseTop(BackgroundColor); n->cmd.box.background_color = UI_UseTop(BackgroundColor);
n->cmd.border_color = UI_UseTop(BorderColor); n->cmd.box.border_color = UI_UseTop(BorderColor);
n->cmd.debug_color = UI_UseTop(DebugColor); n->cmd.box.debug_color = UI_UseTop(DebugColor);
n->cmd.tint = UI_UseTop(Tint); n->cmd.box.tint = UI_UseTop(Tint);
n->cmd.border = UI_UseTop(Border); n->cmd.box.border = UI_UseTop(Border);
n->cmd.font_resource = UI_UseTop(Font); n->cmd.box.font_resource = UI_UseTop(Font);
n->cmd.font_size = UI_UseTop(FontSize); n->cmd.box.font_size = UI_UseTop(FontSize);
n->cmd.rounding = UI_UseTop(Rounding); n->cmd.box.rounding = UI_UseTop(Rounding);
n->cmd.text = UI_UseTop(Text); n->cmd.box.text = UI_UseTop(Text);
n->cmd.floating_pos = UI_UseTop(FloatingPos); n->cmd.box.floating_pos = UI_UseTop(FloatingPos);
} }
++g->bframe.cmds_count; ++g->bframe.cmds_count;
SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n); SllQueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n);
return key; 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 //~ Report
@ -421,7 +438,7 @@ UI_Report UI_ReportFromKey(UI_Key key)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Begin frame //~ 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_State *g = &UI_state;
UI_Frame result = ZI; UI_Frame result = ZI;
@ -474,6 +491,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags)
} }
g->bframe.frame_flags = frame_flags; g->bframe.frame_flags = frame_flags;
g->bframe.swapchain_color = swapchain_color;
////////////////////////////// //////////////////////////////
//- Begin window frame //- 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;) for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{ {
UI_Box *box = g->eframe.boxes_pre[pre_index]; 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; b32 is_cursor_in_box = 0;
{ {
@ -713,104 +731,125 @@ i64 UI_EndFrame(UI_Frame frame)
////////////////////////////// //////////////////////////////
//- Process commands //- Process commands
/* FIXME: Reset raw texture data */
g->boxes_count = 0; g->boxes_count = 0;
for (UI_CmdNode *cmd_node = g->bframe.first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (UI_CmdNode *cmd_node = g->bframe.first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
UI_Cmd cmd = cmd_node->cmd; UI_Cmd cmd = cmd_node->cmd;
UI_Key key = cmd.key; switch (cmd.kind)
if (key.hash == 0)
{ {
key = UI_TransKey(); case UI_CmdKind_BuildBox:
}
b32 is_root = g->eframe.root_box == 0;
UI_Box *parent = 0;
if (!is_root)
{
parent = UI_BoxFromKey(cmd.parent);
if (!parent)
{ {
parent = g->eframe.root_box; UI_Key key = cmd.box.key;
} if (key.hash == 0)
}
/* 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; key = UI_TransKey();
} }
}
if (box) b32 is_root = g->eframe.root_box == 0;
{ UI_Box *parent = 0;
/* Remove box from old parent */ if (!is_root)
if (box->parent)
{ {
DllQueueRemove(box->parent->first, box->parent->last, box); parent = UI_BoxFromKey(cmd.box.parent);
--box->parent->count; 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) if (box)
{ {
SllStackPop(g->first_free_box); box->raw_texture = cmd.set_raw_texture.texture;
ZeroStruct(box); box->raw_texture_uv0 = cmd.set_raw_texture.uv0;
box->raw_texture_uv1 = cmd.set_raw_texture.uv1;
} }
else } break;
{
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);
}
}
} }
if (is_root)
{
g->eframe.root_box = box;
}
} }
////////////////////////////// //////////////////////////////
@ -855,7 +894,7 @@ i64 UI_EndFrame(UI_Frame frame)
/* Push floating children to dfs stack */ /* Push floating children to dfs stack */
for (UI_Box *child = box->last; child; child = child->prev) 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); BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
child_n->box = child; child_n->box = child;
@ -865,7 +904,7 @@ i64 UI_EndFrame(UI_Frame frame)
/* Push non-floating children to dfs stack */ /* Push non-floating children to dfs stack */
for (UI_Box *child = box->last; child; child = child->prev) 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); BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
child_n->box = child; child_n->box = child;
@ -893,12 +932,12 @@ i64 UI_EndFrame(UI_Frame frame)
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
for (Axis axis = 0; axis < Axis_CountXY; ++axis) 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) if (pref_size.kind == UI_SizeKind_Pixel)
{ {
box->solved_dims[axis] = pref_size.v; 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 */ /* TODO: Distinguish between baseline alignment & visual alignment */
f32 text_size = 0; f32 text_size = 0;
@ -929,16 +968,16 @@ i64 UI_EndFrame(UI_Frame frame)
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
if (box->parent) if (box->parent)
{ {
Axis axis = box->parent->cmd.child_layout_axis; Axis axis = box->parent->desc.child_layout_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_Grow) if (pref_size.kind == UI_SizeKind_Grow)
{ {
f32 match_size = 0; f32 match_size = 0;
b32 found_match = 0; b32 found_match = 0;
for (UI_Box *ancestor = box->parent; ancestor != 0 && !found_match; ancestor = ancestor->parent) for (UI_Box *ancestor = box->parent; ancestor != 0 && !found_match; ancestor = ancestor->parent)
{ {
UI_Size ancestor_size = ancestor->cmd.pref_size[axis]; UI_Size ancestor_size = ancestor->desc.pref_size[axis];
if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->cmd.flags, UI_BoxFlag_DrawText))) if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
{ {
/* Match independent ancestor */ /* Match independent ancestor */
match_size = ancestor->solved_dims[axis]; match_size = ancestor->solved_dims[axis];
@ -956,15 +995,15 @@ i64 UI_EndFrame(UI_Frame frame)
UI_Box *box = boxes_post[post_index]; UI_Box *box = boxes_post[post_index];
for (Axis axis = 0; axis < Axis_CountXY; ++axis) 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_Shrink && !AnyBit(box->cmd.flags, UI_BoxFlag_DrawText)) if (pref_size.kind == UI_SizeKind_Shrink && !AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
{ {
f32 accum = 0; f32 accum = 0;
for (UI_Box *child = box->first; child; child = child->next) 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]; accum += child->solved_dims[axis];
} }
@ -985,8 +1024,8 @@ i64 UI_EndFrame(UI_Frame frame)
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
if (box->parent) if (box->parent)
{ {
Axis axis = !box->parent->cmd.child_layout_axis; Axis axis = !box->parent->desc.child_layout_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_Grow) if (pref_size.kind == UI_SizeKind_Grow)
{ {
box->solved_dims[axis] = box->parent->solved_dims[axis] * pref_size.v; 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; f32 flex_accum = 0;
for (UI_Box *child = box->first; child; child = child->next) 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 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 flex = size * (1.0 - strictness);
if (axis == box->cmd.child_layout_axis) if (axis == box->desc.child_layout_axis)
{ {
size_accum += size; size_accum += size;
flex_accum += flex; flex_accum += flex;
@ -1030,13 +1069,13 @@ i64 UI_EndFrame(UI_Frame frame)
f32 adjusted_size_accum = 0; f32 adjusted_size_accum = 0;
for (UI_Box *child = box->first; child; child = child->next) 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 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 flex = size * (1.0 - strictness);
f32 new_size = size; 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)); f32 chopoff = MinF32(flex, violation * (flex / flex_accum));
new_size = size - chopoff; new_size = size - chopoff;
@ -1059,12 +1098,12 @@ i64 UI_EndFrame(UI_Frame frame)
/* Solve floating violations */ /* Solve floating violations */
for (UI_Box *child = box->first; child; child = child->next) 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]; f32 size = child->solved_dims[axis];
if (size > box_size) 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); f32 flex = size * (1.0 - strictness);
child->solved_dims[axis] = MaxF32(size - flex, box_size); 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 */ /* Initialize layout cursor based on alignment */
{ {
Axis axis = box->cmd.child_layout_axis; Axis axis = box->desc.child_layout_axis;
UI_AxisAlignment alignment = box->cmd.child_alignment[axis]; UI_AxisAlignment alignment = box->desc.child_alignment[axis];
f32 box_size = box->solved_dims[axis]; f32 box_size = box->solved_dims[axis];
f32 size_accum = box->final_children_size_accum[axis]; f32 size_accum = box->final_children_size_accum[axis];
switch(alignment) switch(alignment)
@ -1106,11 +1145,11 @@ i64 UI_EndFrame(UI_Frame frame)
Vec2 final_pos = ZI; Vec2 final_pos = ZI;
/* Floating box position */ /* 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); 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); 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; f32 offset[2] = ZI;
/* Calculate offset in layout direction */ /* Calculate offset in layout direction */
{ {
Axis axis = parent->cmd.child_layout_axis; Axis axis = parent->desc.child_layout_axis;
offset[axis] = layout_cursor; offset[axis] = layout_cursor;
} }
/* Calculate offset in non-layout direction (based on alignment) */ /* Calculate offset in non-layout direction (based on alignment) */
{ {
Axis axis = !parent->cmd.child_layout_axis; Axis axis = !parent->desc.child_layout_axis;
UI_AxisAlignment alignment = parent->cmd.child_alignment[axis]; UI_AxisAlignment alignment = parent->desc.child_alignment[axis];
switch(alignment) switch(alignment)
{ {
default: break; default: break;
@ -1155,7 +1194,7 @@ i64 UI_EndFrame(UI_Frame frame)
} }
final_pos.x = parent->p0.x + offset[0]; final_pos.x = parent->p0.x + offset[0];
final_pos.y = parent->p0.y + offset[1]; 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 */ /* Submit position */
@ -1167,7 +1206,7 @@ i64 UI_EndFrame(UI_Frame frame)
/* Rounding */ /* Rounding */
{ {
UI_Round rounding = box->cmd.rounding; UI_Round rounding = box->desc.rounding;
Vec2 half_dims = MulVec2(SubVec2(box->p1, box->p0), 0.5); Vec2 half_dims = MulVec2(SubVec2(box->p1, box->p0), 0.5);
f32 min_half_dims = MinF32(half_dims.x, half_dims.y); f32 min_half_dims = MinF32(half_dims.x, half_dims.y);
f32 final_rounding_tl = 0; f32 final_rounding_tl = 0;
@ -1194,7 +1233,7 @@ i64 UI_EndFrame(UI_Frame frame)
} break; } 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 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)); 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]; UI_Box *box = boxes_pre[pre_index];
b32 is_visible = 1; 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.x > box->p0.x);
is_visible = is_visible && (box->p1.y > box->p0.y); is_visible = is_visible && (box->p1.y > box->p0.y);
if (is_visible || AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug)) if (is_visible || AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug))
@ -1233,32 +1272,32 @@ i64 UI_EndFrame(UI_Frame frame)
/* Box rect */ /* Box rect */
{ {
UI_DRect *rect = PushStruct(g->eframe.rects_arena, UI_DRect); 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->p0 = box->p0;
rect->p1 = box->p1; rect->p1 = box->p1;
rect->tex_uv0 = VEC2(0, 0); rect->tex_uv0 = VEC2(0, 0);
rect->tex_uv1 = VEC2(1, 1); rect->tex_uv1 = VEC2(1, 1);
rect->background_lin = LinearFromSrgb(box->cmd.background_color); rect->background_lin = LinearFromSrgb(box->desc.background_color);
rect->border_lin = LinearFromSrgb(box->cmd.border_color); rect->border_lin = LinearFromSrgb(box->desc.border_color);
rect->debug_lin = LinearFromSrgb(box->cmd.debug_color); rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
rect->tint_lin = LinearFromSrgb(box->cmd.tint); rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->border = box->cmd.border; rect->border = box->desc.border;
rect->tl_rounding = box->rounding_tl; rect->tl_rounding = box->rounding_tl;
rect->tr_rounding = box->rounding_tr; rect->tr_rounding = box->rounding_tr;
rect->br_rounding = box->rounding_br; rect->br_rounding = box->rounding_br;
rect->bl_rounding = box->rounding_bl; rect->bl_rounding = box->rounding_bl;
/* Texture */ /* Texture */
if (box->cmd.background_texture != 0) if (box->raw_texture != 0)
{ {
rect->tex = GPU_Texture2DRidFromResource(box->cmd.background_texture); rect->tex = GPU_Texture2DRidFromResource(box->raw_texture);
rect->tex_uv0 = box->cmd.background_texture_uv0; rect->tex_uv0 = box->raw_texture_uv0;
rect->tex_uv1 = box->cmd.background_texture_uv1; rect->tex_uv1 = box->raw_texture_uv1;
} }
} }
/* Text rects */ /* 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); 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); 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; b32 should_truncate = run.count > 0 && (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) > max_baseline;
/* Truncate run */ /* 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 */ /* Get elipses run */
F_Run trunc_run = F_RunFromString(scratch.arena, box->font, Lit("...")); 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; run.rects = new_rects;
} }
UI_AxisAlignment x_alignment = box->cmd.child_alignment[Axis_X]; UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X];
UI_AxisAlignment y_alignment = box->cmd.child_alignment[Axis_Y]; UI_AxisAlignment y_alignment = box->desc.child_alignment[Axis_Y];
if (should_truncate) if (should_truncate)
{ {
x_alignment = UI_AxisAlignment_Start; 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(baseline, VEC2(rr.pos, 0));
rect->p0 = AddVec2(rect->p0, rr.offset); rect->p0 = AddVec2(rect->p0, rr.offset);
rect->p1 = AddVec2(rect->p0, glyph_size); rect->p1 = AddVec2(rect->p0, glyph_size);
rect->debug_lin = LinearFromSrgb(box->cmd.debug_color); rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
rect->tint_lin = LinearFromSrgb(box->cmd.tint); rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size); rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size);
rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size); rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size);
rect->tex = tex_rid; rect->tex = tex_rid;
@ -1467,7 +1506,7 @@ i64 UI_EndFrame(UI_Frame frame)
Vec2I32 dst_p1 = VEC2I32(0, 0); Vec2I32 dst_p1 = VEC2I32(0, 0);
Vec2I32 src_p0 = VEC2I32(0, 0); Vec2I32 src_p0 = VEC2I32(0, 0);
Vec2I32 src_p1 = draw_size; 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); WND_EndFrame(frame.window_frame);

View File

@ -194,17 +194,20 @@ Struct(UI_Report)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Command types //~ Command types
Struct(UI_Cmd) Enum(UI_CmdKind)
{
UI_CmdKind_None,
UI_CmdKind_BuildBox,
UI_CmdKind_SetRawTexture,
};
Struct(UI_BoxDesc)
{ {
UI_BoxFlag flags; UI_BoxFlag flags;
UI_Key key; UI_Key key;
UI_Key parent; UI_Key parent;
GPU_Resource *background_texture;
Vec2 background_texture_uv0;
Vec2 background_texture_uv1;
UI_Size pref_size[Axis_CountXY]; UI_Size pref_size[Axis_CountXY];
UI_Round rounding; UI_Round rounding;
Vec4 background_color; Vec4 background_color;
@ -220,6 +223,22 @@ Struct(UI_Cmd)
UI_AxisAlignment child_alignment[Axis_CountXY]; 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) Struct(UI_CmdNode)
{ {
UI_CmdNode *next; UI_CmdNode *next;
@ -248,7 +267,10 @@ Struct(UI_Box)
u64 count; u64 count;
//- Cmd data //- Cmd data
UI_Cmd cmd; UI_BoxDesc desc;
GPU_Resource *raw_texture;
Vec2 raw_texture_uv0;
Vec2 raw_texture_uv1;
//- Pre-layout data //- Pre-layout data
u64 pre_index; u64 pre_index;
@ -333,6 +355,7 @@ Struct(UI_State)
UI_Key active_box; UI_Key active_box;
/* Cmds */ /* Cmds */
Vec4 swapchain_color;
UI_FrameFlag frame_flags; UI_FrameFlag frame_flags;
UI_CmdNode *first_cmd_node; UI_CmdNode *first_cmd_node;
UI_CmdNode *last_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); UI_Key UI_BuildBoxEx(UI_Key key);
#define UI_BuildBox() UI_BuildBoxEx(UI_TransKey()) #define UI_BuildBox() UI_BuildBoxEx(UI_TransKey())
void UI_SetRawTexture(UI_Key key, GPU_Resource *texture, Vec2 uv0, Vec2 uv1);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Report //~ Report
@ -457,7 +482,7 @@ UI_Report UI_ReportFromKey(UI_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Begin frame //~ Begin frame
UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags); UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Frame helpers //~ Frame helpers