remove unused layers

This commit is contained in:
jacob 2026-04-06 10:11:28 -05:00
parent fb5aec6bac
commit 179e79f7b7
15 changed files with 495 additions and 3878 deletions

View File

@ -1,459 +0,0 @@
// TODO: Cap max sounds playing.
// Terminology:
//
// `Sample`: Once "PCM" data point representing the smallest unit of audio available for a single channel at a point in time.
// Examples:
// - Single 32 bit float output by mixer and consumed by playback API, that the API interprets as a sound sample for a single channel
// - Single 16 bit integer output by audio file decoder, that may represent a mono sound sample
//
// `Frame`: Represents a single data point of audio for all audio channels at a point in time.
// Examples:
// - Single 16 bit integer output by audio file decoder representing one mono sound sample
// - 2 16 bit integer samples output by audio file decoder representing two sound samples, one sample for each audio channel
// - 2 32 bit float samples output by mixer and consumed by playback API, one sample for each audio channel
MIX_Ctx M = Zi;
////////////////////////////////////////////////////////////
//~ Bootstrap
void MIX_Bootstrap(void)
{
MIX.track_arena = AcquireArena(Gibi(64));
MIX.listener_pos = VEC2(0, 0);
MIX.listener_dir = VEC2(0, -1);
}
////////////////////////////////////////////////////////////
//~ Track
MIX_Handle MIX_HandleFromTrack(MIX_Track *track)
{
MIX_Handle result = Zi;
result.gen = track->gen;
result.data = track;
return result;
}
MIX_Track *MIX_TrackFromHandle(MIX_Handle handle)
{
MIX_Track *track = (MIX_Track *)handle.data;
if (track && track->gen == handle.gen)
{
return track;
}
else
{
return 0;
}
}
MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
{
AssertLockedE(lock, &MIX.mutex);
MIX_Track *track = 0;
if (MIX.track_first_free)
{
// Take from free list
track = MIX.track_first_free;
MIX_Track *next_free = track->next;
MIX.track_first_free = next_free;
if (next_free)
{
next_free->prev = 0;
}
*track = (MIX_Track) { .gen = track->gen + 1 };
}
else
{
// Acquire new
track = PushStruct(MIX.track_arena, MIX_Track);
track->gen = 1;
}
track->sound = sound;
track->mix.source = sound;
track->mix.track_handle = MIX_HandleFromTrack(track);
// Append to playing list
MIX_Track *prev = MIX.track_last_playing;
if (prev)
{
prev->next = track;
}
else
{
MIX.track_first_playing = track;
}
MIX.track_last_playing = track;
track->prev = prev;
++MIX.track_playing_count;
return track;
}
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
{
AssertLockedE(lock, &MIX.mutex);
// Remove from playing list
MIX_Track *prev = track->prev;
MIX_Track *next = track->next;
if (prev)
{
prev->next = next;
}
else
{
// Track was first in list
MIX.track_first_playing = next;
}
if (next)
{
next->prev = prev;
}
else
{
// Track was last in list
MIX.track_last_playing = prev;
}
--MIX.track_playing_count;
++track->gen;
// Add to free list
track->prev = 0;
track->next = MIX.track_first_free;
if (MIX.track_first_free)
{
MIX.track_first_free->prev = track;
}
MIX.track_first_free = track;
}
// TODO: Rework interface to be command based instead of directly modifying tracks.
MIX_Handle MIX_PlaySound(SND_Sound *sound)
{
return MIX_PlaySoundEx(sound, MIX_TRACKDESC());
}
MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc)
{
MIX_Track *track;
{
Lock lock = LockE(&MIX.mutex);
{
track = MIX_AcquireTrackLocked(&lock, sound);
track->desc = desc;
}
Unlock(&lock);
}
return MIX_HandleFromTrack(track);
}
// NOTE: This is quite inefficient.
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
{
MIX_TrackDesc result = Zi;
MIX_Track *track = MIX_TrackFromHandle(handle);
if (track)
{
// TODO: Only lock mutex on track itself or something
Lock lock = LockE(&MIX.mutex);
{
// Confirm handle is still valid now that we're locked
track = MIX_TrackFromHandle(handle);
if (track)
{
result = track->desc;
}
}
Unlock(&lock);
}
return result;
}
// NOTE: This is quite inefficient.
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
{
MIX_Track *track = MIX_TrackFromHandle(handle);
if (track)
{
// TODO: Only lock mutex on track itself or something
Lock lock = LockE(&MIX.mutex);
{
// Confirm handle is still valid now that we're locked
track = MIX_TrackFromHandle(handle);
if (track)
{
track->desc = desc;
}
}
Unlock(&lock);
}
}
void MIX_UpdateListener(Vec2 pos, Vec2 dir)
{
Lock lock = LockE(&MIX.mutex);
{
MIX.listener_pos = pos;
MIX.listener_dir = NormVec2(dir);
}
Unlock(&lock);
}
////////////////////////////////////////////////////////////
//~ Mix
i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap)
{
if (wrap)
{
return sound->samples[sample_pos % sound->samples_count];
}
else if (sample_pos < sound->samples_count)
{
return sound->samples[sample_pos];
}
else
{
return 0;
}
}
// To be called once per audio playback interval
MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
{
TempArena scratch = BeginScratch(arena);
MIX_PcmF32 result = Zi;
result.count = frame_count * 2;
result.samples = PushStructs(arena, f32, result.count);
Vec2 listener_pos = VEC2(0, 0);
Vec2 listener_dir = VEC2(0, 0);
//- Create temp mix array
MIX_MixData **mixes = 0;
u64 mixes_count = 0;
{
Lock lock = LockE(&MIX.mutex);
// Read listener info
listener_pos = MIX.listener_pos;
listener_dir = MIX.listener_dir;
// Update & read mixes
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, MIX.track_playing_count);
for (MIX_Track *track = MIX.track_first_playing; track; track = track->next)
{
MIX_MixData *mix = &track->mix;
mix->desc = track->desc;
mixes[mixes_count++] = mix;
}
Unlock(&lock);
}
//- Process mix data
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index)
{
MIX_MixData *mix = mixes[mix_index];
if (mix->source->samples_count <= 0)
{
// Skip empty sounds
continue;
}
SND_Sound *source = mix->source;
MIX_TrackDesc desc = mix->desc;
MIX_EffectData *effect_data = &mix->effect_data;
b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo;
f32 speed = MaxF32(0, desc.speed);
//- Determine sample range
u64 source_samples_count = 0;
if (source_is_stereo)
{
source_samples_count = frame_count * 2;
// Round <samples_count * speed> to nearest frame boundary (nearest multiple of 2)
source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed);
source_samples_count &= ~1;
}
else
{
source_samples_count = frame_count;
// Round <samples_count * speed> to nearest sample
source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed);
}
u64 source_sample_pos_start = mix->source_pos;
u64 source_sample_pos_end = source_sample_pos_start + source_samples_count;
if (source_sample_pos_end >= source->samples_count)
{
if (desc.looping)
{
source_sample_pos_end = source_sample_pos_end % source->samples_count;
}
else
{
source_sample_pos_end = source->samples_count;
mix->track_finished = 1;
}
}
u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count;
u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start;
mix->source_pos = source_sample_pos_end;
MIX_PcmF32 mix_pcm = {
.count = result.count,
.samples = PushStructs(scratch.arena, f32, result.count)
};
//- Resample
// Transform 16 bit source -> 32 bit stereo at output duration
{
f32 *out_samples = mix_pcm.samples;
u64 out_frames_count = mix_pcm.count / 2;
// TODO: Fast path for 1:1 copy when speed = 1.0?
// TODO: Optimize
if (source_is_stereo)
{
// 16 bit Stereo -> 32 bit Stereo
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
{
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
// Sample source
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f);
f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f);
f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f);
f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
// Lerp
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample1;
out_samples[(out_frame_pos * 2) + 1] += sample2;
}
}
else
{
// 16 bit Mono -> 32 bit Stereo
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
{
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
// Sample source
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f);
f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
// Lerp
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
f32 sample = LerpF32(sample_prev, sample_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample;
out_samples[(out_frame_pos * 2) + 1] += sample;
}
}
}
//- Spatialize
if (desc.flags & MIX_TrackFlag_Spatialize)
{
// Algorithm constants
const f32 rolloff_height = 1.2f;
const f32 rolloff_scale = 6.0f;
const f32 pan_scale = 0.75;
Vec2 pos = desc.pos;
// If sound pos = listener pos, pretend sound is close in front of listener.
if (MatchVec2(listener_pos, pos))
{
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
}
Vec2 sound_rel = SubVec2(pos, listener_pos);
Vec2 sound_rel_dir = NormVec2(sound_rel);
// Compute volume
f32 volume_start = effect_data->spatial_volume;
f32 volume_end;
{
// https://www.desmos.com/calculator/c2h941hobz
// h = `rolloff_height`
// s = `rolloff_scale`
f32 dist = Vec2Len(sound_rel);
f32 v = (dist / rolloff_scale) + 1.0f;
volume_end = rolloff_height * (1.0f / (v * v));
}
effect_data->spatial_volume = volume_end;
// Compute pan
f32 pan_start = effect_data->spatial_pan;
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
effect_data->spatial_pan = pan_end;
// Spatialize samples
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
{
f32 t = (f32)frame_pos / (f32)(frame_count - 1);
f32 volume = LerpF32(volume_start, volume_end, t);
f32 pan = LerpF32(pan_start, pan_end, t);
u64 sample1_index = frame_pos * 2;
u64 sample2_index = sample1_index + 1;
f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume;
mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan);
mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan);
}
}
//- Mix into result
for (u64 i = 0; i < mix_pcm.count; ++i)
{
result.samples[i] += mix_pcm.samples[i] * desc.volume;
}
}
//- Update track effect data
{
Lock lock = LockE(&MIX.mutex);
for (u64 i = 0; i < mixes_count; ++i)
{
MIX_MixData *mix = mixes[i];
MIX_Track *track = MIX_TrackFromHandle(mix->track_handle);
if (track)
{
if (mix->track_finished)
{
// Release finished tracks
MIX_ReleaseTrackLocked(&lock, track);
}
}
}
Unlock(&lock);
}
EndScratch(scratch);
return result;
}

