bullet trail testing

This commit is contained in:
jacob 2026-01-07 04:34:53 -06:00
parent 5bbf007fec
commit 3dc22b9bd7
7 changed files with 186 additions and 38 deletions

View File

@ -513,9 +513,12 @@
#if IsLanguageC #if IsLanguageC
#define Inf INFINITY #define Inf INFINITY
#define Nan NAN #define Nan NAN
#elif IsLanguageG
#define Inf (1.0 / 0.0)
#define Nan (0.0 / 0.0)
#endif
#define IsInf(x) isinf(x) #define IsInf(x) isinf(x)
#define IsNan(x) isnan(x) #define IsNan(x) isnan(x)
#endif
//- u128 //- u128
#if IsLanguageC #if IsLanguageC

View File

@ -210,7 +210,6 @@ Rng2 S_BoundingBoxFromShape(S_Shape shape)
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Collision //~ Collision
@ -1078,6 +1077,7 @@ void S_TickForever(WaveLaneCtx *lane)
ResetArena(world_arena); ResetArena(world_arena);
world = PushStruct(world_arena, S_World); world = PushStruct(world_arena, S_World);
world->seed = tr.unpacked->seed;
world->tick = tr.unpacked->tick; world->tick = tr.unpacked->tick;
world->time_ns = tr.unpacked->time_ns; world->time_ns = tr.unpacked->time_ns;
@ -1399,8 +1399,40 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Check for bullet collisions //- Spawn test bullet
// TODO: Remove this
// {
// b32 bullet_spawned = 0;
// for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
// {
// if (ent->is_bullet)
// {
// bullet_spawned = 1;
// break;
// }
// }
// if (!bullet_spawned)
// {
// }
// }
//////////////////////////////
//- Update bullets
@ -1571,6 +1603,7 @@ void S_TickForever(WaveLaneCtx *lane)
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
++output->snapshots_count; ++output->snapshots_count;
snapshot->seed = world->seed;
snapshot->tick = world->tick; snapshot->tick = world->tick;
snapshot->time_ns = world->time_ns; snapshot->time_ns = world->time_ns;

View File

@ -74,6 +74,10 @@ Struct(S_Ent)
b32 has_weapon; b32 has_weapon;
b32 is_bullet;
Vec2 bullet_start;
Vec2 bullet_end;
////////////////////////////// //////////////////////////////
//- Solver data //- Solver data
@ -158,6 +162,7 @@ Struct(S_Constraint)
Struct(S_World) Struct(S_World)
{ {
u64 seed;
i64 tick; i64 tick;
i64 time_ns; i64 time_ns;
@ -197,6 +202,7 @@ Struct(S_DeltaNode)
Struct(S_Snapshot) Struct(S_Snapshot)
{ {
u64 seed;
i64 tick; i64 tick;
i64 time_ns; i64 time_ns;

View File

@ -36,11 +36,13 @@ S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_
if (pack) if (pack)
{ {
BB_WriteUBits(&bw, src_world->seed, 64);
BB_WriteIBits(&bw, src_world->tick, 64); BB_WriteIBits(&bw, src_world->tick, 64);
BB_WriteIBits(&bw, src_world->time_ns, 64); BB_WriteIBits(&bw, src_world->time_ns, 64);
} }
else else
{ {
result.unpacked->seed = BB_ReadUBits(&br, 64);
result.unpacked->tick = BB_ReadIBits(&br, 64); result.unpacked->tick = BB_ReadIBits(&br, 64);
result.unpacked->time_ns = BB_ReadIBits(&br, 64); result.unpacked->time_ns = BB_ReadIBits(&br, 64);
} }
@ -138,6 +140,13 @@ S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_
result.packed = BB_GetWritten(arena, &bw); result.packed = BB_GetWritten(arena, &bw);
BB_ReleaseDynamicBuff(&bb); BB_ReleaseDynamicBuff(&bb);
} }
else
{
if (!result.unpacked->seed)
{
TrueRand(StringFromStruct(&result.unpacked->seed));
}
}
} }
return result; return result;

View File

