remove unused layers
This commit is contained in:
parent
fb5aec6bac
commit
179e79f7b7
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
@ -1,19 +0,0 @@
|
||||
@Layer mixer
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep platform
|
||||
@Dep sound
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC mixer.h
|
||||
|
||||
@Bootstrap MIX_Bootstrap
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC mixer.c
|
||||
292
src/pp/pp.c
292
src/pp/pp.c
@ -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
|
||||
|
||||
|
||||
12
src/pp/pp.h
12
src/pp/pp.h
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
@ -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
@ -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;
|
||||
|
||||
@ -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 &&
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
String SETTINGS_StringFromWindowSettings(Arena *arena, const PLT_WindowSettings *settings);
|
||||
PLT_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out);
|
||||
@ -1,18 +0,0 @@
|
||||
@Layer settings
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep json
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC settings_core.h
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC settings_core.c
|
||||
Loading…
Reference in New Issue
Block a user