View File

@ -1,120 +0,0 @@
////////////////////////////////////////////////////////////
//~ Track types
Enum(MIX_TrackFlag)
{
MIX_TrackFlag_None = 0,
MIX_TrackFlag_Spatialize = (1 << 0)
};
Struct(MIX_Handle)
{
u64 gen;
void *data;
};
Struct(MIX_TrackDesc)
{
MIX_TrackFlag flags;
f32 volume; // 0 -> 1.0+
f32 speed; // 0 -> 1.0+
b32 looping;
Vec2 pos;
};
#define MIX_TRACKDESC(...) ((MIX_TrackDesc) { \
.flags = 0, \
.volume = 1.0, \
.speed = 1.0, \
.looping = 0, \
.pos = VEC2(0, 0), \
__VA_ARGS__ \
})
////////////////////////////////////////////////////////////
//~ Mix types
// Stereo mix of 32 bit float samples
Struct(MIX_PcmF32)
{
u64 count;
f32 *samples;
};
Struct(MIX_EffectData)
{
// Spatialization
f32 spatial_volume;
f32 spatial_pan;
};
Struct(MIX_MixData)
{
MIX_Handle track_handle;
b32 track_finished;
MIX_TrackDesc desc;
MIX_EffectData effect_data;
SND_Sound *source;
u64 source_pos;
};
Struct(MIX_Track){
u64 gen;
// Controlled via interface
SND_Sound *sound;
MIX_TrackDesc desc;
// Internal
MIX_MixData mix;
MIX_Track *next;
MIX_Track *prev;
};
////////////////////////////////////////////////////////////
//~ State types
Struct(MIX_Ctx)
{
Mutex mutex;
// Listener
Vec2 listener_pos;
Vec2 listener_dir;
// Track list
Arena *track_arena;
MIX_Track *track_first_playing;
MIX_Track *track_last_playing;
u64 track_playing_count;
MIX_Track *track_first_free;
};
extern MIX_Ctx MIX;
////////////////////////////////////////////////////////////
//~ Bootstrap
void MIX_Bootstrap(void);
////////////////////////////////////////////////////////////
//~ Track
MIX_Handle MIX_HandleFromTrack(MIX_Track *track);
MIX_Track *MIX_TrackFromHandle(MIX_Handle handle);
MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound);
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track);
MIX_Handle MIX_PlaySound(SND_Sound *sound);
MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc);
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle);
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc);
void MIX_UpdateListener(Vec2 pos, Vec2 dir);
////////////////////////////////////////////////////////////
//~ Mix
i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap);
MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count);

View File

@ -1,19 +0,0 @@
@Layer mixer
//////////////////////////////
//- Dependencies
@Dep platform
@Dep sound
//////////////////////////////
//- Api
@IncludeC mixer.h
@Bootstrap MIX_Bootstrap
//////////////////////////////
//- Impl
@IncludeC mixer.c

View File