@ -74,6 +74,7 @@ String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey)
V_Emitter *V_PushEmitter(u32 particle_count) V_Emitter *V_PushEmitter(u32 particle_count)
{ {
particle_count = MinU32(particle_count, Mebi(1));
V_Frame *frame = V_CurrentFrame(); V_Frame *frame = V_CurrentFrame();
V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode); V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode);
SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en); SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en);
@ -619,6 +620,7 @@ void V_TickForever(WaveLaneCtx *lane)
S_Snapshot *snapshot = &n->snapshot; S_Snapshot *snapshot = &n->snapshot;
if (snapshot->tick > world->tick) if (snapshot->tick > world->tick)
{ {
world->seed = snapshot->seed;
world->tick = snapshot->tick; world->tick = snapshot->tick;
world->time_ns = snapshot->time_ns; world->time_ns = snapshot->time_ns;
for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
@ -2192,12 +2194,17 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Width, UI_SHRINK(0, 1));
UI_SetNext(Height, UI_SHRINK(0, 1)); UI_SetNext(Height, UI_SHRINK(0, 1));
UI_PushCP(UI_BuildColumn()); UI_PushCP(UI_BuildColumn());
{
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{
UI_BuildLabelF("World seed: 0x%F", FmtHex(world->seed));
}
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{ {
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
Vec2I32 tile_pos = S_TilePosFromWorldPos(frame->world_cursor); Vec2I32 tile_pos = S_TilePosFromWorldPos(frame->world_cursor);
Vec2 cell_pos = MulXformV2(frame->xf.world_to_cell, frame->world_cursor); Vec2 cell_pos = MulXformV2(frame->xf.world_to_cell, frame->world_cursor);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos); i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
{
UI_BuildLabelF("Camera pos: %F", FmtFloat2(frame->camera_pos)); UI_BuildLabelF("Camera pos: %F", FmtFloat2(frame->camera_pos));
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor)); UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos)); UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos));
@ -2586,11 +2593,96 @@ void V_TickForever(WaveLaneCtx *lane)
} }
UnlockTicketMutex(&S.input_back_tm); UnlockTicketMutex(&S.input_back_tm);
////////////////////////////// //////////////////////////////
//- Process bullets //- Spawn test bullet particles
// TODO: Not like this // TODO: Not like this
{
PERSIST Vec2 start = {5, 5};
PERSIST Vec2 end = {3, -20};
if (frame->held_buttons[Button_G])
{
end = frame->world_cursor;
if (!last_frame->held_buttons[Button_G])
{
start = end;
}
}
Vec2 vel = SubVec2(end, start);
f32 trail_len = Vec2Len(SubVec2(end, start));
f32 particles_count = MaxF32(trail_len * 64, 1);
// f32 angle = AngleFromVec2(PerpVec2(SubVec2(end, start)));
f32 angle = AngleFromVec2(NegVec2(SubVec2(end, start)));
V_Emitter *emitter = V_PushEmitter(particles_count);
emitter->lifetime = 1;
emitter->lifetime_spread = 1;
emitter->angle = angle;
emitter->angle_spread = Tau / 4;
emitter->start = start;
emitter->end = end;
emitter->color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1));
// emitter->speed = 0;
// emitter->speed_spread = 1;
emitter->speed = 1;
emitter->speed_spread = 1;
emitter->velocity_falloff = 0;
emitter->velocity_falloff_spread = 0;
start = end;
end = AddVec2(end, vel);
}
//////////////////////////////
//- Spawn test blood particles
// TODO: Not like this
{ {
for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer)) for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer))
@ -2634,23 +2726,22 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_ParticleFlag flags = 0; V_ParticleFlag flags = 0;
flags |= V_ParticleFlag_StainOnPrune; flags |= V_ParticleFlag_StainOnPrune;
if (TweakBool("Emitter stain trail", 0)) if (TweakBool("Emitter stain trail", 1))
{ {
flags |= V_ParticleFlag_StainTrail; flags |= V_ParticleFlag_StainTrail;
} }
// f32 count = TweakFloat("Emitter count", 50, 0, 10000); // f32 count = TweakFloat("Emitter count", 50, 0, 10000);
f32 count = TweakFloat("Emitter count", 50, 1, 1000); f32 count = TweakFloat("Emitter count", 50, 1, 1000);
f32 speed = TweakFloat("Emitter speed", 10, 0, 100); f32 speed = TweakFloat("Emitter speed", 20, 0, 100);
f32 falloff = TweakFloat("Emitter falloff", 30, 0, 100); f32 falloff = TweakFloat("Emitter falloff", 50, 0, 100);
// f32 angle_spread = TweakFloat("Emitter spread", Tau / 20, 0, Tau); f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau;
f32 angle_spread = TweakFloat("Emitter spread", 0.1, 0, 1) * Tau;
V_Emitter *emitter = V_PushEmitter(count); V_Emitter *emitter = V_PushEmitter(count);
emitter->flags = flags; emitter->flags = flags;
Vec2 dir = victim_raycast.normal; Vec2 dir = victim_raycast.normal;
emitter->pos = victim_raycast.p; emitter->start = victim_raycast.p;
emitter->end = emitter->start;
emitter->speed = speed; emitter->speed = speed;
emitter->speed_spread = speed * 2; emitter->speed_spread = speed * 2;
@ -2696,7 +2787,8 @@ void V_TickForever(WaveLaneCtx *lane)
V_Emitter *emitter = V_PushEmitter(25);; V_Emitter *emitter = V_PushEmitter(25);;
Vec2 dir = frame->look; Vec2 dir = frame->look;
emitter->pos = frame->world_cursor; emitter->start = frame->world_cursor;
emitter->end = emitter->start;
emitter->angle = AngleFromVec2(dir); emitter->angle = AngleFromVec2(dir);
// emitter->count = 100; // emitter->count = 100;

