bullet blend testing

This commit is contained in:
jacob 2026-03-17 16:03:47 -05:00
parent 43b0cede66
commit 08b8f10616
7 changed files with 89 additions and 56 deletions

View File

@ -6,10 +6,6 @@
#define SIM_TICKS_PER_SECOND 64
#define SIM_TICK_INTERVAL_NS (NsFromSeconds(1) / SIM_TICKS_PER_SECOND)
// Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the
// master sim (how far back in time should the client render the server's state)
// #define SIM_CLIENT_INTERP_RATIO 2.0
#define GPU_NAMES IsRtcEnabled
@ -30,4 +26,6 @@
// TODO: Move these to user-configurable settings
#define AUDIO_ENABLED 0
#define FPS_LIMIT 300
// #define FPS_LIMIT 60
#define FPS_LIMIT 0

View File

@ -2556,14 +2556,14 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
G_D12_Resource *resource = G_D12_ResourceFromTextureRef(cmd->barrier.texture);
if (resource)
{
if (cmd->barrier.release)
{
G_D12_UpdateTrackedUsage(scratch.arena, batch, resource, resource->texture_mips, G_D12_TrackedUsageKind_Release, cmd);
}
else
{
G_D12_UpdateTrackedUsage(scratch.arena, batch, resource, resource->texture_mips, G_D12_TrackedUsageKind_Acquire, cmd);
}
G_D12_UpdateTrackedUsage(
scratch.arena,
batch,
resource,
resource->texture_mips,
cmd->barrier.release ? G_D12_TrackedUsageKind_Release : G_D12_TrackedUsageKind_Acquire,
cmd
);
}
}
else
@ -2651,9 +2651,9 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
u64 slotted_constants[G_NumConstants];
u64 bound_compute_constants[G_NumConstants];
u64 bound_graphics_constants[G_NumConstants];
for (i32 i = 0; i < countof(slotted_constants); ++i) { slotted_constants[i] = 0; } // Zero-initialize all slots
for (i32 i = 0; i < countof(bound_compute_constants); ++i) { bound_compute_constants[i] = U64Max; }
for (i32 i = 0; i < countof(bound_graphics_constants); ++i) { bound_graphics_constants[i] = U64Max; }
for (i32 slot = 0; slot < countof(slotted_constants); ++slot) { slotted_constants[slot] = 0; } // Zero-initialize all slots
for (i32 slot = 0; slot < countof(bound_compute_constants); ++slot) { bound_compute_constants[slot] = U64Max; }
for (i32 slot = 0; slot < countof(bound_graphics_constants); ++slot) { bound_graphics_constants[slot] = U64Max; }
// Fill built-in constants
if (!G_IsRefNil(queue->print_buffer))
@ -2675,8 +2675,8 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
u64 bound_render_target_uids[G_MaxRenderTargets] = Zi;
u64 bound_render_clear_target_uid = 0;
// Shader-visible heaps
ID3D12DescriptorHeap *heaps[] = {
// Shader-visible descriptor heaps
ID3D12DescriptorHeap *descriptor_heaps[] = {
G_D12.descriptor_heaps[G_D12_DescriptorHeapKind_CbvSrvUav].d3d_heap,
G_D12.descriptor_heaps[G_D12_DescriptorHeapKind_Sampler].d3d_heap,
};
@ -2898,7 +2898,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
// Set descriptor heaps
if (!descriptor_heaps_set)
{
ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(heaps), heaps);
ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(descriptor_heaps), descriptor_heaps);
descriptor_heaps_set = 1;
}
@ -2961,18 +2961,18 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
{
pipeline_desc.is_wireframe = 1;
}
for (u32 i = 0; i < countof(cmd->draw.render_target_descs); ++i)
for (u32 rt_idx = 0; rt_idx < countof(cmd->draw.render_target_descs); ++rt_idx)
{
G_RenderTargetDesc desc = cmd->draw.render_target_descs[i];
G_RenderTargetDesc desc = cmd->draw.render_target_descs[rt_idx];
G_D12_Resource *rt = G_D12_ResourceFromTextureRef(desc.texture);
if (rt)
{
pipeline_desc.render_target_formats[i] = rt->texture_format;
pipeline_desc.render_target_blend_modes[i] = desc.blend;
pipeline_desc.render_target_formats[rt_idx] = rt->texture_format;
pipeline_desc.render_target_blend_modes[rt_idx] = desc.blend;
}
else
{
pipeline_desc.render_target_formats[i] = G_Format_Unknown;
pipeline_desc.render_target_formats[rt_idx] = G_Format_Unknown;
}
}
pipeline = G_D12_PipelineFromDesc(pipeline_desc);
@ -3009,7 +3009,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
// Set descriptor heaps
if (!descriptor_heaps_set)
{
ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(heaps), heaps);
ID3D12GraphicsCommandList_SetDescriptorHeaps(d3d_cl, countof(descriptor_heaps), descriptor_heaps);
descriptor_heaps_set = 1;
}
@ -3104,18 +3104,18 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
{
b32 om_dirty = 0;
u32 rtvs_count = 0;
for (u32 i = 0; i < countof(cmd->draw.render_target_descs); ++i)
for (u32 rt_idx = 0; rt_idx < countof(cmd->draw.render_target_descs); ++rt_idx)
{
G_RenderTargetDesc desc = cmd->draw.render_target_descs[i];
G_RenderTargetDesc desc = cmd->draw.render_target_descs[rt_idx];
G_D12_Resource *rt = G_D12_ResourceFromTextureRef(desc.texture);
if (rt)
{
Assert(AnyBit(rt->d3d_desc.Flags, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET));
if (bound_render_target_uids[i] != rt->uid + desc.mip)
if (bound_render_target_uids[rt_idx] != rt->uid + desc.mip)
{
G_D12_Descriptor *rtv_descriptor = rcl->rtv_descriptors[i];
G_D12_Descriptor *rtv_descriptor = rcl->rtv_descriptors[rt_idx];
G_D12_InitRtvDescriptor(rtv_descriptor, rt, desc.mip);
bound_render_target_uids[i] = rt->uid + desc.mip;
bound_render_target_uids[rt_idx] = rt->uid + desc.mip;
om_dirty = 1;
}
++rtvs_count;
@ -3128,9 +3128,9 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
if (om_dirty)
{
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[G_MaxRenderTargets] = Zi;
for (u32 i = 0; i < rtvs_count; ++i)
for (u32 rt_idx = 0; rt_idx < rtvs_count; ++rt_idx)
{
rtv_handles[i] = rcl->rtv_descriptors[i]->d3d_handle;
rtv_handles[rt_idx] = rcl->rtv_descriptors[rt_idx]->d3d_handle;
}
ID3D12GraphicsCommandList_OMSetRenderTargets(d3d_cl, rtvs_count, rtv_handles, 0, 0);
}
@ -3805,9 +3805,9 @@ G_BackbufferHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_For
}
// Release backbuffers
for (u32 i = 0; i < countof(swapchain->backbuffers); ++i)
for (u32 backbuffer_idx = 0; backbuffer_idx < countof(swapchain->backbuffers); ++backbuffer_idx)
{
G_D12_Backbuffer *backbuffer = &swapchain->backbuffers[i];
G_D12_Backbuffer *backbuffer = &swapchain->backbuffers[backbuffer_idx];
if (backbuffer->d3d_resource)
{
ID3D12Resource_Release(backbuffer->d3d_resource);

View File

@ -569,6 +569,7 @@ void M_BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &cp.flags_dxc, Lit("-O3"));
PushStringToList(perm, &cp.flags_dxc, Lit("-HV 202x")); // 202x makes numeric literals less weird
PushStringToList(perm, &cp.flags_dxc, Lit("-Ges")); // Strict mode
PushStringToList(perm, &cp.flags_dxc, Lit("-res_may_alias"));
// TODO: Export debug info separately for release builds
PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug"));

View File

@ -1951,11 +1951,8 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
}
dst->created_at_ns = frame->time_ns;
dst->created_at_tick = frame->tick;
dst->sim = !P_tl.is_predicting;
++frame->ents_count;
if (!P_tl.is_predicting)
{
dst->sim = 1;
}
}
}
}
@ -2192,25 +2189,42 @@ void P_StepFrame(P_Frame *frame)
P_Ent *local_player = P_EntFromKey(frame, P_tl.local_player);
P_Ent *local_guy = P_EntFromKey(frame, local_player->guy);
//////////////////////////////
//- Mark simulated ents
if (is_predicting)
{
P_EntKey local_player_key = local_player->key;
P_EntKey local_guy_key = local_guy->key;
P_EntKey local_weapon_key = local_guy->weapon;
// Mark player/guy/weapon ents
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
P_EntKey key = ent->key;
b32 sim = 0;
if (
P_MatchEntKey(key, local_player->key) ||
P_MatchEntKey(key, local_guy->key) ||
P_MatchEntKey(key, local_guy->weapon)
P_MatchEntKey(key, local_player_key) ||
P_MatchEntKey(key, local_guy_key) ||
P_MatchEntKey(key, local_weapon_key)
)
{
sim = 1;
}
ent->sim = sim;
}
// Mark child ents
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
if (!ent->sim)
{
ent->sim = P_EntFromKey(frame, ent->source)->sim;
}
}
}
//////////////////////////////
@ -3055,6 +3069,7 @@ void P_StepFrame(P_Frame *frame)
bullet->source = weapon->key;
bullet->damage_attribution = firer->source;
bullet->sim = weapon->sim;
}
}
weapon->last_fire_ns = frame->time_ns;
@ -3095,6 +3110,7 @@ void P_StepFrame(P_Frame *frame)
f32 spread = Tau * 0.05;
// f32 spread = Tau * 0.01;
// f32 spread = 0;
b32 should_ricochet = 0;
@ -3137,7 +3153,6 @@ void P_StepFrame(P_Frame *frame)
if (is_first_bullet_tick)
{
Vec2 fire_pos = Zi;
Vec2 fire_dir = Zi;
Vec2 fire_base0 = Zi;
@ -3185,9 +3200,9 @@ void P_StepFrame(P_Frame *frame)
wep_pix_to_world_af = MulAffine(ent_to_world_af, wep_pix_to_ent_af);
}
SPR_Ray fire_ray = wep.rays[SPR_RayKind_Ap];
fire_pos = MulAffineVec2(wep_pix_to_world_af, fire_ray.pos);
fire_dir = NormVec2(MulAffineBasisVec2(wep_pix_to_world_af, fire_ray.dir));
SPR_Ray muzzle_ray = wep.rays[SPR_RayKind_Ap];
fire_pos = MulAffineVec2(wep_pix_to_world_af, muzzle_ray.pos);
fire_dir = NormVec2(MulAffineBasisVec2(wep_pix_to_world_af, muzzle_ray.dir));
fire_base0 = MulVec2(PerpVec2(NegVec2(firer->xf.r)), WedgeVec2(firer->xf.r, SubVec2(firer->xf.t, fire_pos)));
fire_base0 = AddVec2(fire_base0, firer->xf.t);
@ -3203,10 +3218,12 @@ void P_StepFrame(P_Frame *frame)
P_DebugDrawPoint(fire_base1, Color_Green);
P_DebugDrawPoint(fire_pos, Color_Red);
bullet->xf.t = fire_pos;
bullet->xf.r = NormVec2(fire_dir);
Vec2 bullet_dir = RotateVec2Angle(fire_dir, spread * (Norm24(MixU64s(bullet->key.v, P_BulletSpreadBasis)) - 0.5));
bullet->v = MulVec2(NormVec2(fire_dir), initial_speed);
bullet->xf.t = fire_pos;
bullet->xf.r = NormVec2(bullet_dir);
bullet->v = MulVec2(NormVec2(bullet_dir), initial_speed);
bullet->v = AddVec2(bullet->v, firer->v);
}
@ -3352,7 +3369,7 @@ void P_StepFrame(P_Frame *frame)
bullet->v = MulVec2(bullet->v, 1.0 - SaturateF32(speed_falloff * sim_dt));
// TODO: Remove this
if (!P_IsEntNil(victim))
if (!is_predicting && !P_IsEntNil(victim))
{
if (damager->is_player)
{
@ -3582,6 +3599,7 @@ void P_StepFrame(P_Frame *frame)
killer->kills += 1;
}
guy->exists = 0;
guy->continuity_gen += 1;
}
}
}