@ -215,28 +215,6 @@ P_Shape P_LocalShapeFromEnt(P_Ent *ent)
.count = 1,
.radius = TweakFloat("Guy radius", 0.25, 0, 1),
);
// f32 guy_width = 0.75;
// f32 guy_height = 0.4;
// result = P_ShapeFromDesc(
// .mass = 10,
// .count = 2,
// .points = { VEC2(0, -guy_width / 2 + (guy_height / 2)), VEC2(0, guy_width / 2 - (guy_height / 2)) },
// .radius = guy_height / 2,
// );
// Rng2 test_rect = Zi;
// test_rect.p0 = VEC2(-1, -1);
// test_rect.p1 = VEC2(1, 1);
// result = P_ShapeFromDesc(
// // .radius = 0.5,
// .radius = 0,
// .count = 4,
// .points[0] = VEC2(test_rect.p0.x, test_rect.p0.y),
// .points[1] = VEC2(test_rect.p1.x, test_rect.p0.y),
// .points[2] = VEC2(test_rect.p1.x, test_rect.p1.y),
// .points[3] = VEC2(test_rect.p0.x, test_rect.p1.y),
// );
}
else if (ent->is_pickup)
{
@ -776,30 +754,6 @@ P_CollisionResult P_CollisionResultFromShapes(P_Shape shape0, P_Shape shape1)
// Insert new point into prototype
proto[closest_b_index] = m;
}
// Debug draw
// {
// P_DebugDrawPoint(simplex.a.p, VEC4(1, 0, 0, 0.5));
// P_DebugDrawPoint(simplex.b.p, VEC4(0, 1, 0, 0.5));
// P_DebugDrawPoint(simplex.c.p, VEC4(0, 0, 1, 0.5));
// P_DebugDrawLine(simplex.a.p, simplex.b.p, Color_Yellow);
// P_DebugDrawLine(simplex.b.p, simplex.c.p, Color_Yellow);
// P_DebugDrawLine(simplex.c.p, simplex.a.p, Color_Yellow);
// if (proto_count > 0)
// {
// for (i64 i = 0; i < proto_count; ++i)
// {
// i64 p1_idx = i + 1;
// if (p1_idx == proto_count)
// {
// p1_idx = 0;
// }
// Vec2 p0 = proto[i].p;
// Vec2 p1 = proto[p1_idx].p;
// P_DebugDrawLine(p0, p1, VEC4(0, 1, 0, 0.5));
// }
// }
// }
}
else
{
@ -1627,9 +1581,6 @@ void P_UniqueSpaceEntriesFromRay(Arena *arena, P_SpaceEntryList *result, i32 spa
t_max.x += step_dir.x > 0;
t_max.y += step_dir.y > 0;
t_max = MulVec2Vec2(t_max, inv_delta);
if (IsInf(inv_delta.x))
{
@ -1640,9 +1591,6 @@ void P_UniqueSpaceEntriesFromRay(Arena *arena, P_SpaceEntryList *result, i32 spa
t_max.y = inv_delta.y;
}
Vec2I32 dda_pos = dda_start;
b32 done = 0;
u32 max_iterations = 512;
@ -1802,7 +1750,6 @@ void P_DebugDrawShape(P_Shape shape, Vec4 srgb)
}
}
void P_DebugDrawFrame(P_Frame *frame)
{
if (P_tl.debug_draw_enabled)
@ -1854,13 +1801,6 @@ void P_DebugDrawFrame(P_Frame *frame)
EndScratch(scratch);
}
for (i32 cell_y = 0; cell_y < world->walls_space.dims.y; ++cell_y)
{
for (i32 cell_x = 0; cell_x < world->walls_space.dims.x; ++cell_x)
{
}
}
//////////////////////////////
//- Draw entities
@ -2521,7 +2461,6 @@ void P_StepFrame(P_Frame *frame)
if (guy->is_guy)
{
// Roll
// if (guy->control.roll_presses && !IsVec2Zero(guy->control.move))
if (guy->control.downs[P_Button_Roll])
{
// TODO: Not like this
@ -2592,7 +2531,6 @@ void P_StepFrame(P_Frame *frame)
b32 is_rolling = P_IsEntRolling(frame, guy);
if (is_rolling)
{
// Vec2 roll_dir = NormVec2(guy->last_roll_dir);
Vec2 roll_dir = NormVec2(guy->xf.r);
move = roll_dir;
@ -2602,7 +2540,6 @@ void P_StepFrame(P_Frame *frame)
move_force *= roll_factor;
max_speed *= roll_factor;
// if ((frame->time_ns - guy->last_roll_ns) > P_RollTurnTimeNs)
{
turn_rate = 0.1;
}
@ -2657,12 +2594,10 @@ void P_StepFrame(P_Frame *frame)
f32 solver_dt = sim_dt / solver_steps_count;
// Solid params
// SoftSpring solid_spring = MakeSpring(TweakFloat("Contact spring hz", 25, 5, 200), TweakFloat("Contact spring damp", 10, 5, 100), solver_dt);
SoftSpring solid_spring = MakeSpring(TweakFloat("Contact spring hz", 100, 5, 200), TweakFloat("Contact spring damp", 10, 5, 100), solver_dt);
f32 solid_pushout_velocity = TweakFloat("Contact spring pushout", 3, 0, 50);
// Gentle params
// f32 gentle_pushout_factor = TweakFloat("Gentle pushout factor", 10, 0, 50);
f32 gentle_pushout_factor = TweakFloat("Gentle pushout factor", 0.5, 0, 50);
//////////////////////////////
@ -3161,23 +3096,6 @@ void P_StepFrame(P_Frame *frame)
//////////////////////////////
//- Spawn bullets
// TODO: Remove this
{
P_EntList bullets_to_spawn = Zi;
for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer))
@ -3242,20 +3160,9 @@ void P_StepFrame(P_Frame *frame)
P_SpawnEntsFromList(frame, bullets_to_spawn);
}
//////////////////////////////
//- Update bullets
{
P_EntList ents_to_spawn = Zi;
for (P_Ent *bullet = P_FirstEnt(frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
@ -3294,18 +3201,7 @@ void P_StepFrame(P_Frame *frame)
}
//////////////////////////////
//- Initialize
// if (bullet->created_at_tick != frame->tick)
// {
// Vec2 start = bullet->bullet_start;
// Vec2 end = bullet->bullet_end;
// Vec2 vel = SubVec2(end, start);
// bullet->bullet_start = end;
// bullet->bullet_end = AddVec2(end, vel);
// bullet->xf.t = bullet->bullet_start;
// bullet->xf.r = NormVec2(vel);
// }
//- Initialize bullet
Struct(BulletPath)
{
@ -3392,13 +3288,6 @@ void P_StepFrame(P_Frame *frame)
// bullet->v = AddVec2(bullet->v, firer->v);
}
// On bullet's first tick, we want to ensure that the firer/weapon
// wasn't obstructed (e.g. to prevent shooting through walls), so we
// insert a path from the bullet's base to its starting position before
@ -3581,185 +3470,6 @@ void P_StepFrame(P_Frame *frame)
P_SpawnEntsFromList(frame, ents_to_spawn);
}
// // TODO: Separate 'hits' from bullets, so that bullets can have multiple hits
// for (P_Ent *bullet = P_FirstEnt(frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
// {
// if (bullet->is_bullet)
// {
// P_Ent *weapon = P_EntFromKey(frame, bullet->source);
// P_Ent *firer = P_EntFromKey(frame, weapon->source);
// P_Ent *damager = P_EntFromKey(frame, bullet->damage_attribution_player);
// if (bullet->created_at_tick != frame->tick)
// {
// Vec2 start = bullet->bullet_start;
// Vec2 end = bullet->bullet_end;
// Vec2 vel = SubVec2(end, start);
// bullet->bullet_start = end;
// bullet->bullet_end = AddVec2(end, vel);
// bullet->xf.t = bullet->bullet_start;
// bullet->xf.r = NormVec2(vel);
// }
// bullet->has_hit = 0;
// Struct(BulletPath)
// {
// BulletPath *next;
// Vec2 start;
// Vec2 end;
// };
// BulletPath *first_bullet_path = 0;
// BulletPath *last_bullet_path = 0;
// if (bullet->created_at_tick == frame->tick)
// {
// // On bullet's first tick, we want to ensure that the firer/weapon
// // wasn't obstructed (e.g. to prevent shooting through walls), so we
// // insert a path from the bullet's base to its starting position before
// // its actual firing path
// {
// // Firer origin -> weapon chamber path
// BulletPath *path = PushStruct(scratch.arena, BulletPath);
// SllQueuePush(first_bullet_path, last_bullet_path, path);
// path->start = bullet->bullet_base0;
// path->end = bullet->bullet_base1;
// }
// {
// // Weapon chamber -> bullet start path
// BulletPath *path = PushStruct(scratch.arena, BulletPath);
// SllQueuePush(first_bullet_path, last_bullet_path, path);
// path->start = bullet->bullet_base1;
// path->end = bullet->bullet_start;
// }
// }
// {
// BulletPath *path = PushStruct(scratch.arena, BulletPath);
// SllQueuePush(first_bullet_path, last_bullet_path, path);
// path->start = bullet->bullet_start;
// path->end = bullet->bullet_end;
// }
// P_EntKey victim_key = Zi;
// P_RaycastResult victim_raycast = Zi;
// b32 hit = 0;
// {
// for (BulletPath *path = first_bullet_path; path && !hit; path = path->next)
// {
// Vec2 path_dir = SubVec2(path->end, path->start);
// P_Space *cast_spaces[] = {
// &world->walls_space,
// &post_solve_ents_space,
// };
// P_SpaceEntryList cast_entries = Zi;
// P_UniqueSpaceEntriesFromRay(
// scratch.arena,
// &cast_entries,
// countof(cast_spaces),
// cast_spaces,
// path->start,
// path->end
// );
// f32 closest_len_sq = Inf;
// for (P_SpaceEntryNode *entry_node = cast_entries.first; entry_node; entry_node = entry_node->next)
// {
// P_SpaceEntry *entry = &entry_node->entry;
// P_EntKey potential_victim_key = (P_EntKey) { .v = entry->shape_id };
// if (!P_MatchEntKey(potential_victim_key, firer->key) || P_IsEntKeyNil(firer->key))
// {
// P_Shape potential_victim_shape = entry->shape;
// P_RaycastResult entrance_raycast = P_RaycastShape(potential_victim_shape, path->start, path_dir);
// Vec2 entrance = entrance_raycast.p;
// if (entrance_raycast.is_intersecting)
// {
// P_RaycastResult exit_raycast = P_RaycastShape(potential_victim_shape, path->start, NegVec2(path_dir));
// Vec2 exit = exit_raycast.p;
// f32 da = DotVec2(path_dir, SubVec2(entrance, path->start));
// f32 db = DotVec2(path_dir, SubVec2(exit, path->start));
// if (db > 0 && (da <= Vec2LenSq(path_dir) || da <= 0))
// {
// f32 len_sq = Vec2LenSq(SubVec2(entrance_raycast.p, path->start));
// if (len_sq < closest_len_sq)
// {
// closest_len_sq = len_sq;
// victim_key = potential_victim_key;
// victim_raycast = entrance_raycast;
// hit = 1;
// }
// }
// }
// }
// }
// }
// }
// P_Ent *victim = P_EntFromKey(frame, victim_key);
// // TODO: Truncate bullet trail
// if (hit)
// {
// bullet->has_hit = 1;
// bullet->hit_entry = victim_raycast.p;
// bullet->hit_entry_normal = victim_raycast.normal;
// // bullet->bullet_end = bullet->hit_entry;
// bullet->exists = 0;
// if (victim->is_guy)
// {
// bullet->hit_material = P_MaterialKind_Flesh;
// }
// else
// {
// bullet->hit_material = P_MaterialKind_Wall;
// }
// }
// // TODO: Remove this
// if (!P_IsEntNil(victim))
// {
// if (damager->is_player)
// {
// victim->damage_attribution_player = damager->key;
// }
// victim->health -= 0.25;
// }
// // Prune out of bounds bullet
// Rng2 bounds = Zi;
// bounds.p0 = VEC2(-P_WorldPitch / 2, -P_WorldPitch / 2);
// bounds.p1 = VEC2(P_WorldPitch / 2, P_WorldPitch / 2);
// if (
// bullet->bullet_start.x < bounds.p0.x || bullet->bullet_start.y < bounds.p0.y ||
// bullet->bullet_start.x > bounds.p1.x || bullet->bullet_start.y > bounds.p1.y
// )
// {
// bullet->exists = 0;
// }
// }
// }
//////////////////////////////
//- Kill guys

View File

@ -237,16 +237,11 @@ Struct(P_NetworkedEntState)
Struct(P_LocalEntState)
{
//- Observation info
//- Observation data
i64 initial_observation_time_ns;
i64 last_observation_time_ns;
b32 is_first_observation;
// Vec2 smoothed_v;
// Vec2 smoothed_v_dir;
// Vec2 smoothed_move_dir;
// f32 smoothed_w;
};
Struct(P_Ent)
@ -401,7 +396,6 @@ Struct(P_Space)
Struct(P_Frame)
{
//////////////////////////////
//- Internal world state
struct P_World *world;
@ -412,14 +406,12 @@ Struct(P_Frame)
P_Frame *next_in_bin;
P_Frame *prev_in_bin;
//////////////////////////////
//- Frame state
i64 src_tick;
i64 tick;
i64 time_ns;
//////////////////////////////
//- Ents
i64 ents_count;
@ -429,7 +421,6 @@ Struct(P_Frame)
i64 ent_bins_count;
P_EntBin *ent_bins;
//////////////////////////////
//- Constraints
i64 constraints_count;
@ -439,7 +430,6 @@ Struct(P_Frame)
i64 constraint_bins_count;
P_ConstraintBin *constraint_bins;
//////////////////////////////
//- Snapshot-assembly state
u64 fragments_count;

View File

@ -69,17 +69,12 @@ void S_TickForever(WaveLaneCtx *lane)
BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb);
// FIXME: Header
Rng user_msg_tick_range = RNG(SIM_TICKS_PER_SECOND * -SIM_MAX_PING, SIM_TICKS_PER_SECOND * SIM_MAX_PING);
P_MsgList queued_user_msgs = Zi;
P_MsgNode *first_free_user_msg_node = 0;
P_NetVarState *nvars = &S.nvars;
//////////////////////////////
//- Sim loop
@ -196,11 +191,6 @@ void S_TickForever(WaveLaneCtx *lane)
}
}
//////////////////////////////
//- Connect clients
@ -277,7 +267,7 @@ void S_TickForever(WaveLaneCtx *lane)
}
//////////////////////////////
//- Create player entities (networked version of clients)
//- Create players
{
P_EntList new_players = Zi;
@ -343,7 +333,6 @@ void S_TickForever(WaveLaneCtx *lane)
//
// In case previous snapshots weren't received, backfill with newest snapshot
//
// TODO: Not like this
i64 max_propagate_count = SIM_TICKS_PER_SECOND;
{
// Propagate backwards
@ -423,13 +412,6 @@ void S_TickForever(WaveLaneCtx *lane)
}
}
//////////////////////////////
//- Apply bot controls
@ -484,133 +466,10 @@ void S_TickForever(WaveLaneCtx *lane)
}
}
// //////////////////////////////
// //- Apply bot controls
// {
// f32 move_bias = TweakFloat("Bot movement bias", 0, -1, 1);
// f32 move_frequency = TweakFloat("Bot movement frequency", 0, 0, 10);
// f32 turn_frequency = TweakFloat("Bot turn frequency", 0, 0, 10);
// // b32 bot_movement_enabled = TweakBool("Bot movement enabled", 1);
// for (P_Ent *bot = P_FirstEnt(world_frame); !P_IsEntNil(bot); bot = P_NextEnt(bot))
// {
// if (bot->is_bot)
// {
// i64 alive_time_ns = world_frame->time_ns - bot->created_at_ns;
// f64 alive_time = SecondsFromNs(alive_time_ns);
// // i64 frequency_ns = NsFromSeconds(0.1);
// // bot->control.move.y = SinF32((f64)alive_time_ns / (f64)frequency_ns);
// f32 move_t = alive_time * move_frequency * Tau;
// f32 look_t = alive_time * turn_frequency * Tau;
// bot->control.move.y = SinF32(move_t);
// bot->control.move.y += move_bias;
// bot->control.look = MulVec2(VEC2(CosF32(look_t), SinF32(look_t)), 3);
// }
// }
// }
//////////////////////////////
//- Process connection messages
// {
// for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// //- Register player
// if (msg->kind == P_MsgKind_RegisterUser)
// {
// P_Key user_key = msg->src_user;
// P_Ent *player = P_EntFromKey(world_frame, user_key);
// if (P_EntIsNil(player))
// {
// P_EntList tmp_list = Zi;
// player = P_PushTempEnt(frame_arena, &tmp_list);
// player->key = user_key;
// player->is_user = 1;
// player->exists = 1;
// // FIXME: Set net key here
// i32 min_name_len = P_MinPlayerNameLen;
// i32 max_name_len = P_MaxPlayerNameLen;
// // De-duplicate player name
// String user_name = msg->data;
// user_name = TrimWhitespace(user_name);
// user_name.len = MinI64(user_name.len, max_name_len);
// user_name = TrimWhitespace(user_name);
// if (user_name.len < min_name_len)
// {
// user_name = Lit("Player");
// }
// {
// String orig_user_name = user_name;
// i64 duplicate_id = 0;
// while (duplicate_id < 1000)
// {
// b32 is_duplicate = 0;
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
// {
// if (ent->is_user && MatchString(P_StringFromEnt(ent), user_name))
// {
// is_duplicate = 1;
// break;
// }
// }
// if (is_duplicate)
// {
// duplicate_id += 1;
// user_name = StringF(frame_arena, "%F (%F)", FmtString(orig_user_name), FmtSint(duplicate_id));
// }
// else
// {
// break;
// }
// }
// }
// P_SetEntString(player, user_name);
// P_Msg *msg = P_PushMsg(
// P_MsgKind_Chat,
// StringF(
// frame_arena,
// "Player %F connected",
// FmtString(user_name)
// ));
// )
// P_SpawnEntsFromList(world_frame, tmp_list);
// }
// {
// P_Msg *msg = P_PushMsg(P_MsgKind_RegisterSuccess, Zstr);
// msg->dst_user = player->key;
// }
// }
// }
// }
//////////////////////////////
//- Process player edit messages
// FIXME: Only accept edits from privileged users
// TODO: Only accept edits from privileged users
{
u64 bots_count = 0;
@ -624,7 +483,7 @@ void S_TickForever(WaveLaneCtx *lane)
//- Save world
case P_MsgKind_SaveWorld:
{
// FIXME: Only accept save from local player
// TODO: Only accept save from local player
should_save = 1;
} break;
//- Reset world
@ -1087,14 +946,6 @@ void S_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- End sim frame
// // Reset front input state
// {
// Arena *arena = input->arena;
// ResetArena(arena);
// ZeroStruct(input);
// input->arena = arena;
// }
i64 frame_end_ns = TimeNs();
//////////////////////////////

View File

@ -15,8 +15,6 @@
//////////////////////////////
//- Resources
@Shader V_BuildProfilerGraphCS (1, 128) // Vertical group dims so that profiler-sample access is uniform
@Shader V_PrepareShadeCS (16, 16)
@Shader V_PrepareCellsCS (16, 16)
@Shader V_BackdropDownCS (16, 16)
@Shader V_BackdropUpCS (16, 16)
@ -25,7 +23,6 @@
@Shader V_QuadPS Pixel
@Shader V_EmitParticlesCS (256)
@Shader V_SimParticlesCS (256)
@Shader V_ShadeCS (16, 16)
@Shader V_CompositeCS (16, 16)
@Shader V_BloomDownCS (16, 16)
@Shader V_BloomUpCS (16, 16)

File diff suppressed because it is too large Load Diff

View File

@ -297,7 +297,6 @@ Struct(V_ZoneTrack)
V_Zone *open_zone;
};
Struct(V_Profiler)
{
b32 is_showing;
@ -469,10 +468,6 @@ Struct(V_Ctx)
V_ZoneTrack *first_zone_track;
V_ZoneTrack *last_zone_track;
P_NetVarState nvars;
V_Panel *root_panel;
@ -484,10 +479,6 @@ Struct(V_Ctx)
P_Control queued_pp_control;
i64 text_input_ns;
i64 connect_try_ns;
@ -506,10 +497,6 @@ Struct(V_Ctx)
Atomic32 shutdown;
Fence shutdown_complete;
Vec2 profiler_graph_dims;
u64 profiler_frame_seq;
V_ProfilerFrame *profiler_frames;
f64 smooth_frame_time_seconds;
i64 cur_frame_tick;

View File

@ -29,33 +29,19 @@ Vec4 V_ColorFromParticleDesc(V_ParticleDesc desc, u32 particle_idx, f32 alive_se
{
if (AnyBit(desc.flags, V_ParticleFlag_GasBlend))
{
// f32 t = saturate(density / 10.0);
// f32 t = smoothstep(-10, 32, density);
f32 t = smoothstep(-10, 50, density);
// f32 t = smoothstep(0, 2, (f32)density);
result.a += (1.0 - result.a) * (t);
}
else if (desc.kind == V_ParticleKind_BloodTrail)
else if (AnyBit(desc.flags, V_ParticleFlag_LiquidBlend))
{
// f32 t = (f32)density / 5;
// t = pow(t, 2);
// t = saturate(t);
// result.rgb *= 1.0 - (t * 0.9);
f32 t = (f32)density / 10;
// t = smoothstep(-10, 10, t);
// t = smoothstep(-5, 5, t);
t = smoothstep(-50, 50, t);
// result.rgb *= 1.0 - (t * 0.9);
// result.a = t;
result.a += (1.0 - result.a) * (t);
}
}
result.rgb = result.rgb + (rand_color - 0.5) * 0.05;
// Apply lifetime fade
if (desc.flags & V_ParticleFlag_FadeLifetime && desc.lifetime_min < Inf && alive_seconds > 0)
{
f32 lifetime = V_LifetimeFromParticleDesc(desc, particle_idx);
@ -63,71 +49,12 @@ Vec4 V_ColorFromParticleDesc(V_ParticleDesc desc, u32 particle_idx, f32 alive_se
f32 v = lifetime_complete * lifetime_complete;
result.a *= 1.0 - v;
}
// if (desc.lifetime < Inf && alive_seconds > 0)
// {
// // result.a *= desc.lifetime / alive_seconds;
// f32 lifetime_complete = alive_seconds / desc.lifetime;
// result.a *= lerp(1, 0, saturate(lifetime_complete));
// // result.a *= 0;
// // result.a *= 1.0 - saturate(alive_seconds / desc.lifetime);
// }
return result;
}
////////////////////////////////////////////////////////////
//~ Build profiler graph
ComputeShader(V_BuildProfilerGraphCS)
{
V_SharedFrame frame = G_Deref(V_GpuReg_Frame, StructuredBuffer<V_SharedFrame>)[0];
RWTexture2D<Vec4> graph = G_Deref(frame.profiler_graph, RWTexture2D<Vec4>);
StructuredBuffer<V_ProfilerFrame> profiler_frames = G_Deref(frame.profiler_frames, StructuredBuffer<V_ProfilerFrame>);
Vec2 graph_dims = frame.profiler_graph_dims;
u32 thread_id = SV_DispatchThreadID.x;
if (thread_id <= frame.profiler_frame_seq && thread_id < graph_dims.x)
{
Vec2 graph_pos = SV_DispatchThreadID + 0.5;
graph_pos.x = graph_dims.x - graph_pos.x;
u64 frame_seq = (frame.profiler_frame_seq - thread_id);
u64 frame_idx = frame_seq % V_ProfilerFramesCap;
V_ProfilerFrame prof_frame = profiler_frames[frame_idx];
Vec4 color = Color_Red;
color.g = Norm24(MixU64(frame_seq));
graph[graph_pos] = color;
}
}
////////////////////////////////////////////////////////////
//~ Prepare frame
//- Prepare shade
ComputeShader(V_PrepareShadeCS)
{
V_SharedFrame frame = G_Deref(V_GpuReg_Frame, StructuredBuffer<V_SharedFrame>)[0];
RWTexture2D<Vec4> shade = G_Deref(frame.shade, RWTexture2D<Vec4>);
Vec2 shade_pos = SV_DispatchThreadID + 0.5;
if (all(shade_pos < G_Count2D(shade)))
{
// Clear shade
shade[shade_pos] = 0;
}
}
//- Prepare cells
ComputeShader(V_PrepareCellsCS)
{
@ -209,7 +136,6 @@ ComputeShader(V_PrepareCellsCS)
}
else
{
// f32 dry_rate = saturate(frame.dt * 0.1);
f32 dry_rate = saturate(frame.dt * 0.2);
Vec4 before_stain = stains[cell_pos];
@ -728,10 +654,6 @@ ComputeShader(V_SimParticlesCS)
}
f32 rand_falloff = Norm16(seed0 >> 48);
// f32 falloff = saturate(lerp(1, 2, rand_falloff) * frame.dt);
// f32 falloff = saturate(lerp(10, 20, rand_falloff * frame.dt));
// f32 falloff = saturate(lerp(5, 10, rand_falloff * frame.dt));
// f32 falloff = 20 * frame.dt;
f32 falloff = V_FalloffFromParticleDesc(desc, particle_idx) * frame.dt;
particle.velocity *= 1.0f - falloff;
@ -752,44 +674,6 @@ ComputeShader(V_SimParticlesCS)
}
}
////////////////////////////////////////////////////////////
//~ Shade
// TODO: Remove this
ComputeShader(V_ShadeCS)
{
V_SharedFrame frame = G_Deref(V_GpuReg_Frame, StructuredBuffer<V_SharedFrame>)[0];
SamplerState sampler = G_Deref(frame.basic_samplers[G_BasicSamplerKind_PointClamp], SamplerState);
Texture2D<P_TileKind> tiles = G_Deref(frame.tiles, Texture2D<P_TileKind>);
Texture2D<Vec4> albedo_tex = G_Deref(frame.albedo, Texture2D<Vec4>);
RWTexture2D<Vec4> shade_tex = G_Deref(frame.shade, RWTexture2D<Vec4>);
Texture2D<f32> drynesses = G_Deref(frame.drynesses, Texture2D<f32>);
Vec2 shade_pos = SV_DispatchThreadID + 0.5;
Vec2 world_pos = mul(frame.af.shade_to_world, Vec3(shade_pos, 1));
Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(world_pos, 1));
Vec2 tile_pos = mul(frame.af.world_to_tile, Vec3(world_pos, 1));
P_TileKind tile = tiles[tile_pos];
Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5;
b32 is_in_world = IsInside(cell_pos, P_WorldCellsDims);
//////////////////////////////
//- Compute result
Vec4 result = 0;
//////////////////////////////
//- Write result
if (all(shade_pos < G_Count2D(shade_tex)))
{
shade_tex[shade_pos] = result;
}
}
////////////////////////////////////////////////////////////
//~ Composite
@ -868,16 +752,6 @@ ComputeShader(V_CompositeCS)
Vec4 world_color = 0;
if (is_in_world)
{
//////////////////////////////
//- Shade color
Vec4 shade_color = 0;
// if (all(shade_pos >= Vec2(0, 0)) && all(shade_pos < countof(shade_tex)))
// {
// Vec2 shade_uv = shade_pos / countof(shade_tex);
// shade_color = shade_tex.SampleLevel(sampler, shade_uv, 0);
// }
//////////////////////////////
//- Tile
@ -934,18 +808,6 @@ ComputeShader(V_CompositeCS)
Vec4 albedo_tex_color = albedo_tex[screen_pos];
//////////////////////////////
//- Particles / stains
@ -997,61 +859,6 @@ ComputeShader(V_CompositeCS)
stain_color *= 0.5;
}
// //////////////////////////////
// //- Particles / stains
// // FIXME: Stain
// Vec4 stain_color = 0;
// {
// Vec4 wet_stain = stains[cell_pos];
// Vec4 dry_stain = dry_stains[cell_pos];
// f32 dryness = drynesses[cell_pos];
// stain_color = max(lerp(wet_stain, dry_stain, dryness), 0);
// }
// Vec4 ground_particle_color = 0;
// Vec4 air_particle_color = 0;
// for (V_ParticleLayer layer = (V_ParticleLayer)0; layer < V_ParticleLayer_COUNT; layer += (V_ParticleLayer)1)
// {
// Texture2D<u32> cells = G_Deref(frame.particle_cells[layer], Texture2D<u32>);
// Texture2D<u32> densities = G_Deref(frame.particle_densities[layer], Texture2D<u32>);
// u32 packed = cells[cell_pos];
// V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F);
// if (particle_kind != V_ParticleKind_None)
// {
// u32 density = densities[cell_pos];
// V_ParticleDesc desc = V_DescFromParticleKind(particle_kind);
// u32 particle_idx = packed & ((1 << 24) - 1);
// Vec4 cell_color = V_ColorFromParticleDesc(desc, particle_idx, density);
// cell_color.rgb *= cell_color.a;
// if (layer == V_ParticleLayer_Ground)
// {
// ground_particle_color = BlendPremul(cell_color, ground_particle_color);
// }
// else
// {
// air_particle_color = BlendPremul(cell_color, air_particle_color);
// }
// }
// }
// // Darken wall particles / stains
// if (tile == P_TileKind_Wall)
// {
// ground_particle_color *= 0.5;
// air_particle_color *= 0.5;
// stain_color *= 0.5;
// }
//////////////////////////////
//- Tile shadow
@ -1083,12 +890,8 @@ ComputeShader(V_CompositeCS)
world_color = BlendPremul(stain_color, world_color); // Blend ground stain
world_color = BlendPremul(ground_particle_color, world_color); // Blend ground particle
// TODO: Blend shadows over tex?
// TODO: Blend shadows over albedo?
world_color = BlendPremul(tile_shadow_color, world_color); // Blend shadow
// if (tile_shadow_color.a != 0)
// {
// world_color.rgb *= 0.5; // Blend shadow
// }
}
world_color = BlendPremul(albedo_tex_color, world_color);
if (tile_is_wall)
@ -1098,26 +901,6 @@ ComputeShader(V_CompositeCS)
world_color = BlendPremul(ground_particle_color, world_color); // Blend wall particle
}
world_color = BlendPremul(air_particle_color, world_color); // Blend air particle
// // world_color = BlendPremul(shade_color, world_color);
// world_color = BlendPremul(stain_particle_color, world_color);
// world_color = BlendPremul(ground_particle_color, world_color);
// if (!tile_is_wall)
// {
// world_color = BlendPremul(tile_color, world_color); // Blend ground tile
// world_color = BlendPremul(stain_particle_color, world_color); // Blend ground stain
// world_color = BlendPremul(ground_particle_color, world_color); // Blend ground particle
// }
// world_color = BlendPremul(albedo_tex_color, world_color);
// if (tile_is_wall)
// {
// world_color = BlendPremul(tile_color, world_color); // Blend wall tile
// world_color = BlendPremul(stain_particle_color, world_color); // Blend wall stain
// world_color = BlendPremul(ground_particle_color, world_color); // Blend wall particle
// }
// world_color = BlendPremul(air_particle_color, world_color);
}
//////////////////////////////
@ -1157,11 +940,6 @@ ComputeShader(V_CompositeCS)
dist = min(dist, screen_selection.p1.y - screen_pos.y);
dist = -dist;
// if (dist >= -half_thickness && dist <= half_thickness)
// {
// selection_color = border_color;
// }
// else
{
if (
tile_pos.x >= tile_selection.p0.x &&

View File

@ -51,11 +51,7 @@ Vec4 V_ColorFromParticleDesc(V_ParticleDesc desc, u32 particle_idx, f32 alive_se
////////////////////////////////////////////////////////////
//~ Shaders
//- Build profiler graph
ComputeShader(V_BuildProfilerGraphCS);
//- Prepare frame
ComputeShader(V_PrepareShadeCS);
ComputeShader(V_PrepareCellsCS);
ComputeShader(V_ClearParticlesCS);
@ -71,9 +67,6 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input);
ComputeShader(V_EmitParticlesCS);
ComputeShader(V_SimParticlesCS);
//- Shade
ComputeShader(V_ShadeCS);
//- Composite
ComputeShader(V_CompositeCS);

View File

@ -34,9 +34,10 @@ Enum(V_ParticleFlag)
V_ParticleFlag_StainWhenPruned = (1 << 1),
V_ParticleFlag_NoReflect = (1 << 2),
V_ParticleFlag_OnlyCollideWithWalls = (1 << 3),
V_ParticleFlag_GasBlend = (1 << 4),
V_ParticleFlag_FadeLifetime = (1 << 5),
V_ParticleFlag_HaltOnCollision = (1 << 6),
V_ParticleFlag_LiquidBlend = (1 << 4),
V_ParticleFlag_GasBlend = (1 << 5),
V_ParticleFlag_FadeLifetime = (1 << 6),
V_ParticleFlag_HaltOnCollision = (1 << 7),
};
Enum(V_ParticleLayer)
@ -49,157 +50,157 @@ Enum(V_ParticleLayer)
};
// NOTE: Higher particle enum values take priority over lower within the same layer ones when drawing / staining
#define V_ParticlesXList(X) \
X( \
/* Name */ None, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Ground, \
/* Stain rate, pen chance */ 30, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(0, 0, 0, 0), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
\
/* Ground particles */ \
X( \
/* Name */ BloodTrail, \
/* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Ground, \
/* Stain rate, pen chance */ 100, 0.25, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.5, \
/* Base color */ VEC4(0.6, 0.1, 0.1, 0.05), \
/* Dry color factor */ VEC4(0.4, 0.4, 0.4, 1) \
) \
X( \
/* Name */ Debris, \
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 20, 30, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(0.4, 0.3, 0.2, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \
) \
X( \
#define V_ParticlesXList(X) \
X( \
/* Name */ None, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Ground, \
/* Stain rate, pen chance */ 30, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(0, 0, 0, 0), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
\
/* Ground particles */ \
X( \
/* Name */ BloodTrail, \
/* Flags */ V_ParticleFlag_LiquidBlend | V_ParticleFlag_NoReflect | V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Ground, \
/* Stain rate, pen chance */ 100, 0.25, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.5, \
/* Base color */ VEC4(0.6, 0.1, 0.1, 0.05), \
/* Dry color factor */ VEC4(0.4, 0.4, 0.4, 1) \
) \
X( \
/* Name */ Debris, \
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 20, 30, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(0.4, 0.3, 0.2, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \
) \
X( \
/* Name */ Fire, \
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ HotDebris, \
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 20, 30, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \
) \
X( \
/* Name */ Spark, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.2, 0.3, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
\
/* Air particles */ \
X( \
/* Name */ BulletSmoke, \
/* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.075, 0.2, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.00, \
/* Base color */ VEC4(0.8, 0.6, 0.2, 0.005), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
X( \
/* Name */ MuzzleWide, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.0, .05, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0, \
/* Base color */ VEC4(10, 3.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ MuzzleNarrow, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.0, 0.05, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0, \
/* Base color */ VEC4(10, 3.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ BulletTrail, \
/* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_FadeLifetime, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.075, 0.075, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0, \
/* Base color */ VEC4(3, 1.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ Bullet, \
/* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_HaltOnCollision, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(5, 1.75, 0.75, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ WallDust, \
/* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.1, 0.25, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(0.5, 0.5, 0.5, 0.35), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
\
/* Test particles */ \
X( \
/* Name */ Test, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(1, 1, 0, 1), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
/* ----------------------------------------------------------------------------------------------------------------------------------- */
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ HotDebris, \
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 20, 30, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \
) \
X( \
/* Name */ Spark, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.2, 0.3, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
\
/* Air particles */ \
X( \
/* Name */ BulletSmoke, \
/* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.075, 0.2, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.00, \
/* Base color */ VEC4(0.8, 0.6, 0.2, 0.005), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
X( \
/* Name */ MuzzleWide, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.0, .05, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0, \
/* Base color */ VEC4(10, 3.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ MuzzleNarrow, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.0, 0.05, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0, \
/* Base color */ VEC4(10, 3.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ BulletTrail, \
/* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_FadeLifetime, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.075, 0.075, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0, \
/* Base color */ VEC4(3, 1.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ Bullet, \
/* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_HaltOnCollision, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(5, 1.75, 0.75, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \
) \
X( \
/* Name */ WallDust, \
/* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \
/* Layer */ V_ParticleLayer_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.1, 0.25, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(0.5, 0.5, 0.5, 0.35), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
\
/* Test particles */ \
X( \
/* Name */ Test, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 0, 0, \
/* Prune speed threshold */ 0.01, \
/* Base color */ VEC4(1, 1, 0, 1), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
) \
/* -------------------------------------------------------------------------------------------------------------------------------------- */
Enum(V_ParticleKind)
{
@ -226,7 +227,7 @@ Struct(V_Particle)
{
i32 kind; // If >= 0, then this maps to V_ParticleKind. Otherwise it represent a particle to be initialized using emitter at index [abs(kind) - 1]
u32 origin_occluder;
u32 prev_occluder; // TODO: Remove this
u32 prev_occluder;
f32 alive_seconds;
f32 stain_accum;
u32 cells_count;
@ -285,33 +286,6 @@ Struct(V_DVert)
Vec4 color_lin;
};
////////////////////////////////////////////////////////////
//~ Profiler types
#define V_ProfilerFramesCap Kibi(16)
#define V_ProfilerZonesXList(X) \
X(None, Color_Cyan) \
/* ---------------------------- */
Enum(V_ProfilerZone)
{
#define X(name, ...) CAT(V_ProfilerZone_,name),
V_ProfilerZonesXList(X)
#undef X
V_ProfilerZone_COUNT
};
Struct(V_ProfilerZoneInfo)
{
f32 elapsed_seconds;
};
Struct(V_ProfilerFrame)
{
V_ProfilerZoneInfo zones[V_ProfilerZone_COUNT];
};
////////////////////////////////////////////////////////////
//~ State types
@ -456,12 +430,6 @@ Struct(V_SharedFrame)
G_SamplerRef basic_samplers[G_BasicSamplerKind_COUNT];
u64 profiler_frame_seq;
G_BufferRef profiler_frames;
Vec2 profiler_graph_dims;
G_TextureRef profiler_graph;
V_TileDesc tile_descs[P_TileKind_COUNT];
G_TextureRef tiles;

View File

@ -1,184 +0,0 @@
////////////////////////////////////////////////////////////
//~ Serialize
String SETTINGS_StringFromWindowSettings(Arena *arena, const PLT_WindowSettings *settings)
{
String minimized = settings->flags & PLT_WindowSettingsFlag_Minimized ? Lit("true") : Lit("false");
String maximized = settings->flags & PLT_WindowSettingsFlag_Maximized ? Lit("true") : Lit("false");
String fullscreen = settings->flags & PLT_WindowSettingsFlag_Fullscreen ? Lit("true") : Lit("false");
i32 x = settings->floating_x;
i32 y = settings->floating_y;
i32 width = settings->floating_width;
i32 height = settings->floating_height;
String fmt = Lit(
"{\n"
" \"window\": {\n"
" \"minimized\": %F,\n"
" \"maximized\": %F,\n"
" \"fullscreen\": %F,\n"
" \"x\": %F,\n"
" \"y\": %F,\n"
" \"width\": %F,\n"
" \"height\": %F\n"
" }\n"
"}\n"
);
String formatted = FormatString(
,
fmt,
FmtString(minimized),
FmtString(maximized),
FmtString(fullscreen),
FmtSint(x),
FmtSint(y),
FmtSint(width),
FmtSint(height)
);
return formatted;
}
////////////////////////////////////////////////////////////
//~ Deserialize
PLT_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out)
{
TempArena scratch = BeginScratch(arena);
String error = ZI;
JSON_Error json_error = ZI;
PLT_WindowSettings *settings = PushStruct(arena, PLT_WindowSettings);
JSON_Result parse_result = JSON_BlobFromString(scratch.arena, src);
if (parse_result.errors.count > 0)
{
json_error = *parse_result.errors.first;
goto abort;
}
JSON_Blob *root = parse_result.root;
if (!root)
{
error = Lit("Root object not found.");
goto abort;
}
JSON_Blob *window = root->child_first;
if (!window || window->type != JSON_Type_Object || !MatchString(window->key, Lit("window")))
{
error = Lit("\"window\" object not found");
goto abort;
}
b32 found_maximized = 0;
b32 found_fullscreen = 0;
b32 found_x = 0;
b32 found_y = 0;
b32 found_width = 0;
b32 found_height = 0;
for (JSON_Blob *child = window->child_first; child; child = child->next)
{
String key = child->key;
if (MatchString(key, Lit("maximized")))
{
if (child->type != JSON_Type_Bool)
{
error = Lit("Expected boolean for \"maximized\"");
goto abort;
}
if (child->value.boolean)
{
settings->flags |= PLT_WindowSettingsFlag_Maximized;
}
found_maximized = 1;
}
else if (MatchString(key, Lit("fullscreen")))
{
if (child->type != JSON_Type_Bool)
{
error = Lit("Expected boolean for \"fulscreen\"");
goto abort;
}
if (child->value.boolean)
{
settings->flags |= PLT_WindowSettingsFlag_Fullscreen;
}
found_fullscreen = 1;
}
else if (MatchString(key, Lit("x")))
{
if (child->type != JSON_Type_Number)
{
error = Lit("Expected number for \"x\"");
goto abort;
}
settings->floating_x = RoundF32ToI32(child->value.number);
found_x = 1;
}
else if (MatchString(key, Lit("y")))
{
if (child->type != JSON_Type_Number)
{
error = Lit("Expected number for \"y\"");
goto abort;
}
settings->floating_y = RoundF32ToI32(child->value.number);
found_y = 1;
}
else if (MatchString(key, Lit("width")))
{
if (child->type != JSON_Type_Number)
{
error = Lit("Expected number for \"width\"");
goto abort;
}
settings->floating_width = RoundF32ToI32(child->value.number);
found_width = 1;
}
else if (MatchString(key, Lit("height")))
{
if (child->type != JSON_Type_Number)
{
error = Lit("Expected number for \"height\"");
goto abort;
}
settings->floating_height = RoundF32ToI32(child->value.number);
found_height = 1;
}
}
if (!found_maximized) { error = Lit("Missing \"maximized\""); goto abort; }
if (!found_fullscreen) { error = Lit("Missing \"fullscreen\""); goto abort; }
if (!found_x) { error = Lit("Missing \"x\""); goto abort; }
if (!found_y) { error = Lit("Missing \"y\""); goto abort; }
if (!found_width) { error = Lit("Missing \"width\""); goto abort; }
if (!found_height) { error = Lit("Missing \"height\""); goto abort; }
abort:
if (error_out && (error.len > 0 || json_error.msg.len > 0))
{
if (json_error.msg.len > 0)
{
*error_out = StringF(
arena,
Lit("%F\n(%F:%F)"),
FmtString(json_error.msg),
FmtUint(json_error.start),
FmtUint(json_error.end)
);
}
else
{
*error_out = PushString(arena, error);
}
}
EndScratch(scratch);
return settings;
}

View File

@ -1,2 +0,0 @@
String SETTINGS_StringFromWindowSettings(Arena *arena, const PLT_WindowSettings *settings);
PLT_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out);

View File

@ -1,18 +0,0 @@
@Layer settings
//////////////////////////////
//- Dependencies
@Dep base
@Dep platform
@Dep json
//////////////////////////////
//- Api
@IncludeC settings_core.h
//////////////////////////////
//- Impl
@IncludeC settings_core.c