ui layer testing
This commit is contained in:
parent
2fdf891d49
commit
b74927602c
@ -287,7 +287,7 @@ Struct(GPU_ResourceDesc)
|
||||
{
|
||||
GPU_Format format;
|
||||
Vec3I32 size;
|
||||
i32 mip_levels;
|
||||
i32 mip_levels; /* Defaults to 1 (unless GPU_ResourceFlag_MaxMipLevels is set) */
|
||||
} texture;
|
||||
struct
|
||||
{
|
||||
|
||||
157
src/meta/meta.c
157
src/meta/meta.c
@ -990,95 +990,98 @@ JobDef(Build, _, __)
|
||||
ret = errors.count > 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Compile
|
||||
|
||||
StepParams params_array[3] = ZI;
|
||||
StepResult results_array[3] = ZI;
|
||||
|
||||
StepParams *program_params = ¶ms_array[0];
|
||||
StepResult *program_result = &results_array[0];
|
||||
program_params->flags |= StepParamsFlag_CompileProgram;
|
||||
program_params->compiler_params = cp;
|
||||
program_params->flattened = flattened;
|
||||
|
||||
StepParams *shader_params = ¶ms_array[1];
|
||||
StepResult *shader_result = &results_array[1];
|
||||
shader_params->flags |= StepParamsFlag_CompileShaders;
|
||||
shader_params->compiler_params = cp;
|
||||
shader_params->flattened = flattened;
|
||||
|
||||
StepParams *resource_params = ¶ms_array[2];
|
||||
StepResult *resource_result = &results_array[2];
|
||||
resource_params->flags |= StepParamsFlag_CompileEmbeddedDirs;
|
||||
resource_params->compiler_params = cp;
|
||||
resource_params->flattened = flattened;
|
||||
|
||||
u32 job_count = 0; Fence job_fence = ZI;
|
||||
job_count += RunJob(Step, .count = countof(params_array), .fence = &job_fence, .sig.params = params_array, .sig.results = results_array);
|
||||
YieldOnFence(&job_fence, job_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Process compile step results
|
||||
|
||||
/* Copy meta errors */
|
||||
for (M_Error *e = program_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg);
|
||||
for (M_Error *e = shader_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg);
|
||||
for (M_Error *e = resource_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg);
|
||||
|
||||
ret = (ret != 0) ? ret : program_result->return_code;
|
||||
ret = (ret != 0) ? ret : shader_result->return_code;
|
||||
ret = (ret != 0) ? ret : resource_result->return_code;
|
||||
ret = (ret != 0) ? ret : errors.count > 0;
|
||||
//~ Compile & link
|
||||
|
||||
if (errors.count == 0)
|
||||
{
|
||||
String program_output = StringFromList(arena, program_result->output_lines, Lit("\n"));
|
||||
String shader_output = StringFromList(arena, shader_result->output_lines, Lit("\n"));
|
||||
String resource_output = StringFromList(arena, resource_result->output_lines, Lit("\n"));
|
||||
//- Compile
|
||||
StepParams params_array[3] = ZI;
|
||||
StepResult results_array[3] = ZI;
|
||||
|
||||
EchoLine(StringF(arena, ">>>>> Built C in %Fs", FmtFloat(SecondsFromNs(program_result->elapsed_ns))));
|
||||
if (program_output.len > 0) EchoLine(program_output);
|
||||
StepParams *program_params = ¶ms_array[0];
|
||||
StepResult *program_result = &results_array[0];
|
||||
program_params->flags |= StepParamsFlag_CompileProgram;
|
||||
program_params->compiler_params = cp;
|
||||
program_params->flattened = flattened;
|
||||
|
||||
EchoLine(StringF(arena, ">>>>> Built shaders in %Fs", FmtFloat(SecondsFromNs(shader_result->elapsed_ns))));
|
||||
if (shader_output.len > 0) EchoLine(shader_output);
|
||||
StepParams *shader_params = ¶ms_array[1];
|
||||
StepResult *shader_result = &results_array[1];
|
||||
shader_params->flags |= StepParamsFlag_CompileShaders;
|
||||
shader_params->compiler_params = cp;
|
||||
shader_params->flattened = flattened;
|
||||
|
||||
EchoLine(StringF(arena, ">>>>> Built resources in %Fs", FmtFloat(SecondsFromNs(resource_result->elapsed_ns))));
|
||||
if (resource_output.len > 0) EchoLine(resource_output);
|
||||
}
|
||||
StepParams *resource_params = ¶ms_array[2];
|
||||
StepResult *resource_result = &results_array[2];
|
||||
resource_params->flags |= StepParamsFlag_CompileEmbeddedDirs;
|
||||
resource_params->compiler_params = cp;
|
||||
resource_params->flattened = flattened;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Link
|
||||
u32 job_count = 0; Fence job_fence = ZI;
|
||||
job_count += RunJob(Step, .count = countof(params_array), .fence = &job_fence, .sig.params = params_array, .sig.results = results_array);
|
||||
YieldOnFence(&job_fence, job_count);
|
||||
|
||||
String exe_file = Lit("pp.exe");
|
||||
i64 link_elapsed_ns = 0;
|
||||
if (ret == 0)
|
||||
{
|
||||
i64 start_ns = TimeNs();
|
||||
String program_obj_files_str = StringFromList(arena, program_result->obj_files, Lit(" "));
|
||||
String shader_obj_files_str = StringFromList(arena, shader_result->obj_files, Lit(" "));
|
||||
String resource_obj_files_str = StringFromList(arena, resource_result->obj_files, Lit(" "));
|
||||
//- Process compile step results
|
||||
|
||||
/* Copy meta errors */
|
||||
for (M_Error *e = program_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg);
|
||||
for (M_Error *e = shader_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg);
|
||||
for (M_Error *e = resource_result->meta_errors.first; e; e = e->next) M_PushError(arena, &errors, e->token, e->msg);
|
||||
|
||||
ret = (ret != 0) ? ret : program_result->return_code;
|
||||
ret = (ret != 0) ? ret : shader_result->return_code;
|
||||
ret = (ret != 0) ? ret : resource_result->return_code;
|
||||
ret = (ret != 0) ? ret : errors.count > 0;
|
||||
|
||||
String cmd = StringF(arena,
|
||||
"cmd /c link.exe %F %F %F /OUT:%F %F %F",
|
||||
FmtString(program_obj_files_str),
|
||||
FmtString(shader_obj_files_str),
|
||||
FmtString(resource_obj_files_str),
|
||||
FmtString(exe_file),
|
||||
FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))),
|
||||
FmtString(StringFromList(arena, cp.linker_only_flags_msvc, Lit(" "))));
|
||||
OS_CommandResult result = OS_RunCommand(arena, cmd);
|
||||
String output = TrimWhitespace(result.output);
|
||||
if (output.len > 0)
|
||||
{
|
||||
EchoLine(output);
|
||||
String program_output = StringFromList(arena, program_result->output_lines, Lit("\n"));
|
||||
String shader_output = StringFromList(arena, shader_result->output_lines, Lit("\n"));
|
||||
String resource_output = StringFromList(arena, resource_result->output_lines, Lit("\n"));
|
||||
|
||||
EchoLine(StringF(arena, ">>>>> Built C in %Fs", FmtFloat(SecondsFromNs(program_result->elapsed_ns))));
|
||||
if (program_output.len > 0) EchoLine(program_output);
|
||||
|
||||
EchoLine(StringF(arena, ">>>>> Built shaders in %Fs", FmtFloat(SecondsFromNs(shader_result->elapsed_ns))));
|
||||
if (shader_output.len > 0) EchoLine(shader_output);
|
||||
|
||||
EchoLine(StringF(arena, ">>>>> Built resources in %Fs", FmtFloat(SecondsFromNs(resource_result->elapsed_ns))));
|
||||
if (resource_output.len > 0) EchoLine(resource_output);
|
||||
}
|
||||
|
||||
//- Link
|
||||
|
||||
String exe_file = Lit("pp.exe");
|
||||
i64 link_elapsed_ns = 0;
|
||||
if (ret == 0)
|
||||
{
|
||||
i64 start_ns = TimeNs();
|
||||
String program_obj_files_str = StringFromList(arena, program_result->obj_files, Lit(" "));
|
||||
String shader_obj_files_str = StringFromList(arena, shader_result->obj_files, Lit(" "));
|
||||
String resource_obj_files_str = StringFromList(arena, resource_result->obj_files, Lit(" "));
|
||||
|
||||
String cmd = StringF(arena,
|
||||
"cmd /c link.exe %F %F %F /OUT:%F %F %F",
|
||||
FmtString(program_obj_files_str),
|
||||
FmtString(shader_obj_files_str),
|
||||
FmtString(resource_obj_files_str),
|
||||
FmtString(exe_file),
|
||||
FmtString(StringFromList(arena, cp.flags_msvc, Lit(" "))),
|
||||
FmtString(StringFromList(arena, cp.linker_only_flags_msvc, Lit(" "))));
|
||||
OS_CommandResult result = OS_RunCommand(arena, cmd);
|
||||
String output = TrimWhitespace(result.output);
|
||||
if (output.len > 0)
|
||||
{
|
||||
EchoLine(output);
|
||||
}
|
||||
ret = result.code;
|
||||
link_elapsed_ns = TimeNs() - start_ns;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
EchoLine(StringF(arena, ">>>>> Linked in %Fs", FmtFloat(SecondsFromNs(link_elapsed_ns))));
|
||||
}
|
||||
ret = result.code;
|
||||
link_elapsed_ns = TimeNs() - start_ns;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
EchoLine(StringF(arena, ">>>>> Linked in %Fs", FmtFloat(SecondsFromNs(link_elapsed_ns))));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Echo errors
|
||||
|
||||
@ -286,6 +286,11 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
|
||||
{
|
||||
entry->kind = kind_plus_1 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
String err = StringF(arena, "Unexpected token \"%F\"", FmtString(entry_token->s));
|
||||
M_PushError(arena, &layer->errors, entry->name_token, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
token = token->next;
|
||||
|
||||
26
src/pp/pp.c
26
src/pp/pp.c
@ -495,6 +495,11 @@ void UpdateUser(P_Window *window)
|
||||
g->real_time_ns += g->real_dt_ns;
|
||||
g->screen_size = P_GetWindowSize(window);
|
||||
|
||||
//- Begin UI
|
||||
UI_BeginBuild();
|
||||
UI_Box *pp_root_box = UI_BuildBox(UI_Flag_DrawImage, UI_NilKey);
|
||||
UI_PushParent(pp_root_box);
|
||||
|
||||
//- Pull latest local sim snapshot
|
||||
|
||||
{
|
||||
@ -517,7 +522,7 @@ void UpdateUser(P_Window *window)
|
||||
|
||||
{
|
||||
__profn("Blend snapshots");
|
||||
/* How along are we between sim ticks (0 = start of tick, 1 = end of tick) */
|
||||
/* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */
|
||||
f64 tick_progress = 0;
|
||||
i64 next_tick_expected_ns = g->last_local_to_user_snapshot_published_at_ns + g->average_local_to_user_snapshot_publish_dt_ns;
|
||||
if (next_tick_expected_ns > g->last_local_to_user_snapshot_published_at_ns)
|
||||
@ -2630,12 +2635,12 @@ void UpdateUser(P_Window *window)
|
||||
{
|
||||
DelayReleaseGpuResources_Sig *sig = PushStruct(job->arena, DelayReleaseGpuResources_Sig);
|
||||
job->count = countof(release_resources);
|
||||
job->sig = sig;
|
||||
sig->begin_fence = render_fence;
|
||||
sig->begin_fence_target = g->gpu_render_fence_target;
|
||||
sig->resources = PushStructsNoZero(job->arena, GPU_Resource *, job->count);
|
||||
sig->flags = GPU_ReleaseFlag_Reuse;
|
||||
CopyBytes(sig->resources, release_resources, sizeof(release_resources));
|
||||
job->sig = sig;
|
||||
}
|
||||
CloseJob(job);
|
||||
}
|
||||
@ -2645,12 +2650,21 @@ void UpdateUser(P_Window *window)
|
||||
ResetArena(g->ui_shape_indices_arena);
|
||||
ResetArena(g->grids_arena);
|
||||
}
|
||||
|
||||
Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0));
|
||||
Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y));
|
||||
g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC);
|
||||
}
|
||||
|
||||
/* Render UI */
|
||||
UI_PopParent();
|
||||
UI_SetDisplayImage(pp_root_box, g->ui_target);
|
||||
GPU_Resource *ui_render = UI_EndBuild();
|
||||
|
||||
////////////////////////////////
|
||||
//~ Present
|
||||
|
||||
Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0));
|
||||
Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y));
|
||||
g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, ui_render, g->screen_size, backbuffer_dst, VSYNC);
|
||||
// g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC);
|
||||
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
|
||||
@ -42,14 +42,14 @@ MaterialPS_Input VSDef(MaterialVS, Semantic(u32, sv_instanceid), Semantic(u32, s
|
||||
|
||||
Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy;
|
||||
|
||||
MaterialPS_Input output;
|
||||
output.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||
output.tex = instance.tex;
|
||||
output.grid_id = instance.grid_id;
|
||||
output.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
|
||||
output.tint_lin = LinearFromSrgbU32(instance.tint_srgb);
|
||||
output.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light));
|
||||
return output;
|
||||
MaterialPS_Input result;
|
||||
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||
result.tex = instance.tex;
|
||||
result.grid_id = instance.grid_id;
|
||||
result.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
|
||||
result.tint_lin = LinearFromSrgbU32(instance.tint_srgb);
|
||||
result.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light));
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Pixel shader
|
||||
@ -58,7 +58,7 @@ MaterialPS_Output PSDef(MaterialPS, MaterialPS_Input input)
|
||||
{
|
||||
ConstantBuffer<MaterialSig> sig = mat_sig;
|
||||
|
||||
MaterialPS_Output output;
|
||||
MaterialPS_Output result;
|
||||
Vec4 albedo = input.tint_lin;
|
||||
|
||||
/* Texture */
|
||||
@ -116,10 +116,10 @@ MaterialPS_Output PSDef(MaterialPS, MaterialPS_Input input)
|
||||
|
||||
Vec4 emittance = input.emittance_lin * albedo.a;
|
||||
|
||||
output.sv_target0 = albedo;
|
||||
output.sv_target1 = emittance;
|
||||
result.sv_target0 = albedo;
|
||||
result.sv_target1 = emittance;
|
||||
|
||||
return output;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@ -330,10 +330,10 @@ UiBlitPS_Input VSDef(UiBlitVS, Semantic(u32, sv_vertexid))
|
||||
};
|
||||
Vec2 vert = unit_quad_verts[sv_vertexid];
|
||||
|
||||
UiBlitPS_Input output;
|
||||
output.sv_position = mul(sig.projection, Vec4(vert, 0, 1));
|
||||
output.uv = vert + 0.5;
|
||||
return output;
|
||||
UiBlitPS_Input result;
|
||||
result.sv_position = mul(sig.projection, Vec4(vert, 0, 1));
|
||||
result.uv = vert + 0.5;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Pixel shader
|
||||
@ -343,7 +343,7 @@ UiBlitPS_Output PSDef(UiBlitPS, UiBlitPS_Input input)
|
||||
ConstantBuffer<UiBlitSig> sig = ui_blit_sig;
|
||||
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
||||
|
||||
UiBlitPS_Output output;
|
||||
UiBlitPS_Output result;
|
||||
Texture2D<Vec4> tex = UniformResourceFromRid(sig.src);
|
||||
Vec4 color = tex.Sample(sampler, input.uv);
|
||||
|
||||
@ -361,8 +361,8 @@ UiBlitPS_Output PSDef(UiBlitPS, UiBlitPS_Input input)
|
||||
color = pow(abs(color), 1/sig.gamma);
|
||||
}
|
||||
|
||||
output.sv_target = color;
|
||||
return output;
|
||||
result.sv_target = color;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@ -398,12 +398,12 @@ UiRectPS_Input VSDef(UiRectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_ve
|
||||
Vec2 vert = unit_quad_verts[sv_vertexid];
|
||||
Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy;
|
||||
|
||||
UiRectPS_Input output;
|
||||
output.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||
output.tex = instance.tex;
|
||||
output.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
|
||||
output.tint_srgb = Vec4NormFromU32(instance.tint_srgb);
|
||||
return output;
|
||||
UiRectPS_Input result;
|
||||
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||
result.tex = instance.tex;
|
||||
result.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
|
||||
result.tint_srgb = Vec4NormFromU32(instance.tint_srgb);
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Pixel shader
|
||||
@ -411,7 +411,7 @@ UiRectPS_Input VSDef(UiRectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_ve
|
||||
UiRectPS_Output PSDef(UiRectPS, UiRectPS_Input input)
|
||||
{
|
||||
ConstantBuffer<UiRectSig> sig = ui_rect_sig;
|
||||
UiRectPS_Output output;
|
||||
UiRectPS_Output result;
|
||||
Vec4 color = input.tint_srgb;
|
||||
|
||||
/* Texture */
|
||||
@ -422,8 +422,8 @@ UiRectPS_Output PSDef(UiRectPS, UiRectPS_Input input)
|
||||
color *= tex.Sample(sampler, input.uv);
|
||||
}
|
||||
|
||||
output.sv_target0 = color;
|
||||
return output;
|
||||
result.sv_target0 = color;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@ -447,17 +447,17 @@ UiShapePS_Input VSDef(UiShapeVS, Semantic(u32, sv_vertexid))
|
||||
ConstantBuffer<UiShapeSig> sig = ui_shape_sig;
|
||||
StructuredBuffer<UiShapeVert> verts = UniformResourceFromRid(sig.verts);
|
||||
UiShapeVert vert = verts[sv_vertexid];
|
||||
UiShapePS_Input output;
|
||||
output.sv_position = mul(sig.projection, Vec4(vert.pos.xy, 0, 1));
|
||||
output.color_srgb = Vec4NormFromU32(vert.color_srgb);
|
||||
return output;
|
||||
UiShapePS_Input result;
|
||||
result.sv_position = mul(sig.projection, Vec4(vert.pos.xy, 0, 1));
|
||||
result.color_srgb = Vec4NormFromU32(vert.color_srgb);
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Pixel shader
|
||||
|
||||
UiShapePS_Output PSDef(UiShapePS, UiShapePS_Input input)
|
||||
{
|
||||
UiShapePS_Output output;
|
||||
output.sv_target = input.color_srgb;
|
||||
return output;
|
||||
UiShapePS_Output result;
|
||||
result.sv_target = input.color_srgb;
|
||||
return result;
|
||||
}
|
||||
|
||||
238
src/ui/ui.c
238
src/ui/ui.c
@ -8,14 +8,11 @@ UI_FiberState *UI_GetFiberState(void)
|
||||
UI_FiberState *f = UI_shared_state.fiber_states[FiberId()];
|
||||
if (!f)
|
||||
{
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
PushAlign(perm, CachelineSize);
|
||||
f = PushStruct(perm, UI_FiberState);
|
||||
UI_shared_state.fiber_states[FiberId()] = f;
|
||||
PushAlign(perm, CachelineSize);
|
||||
}
|
||||
f->build_arena = AcquireArena(Gibi(64));
|
||||
Arena *perm = PermArena();
|
||||
PushAlign(perm, CachelineSize);
|
||||
f = PushStruct(perm, UI_FiberState);
|
||||
UI_shared_state.fiber_states[FiberId()] = f;
|
||||
PushAlign(perm, CachelineSize);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
@ -23,26 +20,84 @@ UI_FiberState *UI_GetFiberState(void)
|
||||
////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
UI_Key UI_KeyFromString(String str)
|
||||
UI_Key UI_KeyFromString(u64 seed, String str)
|
||||
{
|
||||
UI_Key key = ZI;
|
||||
key.hash = HashFnv64(Fnv64Basis, str);
|
||||
return key;
|
||||
/* TOIMPL */
|
||||
if (seed == 0)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
seed = RandU64FromSeeds(f->top_parent->box->key.hash, f->top_tag->hash);
|
||||
}
|
||||
UI_Key result = ZI;
|
||||
result.hash = HashFnv64(seed, str);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Stack helpers
|
||||
|
||||
//- Tag
|
||||
|
||||
void UI_PushTagFromHash(u64 hash)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
if (f->top_tag)
|
||||
{
|
||||
hash = RandU64FromSeeds(hash, f->top_tag->hash);
|
||||
}
|
||||
UI_Tag *tag = PushStruct(f->build_arena, UI_Tag);
|
||||
StackPush(f->top_tag, tag);
|
||||
tag->hash = hash;
|
||||
}
|
||||
|
||||
void UI_PushTagFromString(String str)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
u64 hash = Fnv64Basis;
|
||||
if (f->top_tag)
|
||||
{
|
||||
hash = f->top_tag->hash;
|
||||
}
|
||||
hash = HashFnv64(hash, str);
|
||||
UI_Tag *tag = PushStruct(f->build_arena, UI_Tag);
|
||||
StackPush(f->top_tag, tag);
|
||||
tag->hash = hash;
|
||||
}
|
||||
|
||||
void UI_PushTagF_(char *fmt_cstr, ...)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
String str = ZI;
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt_cstr);
|
||||
str = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), va);
|
||||
va_end(va);
|
||||
}
|
||||
UI_PushTagFromString(str);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
void UI_PopTag(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
StackPop(f->top_tag);
|
||||
}
|
||||
|
||||
//- Parent
|
||||
|
||||
void UI_PushParent(UI_Box *box)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_Parent *parent = PushStruct(f->build_arena, UI_Parent);
|
||||
parent->box = box;
|
||||
StackPush(f->top_parent, parent);
|
||||
}
|
||||
|
||||
UI_Box *UI_PopParent(void)
|
||||
void UI_PopParent(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_Box *box = 0;
|
||||
return box;
|
||||
StackPop(f->top_parent);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@ -50,39 +105,142 @@ UI_Box *UI_PopParent(void)
|
||||
|
||||
UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
|
||||
{
|
||||
UI_Box *box = 0;
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_BoxBin *bin = &f->box_bins[key.hash % UI_NumBoxLookupBins];
|
||||
UI_BoxBin *back_bin = &f->back_box_bins[key.hash % UI_NumBoxLookupBins];
|
||||
|
||||
UI_Box *box = PushStruct(f->build_arena, UI_Box);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||
}
|
||||
|
||||
/* Find previous build's box from hash */
|
||||
UI_Box *back_box = 0;
|
||||
if (key.hash != 0)
|
||||
{
|
||||
for (UI_Box *tmp = back_bin->first; tmp; tmp = tmp->next_in_bin)
|
||||
{
|
||||
if (tmp->key.hash == key.hash)
|
||||
{
|
||||
back_box = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (back_box)
|
||||
{
|
||||
*box = *back_box;
|
||||
}
|
||||
|
||||
box->key = key;
|
||||
box->flags = flags;
|
||||
box->parent = f->top_parent->box;
|
||||
DllPushBack(f->top_parent->box->first, f->top_parent->box->last, box);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Text
|
||||
|
||||
String UI_DisplayTextFromString(String str)
|
||||
{
|
||||
/* Cap string at non-display pattern (e.g. "Hello##hiddentext" becomes "Hello") */
|
||||
u64 new_len = str.len;
|
||||
if (str.len > 0)
|
||||
{
|
||||
b32 escaped = 0;
|
||||
for (u64 i = 0; i < str.len - 1 && new_len == str.len; ++i)
|
||||
{
|
||||
u8 c = str.text[i];
|
||||
if (c == '\\')
|
||||
{
|
||||
escaped = !escaped;
|
||||
}
|
||||
else if (!escaped && c == '#' && str.text[i + 1] == '#')
|
||||
{
|
||||
new_len = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return STRING(new_len, str.text);
|
||||
}
|
||||
|
||||
void UI_SetDisplayText(UI_Box *box, String str)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
String text = PushString(f->build_arena, UI_DisplayTextFromString(str));
|
||||
String text = PushString(f->build_arena, str);
|
||||
box->display_text = text;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Image
|
||||
|
||||
void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img)
|
||||
{
|
||||
box->display_image = img;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Begin build
|
||||
|
||||
void UI_BeginBuild(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
|
||||
/* Swap front & back build states */
|
||||
{
|
||||
Arena *swp = f->build_arena;
|
||||
f->build_arena = f->back_build_arena;
|
||||
f->back_build_arena = swp;
|
||||
}
|
||||
f->back_box_bins = f->box_bins;
|
||||
f->back_root_box = f->root_box;
|
||||
|
||||
/* Reset front build state */
|
||||
if (!f->build_arena)
|
||||
{
|
||||
f->build_arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
ResetArena(f->build_arena);
|
||||
|
||||
/* Init bins */
|
||||
f->box_bins = PushStructs(f->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
|
||||
|
||||
/* Init root box */
|
||||
f->root_box = PushStruct(f->build_arena, UI_Box);
|
||||
f->root_box->key = UI_RootKey;
|
||||
UI_BoxBin *bin = &f->box_bins[f->root_box->key.hash % UI_NumBoxLookupBins];
|
||||
DllPushBackNP(bin->first, bin->last, f->root_box, next_in_bin, prev_in_bin);
|
||||
|
||||
/* Init stacks */
|
||||
UI_PushTagF("root");
|
||||
UI_PushParent(f->root_box);
|
||||
|
||||
if (!f->back_build_arena)
|
||||
{
|
||||
/* Back buffer not initialized, swap again */
|
||||
UI_BeginBuild();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ End build
|
||||
|
||||
GPU_Resource *UI_EndBuild(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
|
||||
/* TODO: Ensure root is parent */
|
||||
|
||||
GPU_QueueKind render_queue = GPU_QueueKind_Direct;
|
||||
Fence *render_fence = GPU_FenceFromQueue(render_queue);
|
||||
|
||||
/* TODO: Real size */
|
||||
Vec2I32 root_size = VEC2I32(500, 500);
|
||||
|
||||
/* Acquire render target */
|
||||
if (f->render_target && !EqVec2I32(root_size, GPU_GetTextureSize2D(f->render_target)))
|
||||
{
|
||||
YieldOnFence(render_fence, f->render_fence_target);
|
||||
GPU_ReleaseResource(f->render_target, GPU_ReleaseFlag_None);
|
||||
f->render_target = 0;
|
||||
}
|
||||
if (!f->render_target)
|
||||
{
|
||||
GPU_ResourceDesc desc = ZI;
|
||||
desc.kind = GPU_ResourceKind_Texture2D;
|
||||
desc.flags = GPU_ResourceFlag_Renderable;
|
||||
desc.texture.format = GPU_Format_R8G8B8A8_Unorm;
|
||||
desc.texture.size = VEC3I32(root_size.x, root_size.y, 1);
|
||||
f->render_target = GPU_AcquireResource(desc);
|
||||
}
|
||||
|
||||
/* Build command list */
|
||||
GPU_CommandList *cl = GPU_BeginCommandList(render_queue);
|
||||
{
|
||||
|
||||
}
|
||||
f->render_fence_target = GPU_EndCommandList(cl);
|
||||
|
||||
return f->render_target;
|
||||
}
|
||||
|
||||
75
src/ui/ui.h
75
src/ui/ui.h
@ -2,6 +2,7 @@
|
||||
//~ Key types
|
||||
|
||||
#define UI_NilKey ((UI_Key) { 0 })
|
||||
#define UI_RootKey ((UI_Key) { 0xa3deb3749ef35a7aUll })
|
||||
|
||||
Struct(UI_Key)
|
||||
{
|
||||
@ -15,20 +16,63 @@ Enum(UI_Flag)
|
||||
{
|
||||
UI_Flag_None = 0,
|
||||
UI_Flag_DrawText = (1 << 0),
|
||||
UI_Flag_DrawImage = (1 << 1),
|
||||
};
|
||||
|
||||
Struct(UI_Box)
|
||||
{
|
||||
UI_Box *next_in_bin;
|
||||
UI_Box *prev_in_bin;
|
||||
|
||||
UI_Box *parent;
|
||||
UI_Box *first;
|
||||
UI_Box *last;
|
||||
UI_Box *next;
|
||||
UI_Box *prev;
|
||||
|
||||
UI_Key key;
|
||||
UI_Flag flags;
|
||||
|
||||
String display_text;
|
||||
GPU_Resource *display_image;
|
||||
};
|
||||
|
||||
Struct(UI_BoxBin)
|
||||
{
|
||||
UI_Box *first;
|
||||
UI_Box *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Stack types
|
||||
|
||||
Struct(UI_Tag) { UI_Tag *next; u64 hash; };
|
||||
Struct(UI_Parent) { UI_Parent *next; UI_Box *box; };
|
||||
|
||||
////////////////////////////////
|
||||
//~ State types
|
||||
|
||||
#define UI_NumBoxLookupBins 16384
|
||||
|
||||
Struct(UI_FiberState)
|
||||
{
|
||||
//- Build state
|
||||
Arena *build_arena;
|
||||
Arena *back_build_arena;
|
||||
|
||||
UI_BoxBin *box_bins;
|
||||
UI_BoxBin *back_box_bins;
|
||||
|
||||
UI_Box *root_box;
|
||||
UI_Box *back_root_box;
|
||||
|
||||
//- Stack state
|
||||
UI_Tag *top_tag;
|
||||
UI_Parent *top_parent;
|
||||
|
||||
//- Render state
|
||||
GPU_Resource *render_target;
|
||||
i64 render_fence_target;
|
||||
};
|
||||
|
||||
Struct(UI_SharedState)
|
||||
@ -44,25 +88,44 @@ UI_FiberState *UI_GetFiberState(void);
|
||||
////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
UI_Key UI_KeyFromString(String text);
|
||||
UI_Key UI_KeyFromString(u64 seed, String str);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Stack helpers
|
||||
|
||||
//- Tag
|
||||
void UI_PushTagFromHash(u64 hash);
|
||||
void UI_PushTagFromString(String str);
|
||||
#define UI_PushTagF(fmt_cstr, ...) UI_PushTagF_(fmt_cstr, __VA_ARGS__, FmtEnd);
|
||||
void UI_PushTagF_(char *fmt_cstr, ...);
|
||||
void UI_PopTag(void);
|
||||
|
||||
//- Parent
|
||||
void UI_PushParent(UI_Box *box);
|
||||
UI_Box *UI_PopParent(void);
|
||||
void UI_PopParent(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Box
|
||||
|
||||
UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Text
|
||||
|
||||
String UI_DisplayTextFromString(String str);
|
||||
void UI_SetDisplayText(UI_Box *box, String str);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Image
|
||||
|
||||
void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Begin build
|
||||
|
||||
void UI_BeginBuild(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ End build
|
||||
|
||||
GPU_Resource *UI_EndBuild(void);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -6,10 +6,14 @@
|
||||
//- Api
|
||||
@IncludeC ui.h
|
||||
@IncludeC ui_widgets.h
|
||||
@IncludeC ui_draw.h
|
||||
@IncludeGpu ui_draw.h
|
||||
|
||||
//- Impl
|
||||
@IncludeC ui.c
|
||||
@IncludeC ui_widgets.c
|
||||
@IncludeGpu ui_draw.gpu
|
||||
|
||||
//- Startup
|
||||
@startup UI_Startup
|
||||
//- Shaders
|
||||
@VertexShader UI_RectVS
|
||||
@PixelShader UI_RectPS
|
||||
|
||||
49
src/ui/ui_draw.gpu
Normal file
49
src/ui/ui_draw.gpu
Normal file
@ -0,0 +1,49 @@
|
||||
ConstantBuffer<UI_RectSig> UI_rect_sig : register (b0);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Rect
|
||||
|
||||
Struct(UI_RectPS_Input)
|
||||
{
|
||||
Semantic(Vec4, sv_position);
|
||||
};
|
||||
|
||||
Struct(UI_RectPS_Output)
|
||||
{
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
//- Vertex shader
|
||||
|
||||
UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
||||
{
|
||||
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
|
||||
static const Vec2 unit_quad_verts[4] = {
|
||||
Vec2(-0.5f, -0.5f),
|
||||
Vec2(0.5f, -0.5f),
|
||||
Vec2(0.5f, 0.5f),
|
||||
Vec2(-0.5f, 0.5f)
|
||||
};
|
||||
|
||||
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
|
||||
UI_RectInstance instance = instances[sv_instanceid];
|
||||
Vec2 vert = unit_quad_verts[sv_vertexid];
|
||||
// Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy;
|
||||
Vec2 world_pos = 0;
|
||||
|
||||
UI_RectPS_Input result;
|
||||
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Pixel shader
|
||||
|
||||
UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input)
|
||||
{
|
||||
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
|
||||
f32 color = 0;
|
||||
|
||||
UI_RectPS_Output result;
|
||||
result.sv_target0 = color;
|
||||
return result;
|
||||
}
|
||||
23
src/ui/ui_draw.h
Normal file
23
src/ui/ui_draw.h
Normal file
@ -0,0 +1,23 @@
|
||||
////////////////////////////////
|
||||
//~ Rect types
|
||||
|
||||
Struct(UI_RectSig)
|
||||
{
|
||||
/* ----------------------------------------------------- */
|
||||
Mat4x4 projection; /* 16 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
StructuredBufferRid instances; /* 01 consts */
|
||||
u32 _pad0; /* 01 consts (padding) */
|
||||
u32 _pad1; /* 01 consts (padding) */
|
||||
u32 _pad2; /* 01 consts (padding) */
|
||||
/* ----------------------------------------------------- */
|
||||
};
|
||||
AssertRootConst(UI_RectSig, 20);
|
||||
|
||||
Struct(UI_RectInstance)
|
||||
{
|
||||
i32 _;
|
||||
};
|
||||
#define UI_DefaultRectInstance (UI_RectInstance) { \
|
||||
0 \
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
UI_Box *UI_BuildLabel(String text)
|
||||
{
|
||||
UI_Key key = UI_KeyFromString(text);
|
||||
UI_Key key = UI_KeyFromString(0, text);
|
||||
UI_Box *box = UI_BuildBox(UI_Flag_DrawText, key);
|
||||
UI_SetDisplayText(box, text);
|
||||
return box;
|
||||
@ -11,13 +11,15 @@ UI_Box *UI_BuildLabel(String text)
|
||||
|
||||
UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
va_list args;
|
||||
va_start(args, fmt_cstr);
|
||||
String text = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), args);
|
||||
UI_Box *box = UI_BuildLabel(text);
|
||||
va_end(args);
|
||||
String str = ZI;
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt_cstr);
|
||||
str = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), va);
|
||||
va_end(va);
|
||||
}
|
||||
UI_Box *box = UI_BuildLabel(str);
|
||||
EndScratch(scratch);
|
||||
return box;
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
//~ Label widget
|
||||
|
||||
UI_Box *UI_BuildLabel(String text);
|
||||
UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...);
|
||||
#define UI_BuildLabelF(fmt_cstr, ...) UI_BuildLabelF_(fmt_cstr, __VA_ARGS__, FmtEnd)
|
||||
UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Separator widget
|
||||
|
||||
Loading…
Reference in New Issue
Block a user