View File

@ -6,7 +6,8 @@
#define P_NilEntKey ((P_EntKey) { 0 })
#define P_NilConstraintKey ((P_EntKey) { 0 })
#define P_WallShapeIDBasis 0x40d501b4cf6d4f0cull
#define P_WallShapeIDBasis 0x40d501b4cf6d4f0cull
#define P_BulletSpreadBasis 0xc3b72fe38ca5a1d6ull
Struct(P_EntKey)
{

View File

@ -555,6 +555,7 @@ void V_TickForever(WaveLaneCtx *lane)
{
shutdown = Atomic32Fetch(&V.shutdown);
P_tl.debug_draw_enabled = TweakBool("Vis debug draw", 0);
i64 begin_time_ns = TimeNs();
//////////////////////////////
//- Begin frame
@ -624,7 +625,7 @@ void V_TickForever(WaveLaneCtx *lane)
if (frame->tick == 1)
{
frame->timeline.show = 1;
// frame->timeline.show = 1;
frame->timeline.locked = 1;
}
@ -1697,7 +1698,10 @@ void V_TickForever(WaveLaneCtx *lane)
// TODO: Extract information that occurred between first & last prediction, like bullet hits etc?
V_PushTimelineMarker(predict_frame->tick, Color_Purple, 1);
// V_PushTimelineMarker(predict_frame->tick, Color_Purple, 1);
V_PushTimelineMarker(CeilF64(frame->predict_tick_accum), Color_White, 1);
V_PushTimelineMarker(frame->predict_tick_accum, Color_Purple, 1);
}
@ -1844,7 +1848,6 @@ void V_TickForever(WaveLaneCtx *lane)
for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
// if (ent->sim)
P_Ent *left = ent;
P_Ent *right = ent;
f32 blend_t = 0;
@ -5381,6 +5384,15 @@ void V_TickForever(WaveLaneCtx *lane)
{
LogInfoF("Time to first frame: %Fs", FmtFloat(SecondsFromNs(TimeNs()), .p = 3));
}
//////////////////////////////
//- Sleep
if (!shutdown && FPS_LIMIT > 0)
{
i64 step_dt_ns = FPS_LIMIT > 0 ? NsFromSeconds(1) / FPS_LIMIT : 0;
PLT_SleepFrame(begin_time_ns, step_dt_ns);
}
}
FetchAddFence(&V.shutdown_complete, 1);

View File

@ -1,3 +1,9 @@
////////////////////////////////////////////////////////////
//~ Constant types
G_DeclConstant(G_BufferRef, UI_GpuConst_Frame, 0);
G_DeclConstant(b32, UI_GpuConst_DebugDraw, 1);
////////////////////////////////////////////////////////////
//~ Rect types
@ -23,9 +29,6 @@ Struct(UI_GpuRect)
////////////////////////////////////////////////////////////
//~ State types
G_DeclConstant(G_BufferRef, UI_GpuConst_Frame, 0);
G_DeclConstant(b32, UI_GpuConst_DebugDraw, 1);
Struct(UI_GpuFrame)
{
f32 anti_aliasing;