View File

@ -291,34 +291,33 @@ ComputeShader(V_SimParticlesCS, 64)
{ {
V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1]; V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1];
u64 seed = MixU64(emitter.seed + particle.seq); u64 seed0 = MixU64(emitter.seed + particle.seq);
u64 seed1 = MixU64(seed0);
// u32 speed_noise = (u32)((seed >> 0) & 0xFF); f32 rand_speed = (f32)((seed0 >> 0) & 0xFFFF) / (f32)0xFFFF;
// u32 angle_noise = (u32)((seed >> 8) & 0xFF); f32 rand_angle = (f32)((seed0 >> 16) & 0xFFFF) / (f32)0xFFFF;
f32 rand_offset = (f32)((seed0 >> 32) & 0xFFFF) / (f32)0xFFFF;
f32 rand_falloff = (f32)((seed0 >> 48) & 0xFFFF) / (f32)0xFFFF;
// u32 r_noise = (u32)((seed >> 8) & 0xFF); f32 rand_lifetime = (f32)((seed1 >> 0) & 0xFFFF) / (f32)0xFFFF;
// u32 g_noise = (u32)((seed >> 8) & 0xFF);
// u32 b_noise = (u32)((seed >> 8) & 0xFF);
// u32 a_noise = (u32)((seed >> 8) & 0xFF);
// f32 speed_rand = speed_noise / (f32)0xFFFF; f32 speed = emitter.speed + (rand_speed - 0.5) * emitter.speed_spread;
// f32 angle_rand = angle_noise / (f32)0xFFFF; f32 angle = emitter.angle + (rand_angle - 0.5) * emitter.angle_spread;
f32 velocity_falloff = emitter.velocity_falloff + (rand_falloff - 0.5) * emitter.velocity_falloff_spread;
f32 rand_speed = (f32)((seed >> 0) & 0xFFFF) / (f32)0xFFFF - 0.5; f32 lifetime = emitter.lifetime + (rand_lifetime - 0.5) * emitter.lifetime_spread;
f32 rand_angle = (f32)((seed >> 16) & 0xFFFF) / (f32)0xFFFF - 0.5; Vec3 color = emitter.color_lin.rgb + (rand_lifetime - 0.5) * emitter.color_spread;
f32 rand_falloff = (f32)((seed >> 32) & 0xFFFF) / (f32)0xFFFF - 0.5; Vec2 offset = (emitter.end - emitter.start) * rand_offset;
f32 rand_color = (f32)((seed >> 48) & 0xFF) / (f32)0xFF - 0.5;
f32 speed = emitter.speed + rand_speed * emitter.speed_spread;
f32 angle = emitter.angle + rand_angle * emitter.angle_spread;
f32 velocity_falloff = emitter.velocity_falloff + rand_falloff * emitter.velocity_falloff;
Vec3 color = emitter.color_lin.rgb + rand_color * emitter.color_spread;
particle.flags = emitter.flags; particle.flags = emitter.flags;
particle.pos = emitter.pos; particle.pos = emitter.start + offset;
particle.velocity = Vec2(cos(angle), sin(angle)) * speed; particle.velocity = Vec2(cos(angle), sin(angle)) * speed;
particle.velocity_falloff = velocity_falloff; particle.velocity_falloff = velocity_falloff;
particle.color = color; particle.color = color;
particle.lifetime = lifetime;
if (emitter.lifetime == 0)
{
particle.lifetime = Inf;
}
particle.emitter_init_num = 0; particle.emitter_init_num = 0;
} }
@ -327,7 +326,8 @@ ComputeShader(V_SimParticlesCS, 64)
{ {
particle.pos += particle.velocity * params.dt; particle.pos += particle.velocity * params.dt;
particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt); particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt);
if (particle.exists < 0.001 || dot(particle.velocity, particle.velocity) < (0.001 * 0.001)) particle.lifetime -= params.dt;
if (particle.exists < 0.0001 || particle.lifetime < 0.0001 || dot(particle.velocity, particle.velocity) < (0.0001 * 0.0001))
{ {
particle.exists = 0; particle.exists = 0;
} }

View File

@ -99,7 +99,11 @@ Struct(V_Emitter)
u32 count; u32 count;
u64 seed; u64 seed;
Vec2 pos; Vec2 start;
Vec2 end;
f32 lifetime;
f32 lifetime_spread;
f32 speed; f32 speed;
f32 speed_spread; f32 speed_spread;
@ -126,6 +130,7 @@ Struct(V_Particle)
Vec2 velocity; Vec2 velocity;
f32 exists; f32 exists;
f32 lifetime;
f32 velocity_falloff; f32 velocity_falloff;
Vec3 color; Vec3 color;