Sold my soul to play monlight sonata

Audio sources & decoding are pretty much done and working well.

Playback is not really implemented yet, I'm just hacking in a way to output an audio source.

- Seriously microsoft wtf
This commit is contained in:
Charlie 2024-07-12 21:11:47 +02:00
parent e1aafd8220
commit 2b335aee35
19 changed files with 1102 additions and 198 deletions

5
TODO Normal file
View file

@ -0,0 +1,5 @@
- Audio
- Optimize
- Spam simd
- Concurrent jobs for players?

View file

@ -6,6 +6,6 @@ mkdir build
pushd build pushd build
clang -g -o cgame.exe ../build.c -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -lkernel32 -lgdi32 -luser32 -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -femit-all-decls clang -g -o cgame.exe ../build.c -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -femit-all-decls
popd popd

View file

@ -3,6 +3,8 @@
/// ///
// Build config stuff // Build config stuff
#define OOGABOOGA_DEV 1
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5) #define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
typedef struct Context_Extra { typedef struct Context_Extra {
@ -26,12 +28,13 @@ typedef struct Context_Extra {
// //
// this is a minimal starting point for new projects. Copy & rename to get started // this is a minimal starting point for new projects. Copy & rename to get started
#include "oogabooga/examples/minimal_game_loop.c" // #include "oogabooga/examples/minimal_game_loop.c"
// #include "oogabooga/examples/text_rendering.c" // #include "oogabooga/examples/text_rendering.c"
// #include "oogabooga/examples/custom_logger.c" // #include "oogabooga/examples/custom_logger.c"
// #include "oogabooga/examples/renderer_stress_test.c" // #include "oogabooga/examples/renderer_stress_test.c"
// #include "oogabooga/examples/tile_game.c" // #include "oogabooga/examples/tile_game.c"
#include "oogabooga/examples/audio_test.c"
// This is where you swap in your own project! // This is where you swap in your own project!
// #include "entry_yourepicgamename.c" // #include "entry_yourepicgamename.c"

View file

@ -9,7 +9,7 @@ pushd build
mkdir release mkdir release
pushd release pushd release
clang -o cgame.exe ../../build.c -Ofast -DNDEBUG -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -Wno-deprecated-declarations -lgdi32 -luser32 -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -finline-functions -finline-hint-functions -ffast-math -fno-math-errno -funsafe-math-optimizations -freciprocal-math -ffinite-math-only -fassociative-math -fno-signed-zeros -fno-trapping-math -ftree-vectorize -fomit-frame-pointer -funroll-loops -fno-rtti -fno-exceptions clang -o cgame.exe ../../build.c -Ofast -DNDEBUG -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -Wno-deprecated-declarations -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -finline-functions -finline-hint-functions -ffast-math -fno-math-errno -funsafe-math-optimizations -freciprocal-math -ffinite-math-only -fassociative-math -fno-signed-zeros -fno-trapping-math -ftree-vectorize -fomit-frame-pointer -funroll-loops -fno-rtti -fno-exceptions
popd popd
popd popd

View file

@ -1,3 +1,21 @@
## v0.01.001 - AUDIO!
- Added audio sources
- File stream sources & Fully decoded sources
- 16-bit int & 32-bit float support
- WAV & OGG support
- Usage:
bool audio_source_init_file_stream(*src, path, bit_width, allocator)
bool audio_source_init_file_decode(*src, path, bit_width, allocator)
void audio_source_destroy(*src)
- Misc
- Win32 audio impl
- Make default logger thread safe
- Rename tm_scope_cycles & tm_scope_cycles_xxx -> tm_scope & tm_scope_xxx
- Minor cleanups
## v0.00.005 - Z layers ## v0.00.005 - Z layers
Renderer: Renderer:

View file

@ -1,37 +1,308 @@
/*
bool check_wav_header(string data) { bool check_wav_header(string data) {
return string_starts_with(data, STR("RIFFWAVE")); return string_starts_with(data, STR("RIFF"));
} }
bool check_ogg_header(string data) { bool check_ogg_header(string data) {
return string_starts_with(data, STR("oggs")); return string_starts_with(data, STR("OggS"));
} }
typedef enum Audio_Format_Type { // Supporting more than s16 and f32
AUDIO_FORMAT_TYPE_UNKNOWN, // If it's a real thing that there's audio devices which support neither then I will be surprised
AUDIO_FORMAT_TYPE_U8, // The only format I might consider adding is S32 if it turns out people want VERY detailed audio
AUDIO_FORMAT_TYPE_S16, typedef enum Audio_Format_Bits {
AUDIO_FORMAT_TYPE_S24, AUDIO_BITS_16, // this will be s16
AUDIO_FORMAT_TYPE_S32, AUDIO_BITS_32, // this will be f32
AUDIO_FORMAT_TYPE_F32 } Audio_Format_Bits;
} Audio_Format_Type; u64 get_audio_bit_width_byte_size(Audio_Format_Bits b) {
switch (b) {
case AUDIO_BITS_32: return 4; break;
case AUDIO_BITS_16: return 2; break;
}
panic("");
}
typedef struct Audio_Format { typedef struct Audio_Format {
Audio_Format_Type type; Audio_Format_Bits bit_width;
int channels; int channels;
int sample_rate; int sample_rate;
} Audio_Format; } Audio_Format;
u64 get_audio_format_component_byte_size(Audio_Format_Type format) { // I don't see a big reason for you to use anything else than WAV and OGG.
switch (format) { // If you use mp3 that's just not very smart.
case AUDIO_FORMAT_TYPE_F32: return 4; break; // Ogg has better quality AND better compression AND you don't need any licensing (which you need for mp3)
case AUDIO_FORMAT_TYPE_S32: return 4; break; // https://convertio.co/mp3-ogg/
case AUDIO_FORMAT_TYPE_S24: return 3; break; // I will probably add mp3 support at some point for compatibility reasonavg.
case AUDIO_FORMAT_TYPE_S16: return 2; break; // - Charlie 2024-07-11
case AUDIO_FORMAT_TYPE_U8: return 1; break; typedef enum Audio_Decoder_Kind {
case AUDIO_FORMAT_TYPE_UNKNOWN: return 0; break; AUDIO_DECODER_WAV,
AUDIO_DECODER_OGG
} Audio_Decoder_Kind;
typedef enum Audio_Source_Kind {
AUDIO_SOURCE_FILE_STREAM,
AUDIO_SOURCE_MEMORY, // Raw pcm frames
} Audio_Source_Kind;
typedef struct Audio_Source {
Audio_Source_Kind kind;
Audio_Format format;
u64 number_of_frames;
Allocator allocator;
string compressed_data;
// For file stream
Audio_Decoder_Kind decoder;
union {
drwav wav;
stb_vorbis *ogg;
};
// For memory source
void *pcm_frames;
} Audio_Source;
int
_audio_file_stream_sample_frames(Audio_Source *src, u64 first_frame_index,
u64 number_of_frames, void *output_buffer);
bool
audio_source_init_file_stream(Audio_Source *src, string path, Audio_Format_Bits bit_width,
Allocator allocator) {
*src = ZERO(Audio_Source);
src->allocator = allocator;
src->kind = AUDIO_SOURCE_FILE_STREAM;
string data;
bool read_ok = os_read_entire_file(path, &data, allocator);
src->compressed_data = data;
third_party_allocator = allocator;
if (!read_ok) {
third_party_allocator = ZERO(Allocator);
return false;
} }
panic("");
if (check_wav_header(data)) {
drwav_bool32 init_ok = drwav_init_memory(&src->wav, data.data, data.count, null);
if (!init_ok) {
third_party_allocator = ZERO(Allocator);
return false;
}
src->decoder = AUDIO_DECODER_WAV;
src->format.channels = src->wav.fmt.channels;
src->format.sample_rate = src->wav.fmt.sampleRate;
src->number_of_frames = src->wav.totalPCMFrameCount;
} else if (check_ogg_header(data)) {
int err;
src->ogg = stb_vorbis_open_memory(data.data, data.count, &err, null);
if (!src->ogg) {
third_party_allocator = ZERO(Allocator);
return false;
}
src->decoder = AUDIO_DECODER_OGG;
stb_vorbis_info info = stb_vorbis_get_info(src->ogg);
src->format.channels = info.channels;
src->format.sample_rate = info.sample_rate;
src->number_of_frames = stb_vorbis_stream_length_in_samples(src->ogg);
} else {
log_error("Error in init_audio_source_file_stream(): Unrecognized audio format in file '%s'. We currently support WAV and OGG (Vorbis).", path);
third_party_allocator = ZERO(Allocator);
return false;
}
src->format.bit_width = bit_width;
third_party_allocator = ZERO(Allocator);
return true;
} }
bool
audio_source_init_file_decode(Audio_Source *src, string path, Audio_Format_Bits bit_width,
Allocator allocator) {
if (!audio_source_init_file_stream(src, path, bit_width, allocator)) return false;
src->kind = AUDIO_SOURCE_MEMORY;
u64 comp_size = get_audio_bit_width_byte_size(src->format.bit_width);
u64 total_size = src->number_of_frames * src->format.channels * comp_size;
src->pcm_frames = alloc(allocator, total_size);
int num_retrieved = _audio_file_stream_sample_frames(src, 0, src->number_of_frames, src->pcm_frames);
assert(num_retrieved == src->number_of_frames, "decoder failed failed");
return true;
}
void
audio_source_destroy(Audio_Source *src) {
switch (src->kind) {
case AUDIO_SOURCE_FILE_STREAM: {
if (src->pcm_frames) dealloc(src->allocator, src->pcm_frames);
break;
}
case AUDIO_SOURCE_MEMORY: {
dealloc(src->allocator, src->pcm_frames);
break;
}
}
third_party_allocator = src->allocator;
switch (src->decoder) {
case AUDIO_DECODER_WAV: {
drwav_uninit(&src->wav);
break;
}
case AUDIO_DECODER_OGG: {
stb_vorbis_close(src->ogg);
break;
}
}
third_party_allocator = ZERO(Allocator);
dealloc_string(src->allocator, src->compressed_data);
}
int
_audio_file_stream_sample_frames(Audio_Source *src, u64 first_frame_index,
u64 number_of_frames, void *output_buffer) {
third_party_allocator = src->allocator;
int retrieved = 0;
switch (src->decoder) {
case AUDIO_DECODER_WAV:
bool seek_ok = drwav_seek_to_pcm_frame(&src->wav, first_frame_index);
assert(seek_ok);
switch(src->format.bit_width) {
case AUDIO_BITS_32: {
retrieved = drwav_read_pcm_frames_f32(
&src->wav,
number_of_frames,
(f32*)output_buffer
);
break;
}
case AUDIO_BITS_16: {
retrieved = drwav_read_pcm_frames_s16(
&src->wav,
number_of_frames,
(s16*)output_buffer
);
break;
}
default: panic("Invalid bits value");
} break; // case AUDIO_DECODER_WAV:
case AUDIO_DECODER_OGG:
seek_ok = stb_vorbis_seek(src->ogg, first_frame_index);
assert(seek_ok);
switch(src->format.bit_width) {
case AUDIO_BITS_32: {
retrieved = stb_vorbis_get_samples_float_interleaved(
src->ogg,
src->format.channels,
(f32*)output_buffer,
number_of_frames * src->format.channels
);
break;
}
case AUDIO_BITS_16: {
retrieved = stb_vorbis_get_samples_short_interleaved(
src->ogg,
src->format.channels,
(s16*)output_buffer,
number_of_frames * src->format.channels
);
break;
}
default: panic("Invalid bits value");
} break; // case AUDIO_DECODER_OGG:
default: panic("Invalid decoder value");
}
third_party_allocator = ZERO(Allocator);
return retrieved;
}
u64 // New frame index
audio_source_sample_frames(Audio_Source *src, u64 first_frame_index, u64 number_of_frames,
void *output_buffer, bool looping) {
u64 comp_size = get_audio_bit_width_byte_size(src->format.bit_width);
u64 frame_size = comp_size * src->format.channels;
u64 output_size = number_of_frames * frame_size;
if (first_frame_index == src->number_of_frames) {
return first_frame_index;
}
assert(first_frame_index < src->number_of_frames, "Invalid first_frame_index");
u64 new_index = first_frame_index;
int num_retrieved;
switch (src->kind) {
case AUDIO_SOURCE_FILE_STREAM: {
num_retrieved = _audio_file_stream_sample_frames(
src,
first_frame_index,
number_of_frames,
output_buffer
);
new_index += num_retrieved;
assert(num_retrieved <= number_of_frames);
if (num_retrieved < number_of_frames) {
void *dst_remain = ((u8*)output_buffer) + num_retrieved*frame_size;
if (looping) {
num_retrieved = _audio_file_stream_sample_frames(
src,
0,
number_of_frames-num_retrieved,
dst_remain
);
new_index = number_of_frames-num_retrieved;
} else {
memset(dst_remain, 0, frame_size * (number_of_frames - num_retrieved));
}
}
break; // case AUDIO_SOURCE_FILE_STREAM
}
case AUDIO_SOURCE_MEMORY: {
s64 first_number_of_frames = min(number_of_frames, src->number_of_frames-first_frame_index);
void *src_pcm_start = (u8*)src->pcm_frames + first_frame_index*frame_size;
memcpy(output_buffer, src_pcm_start, first_number_of_frames*frame_size);
new_index += first_number_of_frames;
s64 remainder = number_of_frames-first_number_of_frames;
if (remainder > 0) {
void *dst_remain = (u8*)output_buffer + first_number_of_frames*frame_size;
if (looping) {
memcpy(dst_remain, src->pcm_frames, frame_size*remainder);
new_index = remainder;
} else {
memset(dst_remain, 0, frame_size*remainder);
}
}
break;
}
}
return new_index;
}
#define U8_MAX 255 #define U8_MAX 255
#define S16_MIN -32768 #define S16_MIN -32768
#define S16_MAX 32767 #define S16_MAX 32767
@ -40,8 +311,9 @@ u64 get_audio_format_component_byte_size(Audio_Format_Type format) {
#define S32_MIN -2147483648 #define S32_MIN -2147483648
#define S32_MAX 2147483647 #define S32_MAX 2147483647
void mix_frames(void *dst, void *src, u64 frame_count, Audio_Format format) { void
u64 comp_size = get_audio_format_component_byte_size(format.type); mix_frames(void *dst, void *src, u64 frame_count, Audio_Format format) {
u64 comp_size = get_audio_bit_width_byte_size(format.bit_width);
u64 frame_size = comp_size * format.channels; u64 frame_size = comp_size * format.channels;
u64 output_size = frame_count * frame_size; u64 output_size = frame_count * frame_size;
@ -57,54 +329,300 @@ void mix_frames(void *dst, void *src, u64 frame_count, Audio_Format format) {
void *src_sample = (u8*)src + frame*frame_size + c*comp_size; void *src_sample = (u8*)src + frame*frame_size + c*comp_size;
void *dst_sample = (u8*)dst + frame*frame_size + c*comp_size; void *dst_sample = (u8*)dst + frame*frame_size + c*comp_size;
switch (format.type) { switch (format.bit_width) {
case AUDIO_FORMAT_TYPE_F32: { case AUDIO_BITS_32: {
*((f32*)dst_sample) += *((f32*)src_sample); *((f32*)dst_sample) += *((f32*)src_sample);
} }
case AUDIO_FORMAT_TYPE_S32: { case AUDIO_BITS_16: {
s32 dst_int = *((s32*)dst_sample);
s32 src_int = *((s32*)src_sample);
*((s32*)dst_sample) = (s32)clamp((s64)(dst_int + src_int), S32_MIN, S32_MAX);
break;
}
case AUDIO_FORMAT_TYPE_S24: {
s64 src_int = 0;
memcpy(&src_int, src_sample, 3);
src_int <<= 40;
src_int >>= 40;
s64 dst_int;
memcpy(&dst_int, dst_sample, 3);
dst_int <<= 40;
dst_int >>= 40;
s64 sum = clamp(src_int + dst_int, S24_MIN, S24_MAX);
memcpy(dst_sample, &sum, 3);
break;
}
case AUDIO_FORMAT_TYPE_S16: {
s16 dst_int = *((s16*)dst_sample); s16 dst_int = *((s16*)dst_sample);
s16 src_int = *((s16*)src_sample); s16 src_int = *((s16*)src_sample);
*((s16*)dst_sample) = (s16)clamp((s64)(dst_int + src_int), S16_MIN, S16_MAX); *((s16*)dst_sample) = (s16)clamp((s64)(dst_int + src_int), S16_MIN, S16_MAX);
break; break;
} }
case AUDIO_FORMAT_TYPE_U8: {
u8 dst_int = *((u8*)dst_sample);
u8 src_int = *((u8*)src_sample);
*((u8*)dst_sample) = (u8)clamp((s64(dst_int + src_int), 0, U8_MAX);
break;
}
case AUDIO_FORMAT_TYPE_UNKNOWN: break;
} }
} }
} }
} }
*/ void
convert_one_component(void *dst, Audio_Format_Bits dst_bits,
void *src, Audio_Format_Bits src_bits) {
switch (dst_bits) {
case AUDIO_BITS_32: {
switch (src_bits) {
case AUDIO_BITS_32:
memcpy(dst, src, get_audio_bit_width_byte_size(dst_bits)); break;
case AUDIO_BITS_16:
// #Simd
*(f32*)dst = (f64)((f32)*((s16*)src) * ((f64)1.0 / (f64)32768.0));
break;
default: panic("Unhandled bits");
}
break;
}
case AUDIO_BITS_16: {
switch (src_bits) {
case AUDIO_BITS_32:
// #Simd
*(s16*)dst = (s16)(*((f32*)src) * 32768.0f);
break;
case AUDIO_BITS_16:
memcpy(dst, src, get_audio_bit_width_byte_size(dst_bits));
break;
default: panic("Unhandled bits");
}
break;
}
default: panic("Unhandled bits");
}
}
// Assume dst buffer is large enough
// in-place conversion is OK
void
resample_frames(void *dst, Audio_Format dst_format,
void *src, Audio_Format src_format, u64 src_frame_count) {
assert(dst_format.channels == src_format.channels, "Channel count must be the same for sample rate conversion");
assert(dst_format.bit_width == src_format.bit_width, "Types must be the same for sample rate conversion");
f32 src_ratio = (f32)src_format.sample_rate / (f32)dst_format.sample_rate;
u64 dst_frame_count = (u64)round(src_frame_count / src_ratio);
u64 dst_comp_size = get_audio_bit_width_byte_size(dst_format.bit_width);
u64 dst_frame_size = dst_comp_size * dst_format.channels;
u64 src_comp_size = get_audio_bit_width_byte_size(src_format.bit_width);
u64 src_frame_size = src_comp_size * src_format.channels;
// Reverse in case dst == src (so we can do in-place conversion)
for (s64 dst_frame_index = dst_frame_count - 1; dst_frame_index >= 1; dst_frame_index--) {
f32 src_frame_index_f = dst_frame_index * src_ratio;
u64 src_frame_index_1 = (u64)src_frame_index_f;
u64 src_frame_index_2 = src_frame_index_1 + 1;
if (src_frame_index_2 >= src_frame_count) src_frame_index_2 = src_frame_count - 1;
f32 lerp_factor = src_frame_index_f - (f32)src_frame_index_1;
void *src_frame_1 = (u8*)src + src_frame_index_1 * src_frame_size;
void *src_frame_2 = (u8*)src + src_frame_index_2 * src_frame_size;
void *dst_frame = (u8*)dst + dst_frame_index * dst_frame_size;
for (int c = 0; c < src_format.channels; c++) {
union {
s16 s16_sample;
f32 f32_sample;
u8 data[4];
} sample_dst;
void *src_comp_1 = (u8*)src_frame_1 + c * src_comp_size;
void *src_comp_2 = (u8*)src_frame_2 + c * src_comp_size;
void *dst_comp = (u8*)dst_frame + c * dst_comp_size;
if (src_format.bit_width == AUDIO_BITS_32) {
float sample_1 = *((f32*)src_comp_1);
float sample_2 = *((f32*)src_comp_2);
sample_dst.f32_sample = sample_1 + lerp_factor * (sample_2 - sample_1);
} else if (src_format.bit_width == AUDIO_BITS_16) {
s16 sample_1 = *((s16*)src_comp_1);
s16 sample_2 = *((s16*)src_comp_2);
sample_dst.s16_sample = (s16)((f32)sample_1 + lerp_factor * ((f32)sample_2 - (f32)sample_1));
} else {
panic("Unhandled bit width");
}
memcpy(dst_comp, sample_dst.data, dst_comp_size);
}
}
// Correct padding if we downscaled (since we coverted in reverse)
if (src == dst && dst_format.sample_rate < src_format.sample_rate) {
void *dst_after_pad = (u8*)dst + (src_frame_count - dst_frame_count) * dst_frame_size;
u64 padding = (u64)dst_after_pad - (u64)dst;
memcpy(
dst,
dst_after_pad,
dst_frame_count * dst_frame_size
);
memset((u8*)dst+dst_frame_count * dst_frame_size, 0, padding);
}
}
// Assumes dst buffer is large enough
void
convert_frames(void *dst, Audio_Format dst_format,
void *src, Audio_Format src_format, u64 src_frame_count) {
u64 dst_comp_size = get_audio_bit_width_byte_size(dst_format.bit_width);
u64 dst_frame_size = dst_comp_size * dst_format.channels;
u64 src_comp_size = get_audio_bit_width_byte_size(src_format.bit_width);
u64 src_frame_size = src_comp_size * src_format.channels;
if (dst_format.sample_rate != src_format.sample_rate) {
f32 ratio = (f32)src_format.sample_rate/(f32)dst_format.sample_rate;
src_frame_count = (u64)round((f32)src_frame_count*ratio);
}
if (bytes_match(&dst_format, &src_format, sizeof(Audio_Format))) {
memcpy(dst, src, src_frame_count*src_frame_size);
return;
}
u64 output_frame_count = src_frame_count;
// #Speed #Simd
if (dst_format.channels != src_format.channels || dst_format.bit_width != src_format.bit_width) {
for (u64 src_frame_index = 0; src_frame_index < src_frame_count; src_frame_index++) {
void *src_frame = ((u8*)src) + src_frame_index*src_frame_size;
void *dst_frame = ((u8*)dst) + src_frame_index*dst_frame_size;
// For getting average src sample
union {
s16 s16_sample;
f32 f32_sample;
u8 data[4];
} avg;
if (src_format.channels != dst_format.channels) {
// This is where we get the average src sample
f32 sum = 0;
for (int c = 0; c < src_format.channels; c++) {
avg.s16_sample = 0;
void *src_comp = (u8*)src_frame + c * src_comp_size;
convert_one_component(
avg.data, dst_format.bit_width,
src_comp, src_format.bit_width
);
if (dst_format.bit_width == AUDIO_BITS_32) sum += avg.f32_sample;
else if (dst_format.bit_width == AUDIO_BITS_16) sum += (f32)avg.s16_sample;
else panic("Unhandled bit width");
}
if (dst_format.bit_width == AUDIO_BITS_32) {
avg.f32_sample = sum/(f32)src_format.channels;
} else if (dst_format.bit_width == AUDIO_BITS_16) {
avg.s16_sample = (s16)round(sum/(f32)src_format.channels);
} else panic("Unhandled bit width");
}
if (src_format.channels > dst_format.channels) {
// #Limitation #Audioquality
// Here we are down-scaling the channel count.
// So what we do is we get the average sample for all channels in src and then
// set all channels in dst to that. This is fine for mono to stereo, but will
// be a loss for example for surround to mono. But I'm not sure we will ever
// care about non-stereo/mono audio.
for (int c = 0; c < dst_format.channels; c++) {
void *dst_comp = (u8*)dst_frame + c * dst_comp_size;
memcpy(dst_comp, avg.data, dst_comp_size);
}
} else if (dst_format.channels > src_format.channels) {
// Here, we are upscaling to a higher channel count.
// I'm not sure what the best way to do this is, but for now I will try to just
// get the average in src and set that to the extra channels in dst.
// This is obviously fine for mono -> stereo but might be a problem for surround.
// Again, I'm not sure if surround will ever be on our list of worries.
for (int c = 0; c < dst_format.channels; c++) {
void *dst_comp = (u8*)dst_frame + c * dst_comp_size;
void *src_comp = (u8*)src_frame + c * src_comp_size;
if (c < src_format.channels)
convert_one_component(dst_comp, dst_format.bit_width,
src_comp, src_format.bit_width);
else
memcpy(dst_comp, avg.data, dst_comp_size);
}
} else {
// Same channel count, just copy components over
for (int c = 0; c < dst_format.channels; c++) {
void *dst_comp = (u8*)dst_frame + c * dst_comp_size;
void *src_comp = (u8*)src_frame + c * src_comp_size;
convert_one_component(dst_comp, dst_format.bit_width, src_comp, src_format.bit_width);
}
}
}
}
if (dst_format.sample_rate != src_format.sample_rate) {
resample_frames(
dst,
(Audio_Format){dst_format.bit_width, dst_format.channels, dst_format.sample_rate},
dst,
(Audio_Format){dst_format.bit_width, dst_format.channels, src_format.sample_rate},
src_frame_count
);
}
}
// #Temporary this is jsut for testing
Audio_Source *current_source = 0;
u64 current_index = 0;
// This is supposed to be called by OS layer audio thread whenever it wants more audio samples
void do_program_audio_sample(u64 number_of_output_frames, Audio_Format out_format,
void *output) {
u64 out_comp_size = get_audio_bit_width_byte_size(out_format.bit_width);
u64 out_frame_size = out_comp_size * out_format.channels;
u64 output_size = number_of_output_frames * out_frame_size;
memset(output, 0, output_size);
if (current_source) {
bool need_convert = !bytes_match(&out_format, &current_source->format, sizeof(Audio_Format));
u64 in_comp_size = get_audio_bit_width_byte_size(current_source->format.bit_width);
u64 in_frame_size = in_comp_size * current_source->format.channels;
u64 input_size = number_of_output_frames * in_frame_size;
void *target_buffer = output;
u64 number_of_sample_frames = number_of_output_frames;
thread_local local_persist void *convert_buffer = 0;
thread_local local_persist u64 convert_buffer_size;
if (need_convert) {
if (current_source->format.sample_rate != out_format.sample_rate) {
f32 src_ratio
= (f32)current_source->format.sample_rate / (f32)out_format.sample_rate;
number_of_sample_frames = round(number_of_output_frames * src_ratio);
input_size = number_of_sample_frames * in_frame_size;
}
u64 biggest_size = max(input_size, output_size);
if (!convert_buffer || convert_buffer_size < biggest_size) {
// #Speed
if (convert_buffer) dealloc(get_heap_allocator(), convert_buffer);
convert_buffer = alloc(get_heap_allocator(), biggest_size);
convert_buffer_size = biggest_size;
}
target_buffer = convert_buffer;
memset(convert_buffer, 0, biggest_size);
}
current_index = audio_source_sample_frames(
current_source,
current_index,
number_of_sample_frames,
target_buffer,
true
);
if (need_convert) {
convert_frames(
output,
out_format,
convert_buffer,
current_source->format,
number_of_output_frames
);
}
}
}

View file

@ -3,6 +3,13 @@ typedef struct Spinlock Spinlock;
typedef struct Mutex Mutex; typedef struct Mutex Mutex;
typedef struct Binary_Semaphore Binary_Semaphore; typedef struct Binary_Semaphore Binary_Semaphore;
// These are probably your best friend for sync-free multi-processing.
inline bool compare_and_swap_8(uint8_t *a, uint8_t b, uint8_t old);
inline bool compare_and_swap_16(uint16_t *a, uint16_t b, uint16_t old);
inline bool compare_and_swap_32(uint32_t *a, uint32_t b, uint32_t old);
inline bool compare_and_swap_64(uint64_t *a, uint64_t b, uint64_t old);
inline bool compare_and_swap_bool(bool *a, bool b, bool old);
/// ///
// Spinlock "primitive" // Spinlock "primitive"
// Like a mutex but it eats up the entire core while waiting. // Like a mutex but it eats up the entire core while waiting.

View file

@ -29,7 +29,8 @@ typedef struct Cpu_Capabilities {
#define inline __forceinline #define inline __forceinline
#define alignat(x) __declspec(align(x)) #define alignat(x) __declspec(align(x))
#define COMPILER_HAS_MEMCPY_INTRINSICS 1 #define COMPILER_HAS_MEMCPY_INTRINSICS 1
inline void crash() { inline void
crash() {
__debugbreak(); __debugbreak();
volatile int *a = 0; volatile int *a = 0;
*a = 5; *a = 5;
@ -38,7 +39,8 @@ typedef struct Cpu_Capabilities {
} }
#include <intrin.h> #include <intrin.h>
#pragma intrinsic(__rdtsc) #pragma intrinsic(__rdtsc)
inline u64 rdtsc() { inline u64
rdtsc() {
return __rdtsc(); return __rdtsc();
} }
inline Cpu_Info_X86 cpuid(u32 function_id) { inline Cpu_Info_X86 cpuid(u32 function_id) {
@ -77,23 +79,28 @@ typedef struct Cpu_Capabilities {
#pragma intrinsic(_InterlockedCompareExchange) #pragma intrinsic(_InterlockedCompareExchange)
#pragma intrinsic(_InterlockedCompareExchange64) #pragma intrinsic(_InterlockedCompareExchange64)
inline bool compare_and_swap_8(uint8_t *a, uint8_t b, uint8_t old) { inline bool
compare_and_swap_8(uint8_t *a, uint8_t b, uint8_t old) {
return _InterlockedCompareExchange8((volatile char*)a, (char)b, (char)old) == old; return _InterlockedCompareExchange8((volatile char*)a, (char)b, (char)old) == old;
} }
inline bool compare_and_swap_16(uint16_t *a, uint16_t b, uint16_t old) { inline bool
compare_and_swap_16(uint16_t *a, uint16_t b, uint16_t old) {
return _InterlockedCompareExchange16((volatile short*)a, (short)b, (short)old) == old; return _InterlockedCompareExchange16((volatile short*)a, (short)b, (short)old) == old;
} }
inline bool compare_and_swap_32(uint32_t *a, uint32_t b, uint32_t old) { inline bool
compare_and_swap_32(uint32_t *a, uint32_t b, uint32_t old) {
return _InterlockedCompareExchange((volatile long*)a, (long)b, (long)old) == old; return _InterlockedCompareExchange((volatile long*)a, (long)b, (long)old) == old;
} }
inline bool compare_and_swap_64(uint64_t *a, uint64_t b, uint64_t old) { inline bool
compare_and_swap_64(uint64_t *a, uint64_t b, uint64_t old) {
return _InterlockedCompareExchange64((volatile long long*)a, (long long)b, (long long)old) == old; return _InterlockedCompareExchange64((volatile long long*)a, (long long)b, (long long)old) == old;
} }
inline bool compare_and_swap_bool(bool *a, bool b, bool old) { inline bool
compare_and_swap_bool(bool *a, bool b, bool old) {
return compare_and_swap_8((uint8_t*)a, (uint8_t)b, (uint8_t)old); return compare_and_swap_8((uint8_t*)a, (uint8_t)b, (uint8_t)old);
} }
@ -103,19 +110,25 @@ typedef struct Cpu_Capabilities {
#define inline __attribute__((always_inline)) inline #define inline __attribute__((always_inline)) inline
#define alignat(x) __attribute__((aligned(x))) #define alignat(x) __attribute__((aligned(x)))
#define COMPILER_HAS_MEMCPY_INTRINSICS 1 #define COMPILER_HAS_MEMCPY_INTRINSICS 1
inline void crash() {
inline void
crash() {
__builtin_trap(); __builtin_trap();
volatile int *a = 0; volatile int *a = 0;
*a = 5; *a = 5;
a = (int*)0xDEADBEEF; a = (int*)0xDEADBEEF;
*a = 5; *a = 5;
} }
inline u64 rdtsc() {
inline u64
rdtsc() {
unsigned int lo, hi; unsigned int lo, hi;
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo; return ((u64)hi << 32) | lo;
} }
inline Cpu_Info_X86 cpuid(u32 function_id) {
inline
Cpu_Info_X86 cpuid(u32 function_id) {
Cpu_Info_X86 info; Cpu_Info_X86 info;
__asm__ __volatile__( __asm__ __volatile__(
"cpuid" "cpuid"
@ -152,7 +165,8 @@ typedef struct Cpu_Capabilities {
#define DEPRECATED(proc, msg) proc __attribute__((deprecated(msg))) #define DEPRECATED(proc, msg) proc __attribute__((deprecated(msg)))
inline bool compare_and_swap_8(uint8_t *a, uint8_t b, uint8_t old) { inline bool
compare_and_swap_8(uint8_t *a, uint8_t b, uint8_t old) {
unsigned char result; unsigned char result;
__asm__ __volatile__( __asm__ __volatile__(
"lock; cmpxchgb %2, %1" "lock; cmpxchgb %2, %1"
@ -163,7 +177,8 @@ typedef struct Cpu_Capabilities {
return result == old; return result == old;
} }
inline bool compare_and_swap_16(uint16_t *a, uint16_t b, uint16_t old) { inline bool
compare_and_swap_16(uint16_t *a, uint16_t b, uint16_t old) {
unsigned short result; unsigned short result;
__asm__ __volatile__( __asm__ __volatile__(
"lock; cmpxchgw %2, %1" "lock; cmpxchgw %2, %1"
@ -174,7 +189,8 @@ typedef struct Cpu_Capabilities {
return result == old; return result == old;
} }
inline bool compare_and_swap_32(uint32_t *a, uint32_t b, uint32_t old) { inline bool
compare_and_swap_32(uint32_t *a, uint32_t b, uint32_t old) {
unsigned int result; unsigned int result;
__asm__ __volatile__( __asm__ __volatile__(
"lock; cmpxchgl %2, %1" "lock; cmpxchgl %2, %1"
@ -185,7 +201,8 @@ typedef struct Cpu_Capabilities {
return result == old; return result == old;
} }
inline bool compare_and_swap_64(uint64_t *a, uint64_t b, uint64_t old) { inline bool
compare_and_swap_64(uint64_t *a, uint64_t b, uint64_t old) {
unsigned long long result; unsigned long long result;
__asm__ __volatile__( __asm__ __volatile__(
"lock; cmpxchgq %2, %1" "lock; cmpxchgq %2, %1"
@ -196,7 +213,8 @@ typedef struct Cpu_Capabilities {
return result == old; return result == old;
} }
inline bool compare_and_swap_bool(bool *a, bool b, bool old) { inline bool
compare_and_swap_bool(bool *a, bool b, bool old) {
return compare_and_swap_8((uint8_t*)a, (uint8_t)b, (uint8_t)old); return compare_and_swap_8((uint8_t*)a, (uint8_t)b, (uint8_t)old);
} }
@ -206,7 +224,8 @@ typedef struct Cpu_Capabilities {
#define inline inline #define inline inline
#define COMPILER_HAS_MEMCPY_INTRINSICS 0 #define COMPILER_HAS_MEMCPY_INTRINSICS 0
inline u64 rdtsc() { return 0; } inline u64
rdtsc() { return 0; }
inline Cpu_Info_X86 cpuid(u32 function_id) {return (Cpu_Info_X86){0};} inline Cpu_Info_X86 cpuid(u32 function_id) {return (Cpu_Info_X86){0};}
#define COMPILER_CAN_DO_SSE2 0 #define COMPILER_CAN_DO_SSE2 0
#define COMPILER_CAN_DO_AVX 0 #define COMPILER_CAN_DO_AVX 0
@ -220,7 +239,8 @@ typedef struct Cpu_Capabilities {
#warning "Compiler is not explicitly supported, some things will probably not work as expected" #warning "Compiler is not explicitly supported, some things will probably not work as expected"
#endif #endif
Cpu_Capabilities query_cpu_capabilities() { Cpu_Capabilities
query_cpu_capabilities() {
Cpu_Capabilities result = {0}; Cpu_Capabilities result = {0};
Cpu_Info_X86 info = cpuid(1); Cpu_Info_X86 info = cpuid(1);

View file

@ -0,0 +1,41 @@
int entry(int argc, char **argv) {
window.title = STR("Audio test");
window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI)
window.scaled_height = 720;
window.x = 200;
window.y = 90;
window.clear_color = hex_to_rgba(0x6495EDff);
Allocator heap = get_heap_allocator();
Audio_Source bruh, song;
bool bruh_ok = audio_source_init_file_decode(&bruh, STR("oogabooga/examples/bruh.wav"), AUDIO_BITS_32, heap);
assert(bruh_ok, "Could not load bruh.wav");
bool song_ok = audio_source_init_file_stream(&song, STR("oogabooga/examples/song.ogg"), AUDIO_BITS_16, heap);
assert(bruh_ok, "Could not load song.ogg");
// #Temporary This is not actually how it will work, I'm just testing audio source output.
current_source = &song;
while (!window.should_close) {
reset_temporary_storage();
float64 now = os_get_current_time_in_seconds();
Matrix4 rect_xform = m4_scalar(1.0);
rect_xform = m4_rotate_z(rect_xform, (f32)now);
rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0));
draw_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN);
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
os_update();
gfx_update();
}
return 0;
}

Binary file not shown.

View file

@ -6,6 +6,10 @@
We also have log levels to be able to disable/enable the respective levels. We also have log levels to be able to disable/enable the respective levels.
BEWARE!!
This logger is not thread-safe. If multiple threads call log(), then nobody knows
what might happen. If you need to make it thread-safe, check out concurrency.c.
*/ */
// start all log levels enabled // start all log levels enabled

View file

@ -36,7 +36,7 @@ int entry(int argc, char **argv) {
Matrix4 camera_view = m4_scalar(1.0); Matrix4 camera_view = m4_scalar(1.0);
float64 last_time = os_get_current_time_in_seconds(); float64 last_time = os_get_current_time_in_seconds();
while (!window.should_close) tm_scope_cycles("Frame") { while (!window.should_close) tm_scope("Frame") {
reset_temporary_storage(); reset_temporary_storage();
float64 now = os_get_current_time_in_seconds(); float64 now = os_get_current_time_in_seconds();
@ -47,7 +47,7 @@ int entry(int argc, char **argv) {
delta = now - last_time; delta = now - last_time;
} }
last_time = now; last_time = now;
tm_scope_cycles("os_update") { tm_scope("os_update") {
os_update(); os_update();
} }
@ -134,7 +134,7 @@ int entry(int argc, char **argv) {
if (show) draw_image(atlas->image, v2(-1.6, -1), v2(4, 4), COLOR_WHITE); if (show) draw_image(atlas->image, v2(-1.6, -1), v2(4, 4), COLOR_WHITE);
tm_scope_cycles("gfx_update") { tm_scope("gfx_update") {
gfx_update(); gfx_update();
} }

View file

@ -14,7 +14,7 @@ int entry(int argc, char **argv) {
const u32 font_height = 48; const u32 font_height = 48;
while (!window.should_close) tm_scope_cycles("Frame") { while (!window.should_close) tm_scope("Frame") {
reset_temporary_storage(); reset_temporary_storage();
// Text is easiest to deal with if our projection matches window pixel size, because // Text is easiest to deal with if our projection matches window pixel size, because

View file

@ -6,6 +6,7 @@
#endif #endif
// #Cleanup apparently there are C macros for these (COBJMACROS)
#define D3D11Release(x) x->lpVtbl->Release(x) #define D3D11Release(x) x->lpVtbl->Release(x)
#define VTABLE(proc, ...) FIRST_ARG(__VA_ARGS__)->lpVtbl->proc(__VA_ARGS__) #define VTABLE(proc, ...) FIRST_ARG(__VA_ARGS__)->lpVtbl->proc(__VA_ARGS__)
@ -114,28 +115,30 @@ void CALLBACK d3d11_debug_callback(D3D11_MESSAGE_CATEGORY category, D3D11_MESSAG
#define win32_check_hr(hr) win32_check_hr_impl(hr, __LINE__, __FILE__); #define win32_check_hr(hr) win32_check_hr_impl(hr, __LINE__, __FILE__);
void win32_check_hr_impl(HRESULT hr, u32 line, const char* file_name) { void win32_check_hr_impl(HRESULT hr, u32 line, const char* file_name) {
if (FAILED(hr)) { if (hr != S_OK) {
LPVOID errorMsg; LPVOID errorMsg;
DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS; FORMAT_MESSAGE_IGNORE_INSERTS;
DWORD messageLength = FormatMessage( DWORD messageLength = FormatMessageW(
dwFlags, dwFlags,
NULL, NULL,
hr, hr,
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPTSTR) &errorMsg, (LPWSTR) &errorMsg,
0, 0,
NULL ); NULL );
if (messageLength > 0) { if (messageLength > 0) {
MessageBox(NULL, (LPCTSTR)errorMsg, TEXT("Error"), MB_OK | MB_ICONERROR); MessageBoxW(NULL, (LPWSTR)errorMsg, L"Error", MB_OK | MB_ICONERROR);
} else { } else {
MessageBox(NULL, TEXT("Failed to retrieve error message."), TEXT("Error"), MB_OK | MB_ICONERROR); MessageBoxW(NULL, L"Failed to retrieve error message.", L"Error", MB_OK | MB_ICONERROR);
} }
panic("win32 hr failed in file %cs on line %d", file_name, line);
panic("win32 hr failed in file %cs on line %d, hr was %d", file_name, line, hr);
} }
} }
@ -176,8 +179,8 @@ void d3d11_update_swapchain() {
// Obtain DXGI factory from device // Obtain DXGI factory from device
IDXGIDevice *dxgi_device; IDXGIDevice *dxgi_device = 0;
hr = VTABLE(QueryInterface, d3d11_device, &IID_IDXGIDevice, cast(void**)&dxgi_device); hr = ID3D11Device_QueryInterface(d3d11_device, &IID_IDXGIDevice, cast(void**)&dxgi_device);
win32_check_hr(hr); win32_check_hr(hr);
IDXGIAdapter *adapter; IDXGIAdapter *adapter;
@ -599,8 +602,8 @@ void d3d11_process_draw_frame() {
D3D11_Vertex* pointer = head; D3D11_Vertex* pointer = head;
u64 number_of_rendered_quads = 0; u64 number_of_rendered_quads = 0;
tm_scope_cycles("Quad processing") { tm_scope("Quad processing") {
if (draw_frame.enable_z_sorting) tm_scope_cycles("Z sorting") { if (draw_frame.enable_z_sorting) tm_scope("Z sorting") {
if (!sort_quad_buffer || (sort_quad_buffer_size < allocated_quads*sizeof(Draw_Quad))) { if (!sort_quad_buffer || (sort_quad_buffer_size < allocated_quads*sizeof(Draw_Quad))) {
// #Memory #Heapalloc // #Memory #Heapalloc
if (sort_quad_buffer) dealloc(get_heap_allocator(), sort_quad_buffer); if (sort_quad_buffer) dealloc(get_heap_allocator(), sort_quad_buffer);
@ -721,23 +724,23 @@ void d3d11_process_draw_frame() {
} }
} }
tm_scope_cycles("Write to gpu") { tm_scope("Write to gpu") {
D3D11_MAPPED_SUBRESOURCE buffer_mapping; D3D11_MAPPED_SUBRESOURCE buffer_mapping;
tm_scope_cycles("The Map call") { tm_scope("The Map call") {
hr = VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_DISCARD, 0, &buffer_mapping); hr = VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_DISCARD, 0, &buffer_mapping);
win32_check_hr(hr); win32_check_hr(hr);
} }
tm_scope_cycles("The memcpy") { tm_scope("The memcpy") {
memcpy(buffer_mapping.pData, d3d11_staging_quad_buffer, number_of_rendered_quads*sizeof(D3D11_Vertex)*6); memcpy(buffer_mapping.pData, d3d11_staging_quad_buffer, number_of_rendered_quads*sizeof(D3D11_Vertex)*6);
} }
tm_scope_cycles("The Unmap call") { tm_scope("The Unmap call") {
VTABLE(Unmap, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0); VTABLE(Unmap, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0);
} }
} }
/// ///
// Draw call // Draw call
tm_scope_cycles("Draw call") d3d11_draw_call(number_of_rendered_quads, textures, num_textures); tm_scope("Draw call") d3d11_draw_call(number_of_rendered_quads, textures, num_textures);
} }
reset_draw_frame(&draw_frame); reset_draw_frame(&draw_frame);
@ -762,7 +765,7 @@ void gfx_update() {
d3d11_process_draw_frame(); d3d11_process_draw_frame();
tm_scope_cycles("Present") { tm_scope("Present") {
VTABLE(Present, d3d11_swap_chain, window.enable_vsync, window.enable_vsync ? 0 : DXGI_PRESENT_ALLOW_TEARING); VTABLE(Present, d3d11_swap_chain, window.enable_vsync, window.enable_vsync ? 0 : DXGI_PRESENT_ALLOW_TEARING);
} }

View file

@ -98,16 +98,16 @@
Note: Note:
See timing macros in profile.c See timing macros in profile.c
tm_scope_cycles tm_scope
tm_scope_cycles_var tm_scope_var
tm_scope_cycles_accum tm_scope_accum
*/ */
#define OGB_VERSION_MAJOR 0 #define OGB_VERSION_MAJOR 0
#define OGB_VERSION_MINOR 0 #define OGB_VERSION_MINOR 1
#define OGB_VERSION_PATCH 5 #define OGB_VERSION_PATCH 0
#define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH) #define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH)
@ -212,6 +212,7 @@ typedef u8 bool;
#define MACOS 2 #define MACOS 2
#ifdef _WIN32 #ifdef _WIN32
#define COBJMACROS
#include <Windows.h> #include <Windows.h>
#define TARGET_OS WINDOWS #define TARGET_OS WINDOWS
#define OS_PATHS_HAVE_BACKSLASH 1 #define OS_PATHS_HAVE_BACKSLASH 1
@ -314,6 +315,26 @@ typedef u8 bool;
#define malloc please_use_alloc_for_memory_allocations_instead_of_malloc #define malloc please_use_alloc_for_memory_allocations_instead_of_malloc
#define free please_use_dealloc_for_memory_deallocations_instead_of_free #define free please_use_dealloc_for_memory_deallocations_instead_of_free
Mutex _default_logger_mutex;
bool _default_logger_mutex_initted = false;
void default_logger(Log_Level level, string s) {
if (!_default_logger_mutex_initted) {
mutex_init(&_default_logger_mutex);
_default_logger_mutex_initted = true;
}
mutex_acquire_or_wait(&_default_logger_mutex);
switch (level) {
case LOG_VERBOSE: print("[VERBOSE]: %s\n", s); break;
case LOG_INFO: print("[INFO]: %s\n", s); break;
case LOG_WARNING: print("[WARNING]: %s\n", s); break;
case LOG_ERROR: print("[ERROR]: %s\n", s); break;
case LOG_LEVEL_COUNT: break;
}
mutex_release(&_default_logger_mutex);
}
void oogabooga_init(u64 program_memory_size) { void oogabooga_init(u64 program_memory_size) {
context.logger = default_logger; context.logger = default_logger;
temp = get_initialization_allocator(); temp = get_initialization_allocator();

View file

@ -1,5 +1,11 @@
#define CINTERFACE
#include <Shlwapi.h> #include <Shlwapi.h>
#include <audioclient.h>
#include <audiopolicy.h>
#include <mmdeviceapi.h>
#include <initguid.h>
#include <avrt.h>
#define VIRTUAL_MEMORY_BASE ((void*)0x0000690000000000ULL) #define VIRTUAL_MEMORY_BASE ((void*)0x0000690000000000ULL)
@ -132,12 +138,72 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
return 0; return 0;
} }
void win32_audio_thread(Thread *t);
void
win32_audio_init();
void win32_init_window() {
memset(&window, 0, sizeof(window));
window.title = STR("Unnamed Window");
window.width = 1280;
window.height = 720;
window.x = 0;
window.y = 0;
window.should_close = false;
window._initialized = false;
window.clear_color.r = 0.392f;
window.clear_color.g = 0.584f;
window.clear_color.b = 0.929f;
window.clear_color.a = 1.0f;
WNDCLASSEX wc = (WNDCLASSEX){0};
MSG msg;
HINSTANCE instance = GetModuleHandle(0);
assert(instance != INVALID_HANDLE_VALUE, "Failed getting current HINSTANCE");
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_OWNDC;
wc.lpfnWndProc = win32_window_proc;
wc.hInstance = instance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = "sigma balls";
wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
BOOL ok = RegisterClassEx(&wc);
assert(ok, "Failed registering window class (error code %lu)", GetLastError());
RECT rect = {0, 0, window.width, window.height};
DWORD style = WS_OVERLAPPEDWINDOW;
DWORD ex_style = WS_EX_CLIENTEDGE;
ok = AdjustWindowRectEx(&rect, style, FALSE, ex_style);
assert(ok != 0, "AdjustWindowRectEx failed with error code %lu", GetLastError());
u32 actual_window_width = rect.right - rect.left;
u32 actual_window_height = rect.bottom - rect.top;
// Create the window
window._os_handle = CreateWindowEx(
ex_style,
"sigma balls",
temp_convert_to_null_terminated_string(window.title),
style,
CW_USEDEFAULT, CW_USEDEFAULT, actual_window_width, actual_window_height,
0, 0, instance, 0);
assert(window._os_handle != 0, "Window creation failed, error: %lu", GetLastError());
window._initialized = true;
ShowWindow(window._os_handle, SW_SHOWDEFAULT);
UpdateWindow(window._os_handle);
}
void os_init(u64 program_memory_size) { void os_init(u64 program_memory_size) {
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
win32_check_hr(hr);
context.thread_id = GetCurrentThreadId(); context.thread_id = GetCurrentThreadId();
memset(&window, 0, sizeof(window));
#if CONFIGURATION == RELEASE #if CONFIGURATION == RELEASE
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
@ -159,7 +225,7 @@ void os_init(u64 program_memory_size) {
unsigned char* addr = 0; unsigned char* addr = 0;
while (VirtualQuery(addr, &mbi, sizeof(mbi))) { while (VirtualQuery(addr, &mbi, sizeof(mbi))) {
if (mbi.Type == MEM_IMAGE) { if (mbi.Type == MEM_IMAGE) {
if (os.static_memory_start == NULL) { if (os.static_memory_start == 0) {
os.static_memory_start = mbi.BaseAddress; os.static_memory_start = mbi.BaseAddress;
} }
os.static_memory_end = (unsigned char*)mbi.BaseAddress + mbi.RegionSize; os.static_memory_end = (unsigned char*)mbi.BaseAddress + mbi.RegionSize;
@ -171,7 +237,6 @@ void os_init(u64 program_memory_size) {
program_memory_mutex = os_make_mutex(); program_memory_mutex = os_make_mutex();
os_grow_program_memory(program_memory_size); os_grow_program_memory(program_memory_size);
heap_init(); heap_init();
os.crt = os_load_dynamic_library(STR("msvcrt.dll")); os.crt = os_load_dynamic_library(STR("msvcrt.dll"));
@ -189,61 +254,8 @@ void os_init(u64 program_memory_size) {
os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, STR("memset")); os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, STR("memset"));
assert(os.crt_memset, "Missing memset in crt"); assert(os.crt_memset, "Missing memset in crt");
window.title = STR("Unnamed Window"); win32_init_window();
window.width = 1280; os_start_thread(os_make_thread(win32_audio_thread, get_heap_allocator()));
window.height = 720;
window.x = 0;
window.y = 0;
window.should_close = false;
window._initialized = false;
window.clear_color.r = 0.392f;
window.clear_color.g = 0.584f;
window.clear_color.b = 0.929f;
window.clear_color.a = 1.0f;
WNDCLASSEX wc = (WNDCLASSEX){0};
MSG msg;
HINSTANCE instance = GetModuleHandle(NULL);
assert(instance != INVALID_HANDLE_VALUE, "Failed getting current HINSTANCE");
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_OWNDC;
wc.lpfnWndProc = win32_window_proc;
wc.hInstance = instance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = "sigma balls";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
BOOL ok = RegisterClassEx(&wc);
assert(ok, "Failed registering window class (error code %lu)", GetLastError());
RECT rect = {0, 0, window.width, window.height};
DWORD style = WS_OVERLAPPEDWINDOW;
DWORD ex_style = WS_EX_CLIENTEDGE;
ok = AdjustWindowRectEx(&rect, style, FALSE, ex_style);
assert(ok != 0, "AdjustWindowRectEx failed with error code %lu", GetLastError());
u32 actual_window_width = rect.right - rect.left;
u32 actual_window_height = rect.bottom - rect.top;
// Create the window
window._os_handle = CreateWindowEx(
ex_style,
"sigma balls",
temp_convert_to_null_terminated_string(window.title),
style,
CW_USEDEFAULT, CW_USEDEFAULT, actual_window_width, actual_window_height,
NULL, NULL, instance, NULL);
assert(window._os_handle != NULL, "Window creation failed, error: %lu", GetLastError());
window._initialized = true;
ShowWindow(window._os_handle, SW_SHOWDEFAULT);
UpdateWindow(window._os_handle);
} }
void s64_to_null_terminated_string_reverse(char str[], int length) void s64_to_null_terminated_string_reverse(char str[], int length)
@ -573,7 +585,7 @@ void os_write_string_to_stdout(string s) {
HANDLE win32_stdout = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE win32_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (win32_stdout == INVALID_HANDLE_VALUE) return; if (win32_stdout == INVALID_HANDLE_VALUE) return;
WriteFile(win32_stdout, s.data, s.count, 0, NULL); WriteFile(win32_stdout, s.data, s.count, 0, 0);
} }
u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator) { u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator) {
@ -591,7 +603,7 @@ u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator)
int result = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)utf8.data, (int)utf8.count, utf16_str, utf16_length); int result = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)utf8.data, (int)utf8.count, utf16_str, utf16_length);
if (result == 0) { if (result == 0) {
dealloc(allocator, utf16_str); dealloc(allocator, utf16_str);
return NULL; return 0;
} }
utf16_str[utf16_length] = 0; utf16_str[utf16_length] = 0;
@ -646,7 +658,7 @@ File os_file_open_s(string path, Os_Io_Open_Flags flags) {
u16 *wide = temp_win32_fixed_utf8_to_null_terminated_wide(path); u16 *wide = temp_win32_fixed_utf8_to_null_terminated_wide(path);
return CreateFileW(wide, access, FILE_SHARE_READ, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); return CreateFileW(wide, access, FILE_SHARE_READ, 0, creation, FILE_ATTRIBUTE_NORMAL, 0);
} }
void os_file_close(File f) { void os_file_close(File f) {
@ -672,7 +684,7 @@ bool os_make_directory_s(string path, bool recursive) {
wchar_t *sep = wcschr(wide_path + 1, L'\\'); wchar_t *sep = wcschr(wide_path + 1, L'\\');
while (sep) { while (sep) {
*sep = 0; *sep = 0;
if (!CreateDirectoryW(wide_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { if (!CreateDirectoryW(wide_path, 0) && GetLastError() != ERROR_ALREADY_EXISTS) {
return false; return false;
} }
*sep = L'\\'; *sep = L'\\';
@ -680,7 +692,7 @@ bool os_make_directory_s(string path, bool recursive) {
} }
} }
if (!CreateDirectoryW(wide_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { if (!CreateDirectoryW(wide_path, 0) && GetLastError() != ERROR_ALREADY_EXISTS) {
return false; return false;
} }
@ -733,19 +745,19 @@ bool os_delete_directory_s(string path, bool recursive) {
bool os_file_write_string(File f, string s) { bool os_file_write_string(File f, string s) {
DWORD written; DWORD written;
BOOL result = WriteFile(f, s.data, s.count, &written, NULL); BOOL result = WriteFile(f, s.data, s.count, &written, 0);
return result && (written == s.count); return result && (written == s.count);
} }
bool os_file_write_bytes(File f, void *buffer, u64 size_in_bytes) { bool os_file_write_bytes(File f, void *buffer, u64 size_in_bytes) {
DWORD written; DWORD written;
BOOL result = WriteFile(f, buffer, (DWORD)size_in_bytes, &written, NULL); BOOL result = WriteFile(f, buffer, (DWORD)size_in_bytes, &written, 0);
return result && (written == size_in_bytes); return result && (written == size_in_bytes);
} }
bool os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_bytes) { bool os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_bytes) {
DWORD read; DWORD read;
BOOL result = ReadFile(f, buffer, (DWORD)bytes_to_read, &read, NULL); BOOL result = ReadFile(f, buffer, (DWORD)bytes_to_read, &read, 0);
if (actual_read_bytes) { if (actual_read_bytes) {
*actual_read_bytes = read; *actual_read_bytes = read;
} }
@ -799,7 +811,7 @@ bool os_read_entire_file_s(string path, string *result, Allocator allocator) {
bool os_is_file_s(string path) { bool os_is_file_s(string path) {
u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path); u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path);
assert(path_wide, "Invalid path string"); assert(path_wide, "Invalid path string");
if (path_wide == NULL) { if (path_wide == 0) {
return false; return false;
} }
@ -815,7 +827,7 @@ bool os_is_file_s(string path) {
bool os_is_directory_s(string path) { bool os_is_directory_s(string path) {
u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path); u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path);
assert(path_wide, "Invalid path string"); assert(path_wide, "Invalid path string");
if (path_wide == NULL) { if (path_wide == 0) {
return false; return false;
} }
@ -901,10 +913,10 @@ bool os_do_paths_match(string a, string b) {
wchar_t full_path_b[MAX_PATH]; wchar_t full_path_b[MAX_PATH];
// Get the full path for both paths // Get the full path for both paths
if (!GetFullPathNameW(wide_path_a, MAX_PATH, full_path_a, NULL)) { if (!GetFullPathNameW(wide_path_a, MAX_PATH, full_path_a, 0)) {
return false; return false;
} }
if (!GetFullPathNameW(wide_path_b, MAX_PATH, full_path_b, NULL)) { if (!GetFullPathNameW(wide_path_b, MAX_PATH, full_path_b, 0)) {
return false; return false;
} }
@ -950,9 +962,270 @@ void* os_get_stack_limit() {
return tib->StackLimit; return tib->StackLimit;
} }
// Actually fuck you bill gates
const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}};
const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}};
const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}};
const GUID IID_IAudioRenderClient = {0xf294acfc, 0x3146, 0x4483, {0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2}};
DEFINE_GUID(IID_ISimpleAudioVolume,
0x87CE5498, 0x68D6, 0x44E5, 0x92, 0x15, 0x6D, 0xA4, 0x7E, 0xF8, 0x83, 0xD8);
IAudioClient* win32_audio_client;
IAudioRenderClient* win32_render_client;
bool win32_audio_deactivated = false;
Audio_Format win32_output_format;
IMMDevice* win32_audio_device = 0;
IMMDeviceEnumerator* win32_device_enumerator = 0;
ISimpleAudioVolume* win32_audio_volume = 0;
void
win32_audio_init() {
win32_audio_client = 0;
win32_render_client = 0;
win32_audio_deactivated = 0;
win32_audio_device = 0;
win32_device_enumerator = 0;
HRESULT hr;
WAVEFORMATEX* device_base_format = 0;
WAVEFORMATEX* output_format = 0;
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void**)&win32_device_enumerator);
win32_check_hr(hr);
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(win32_device_enumerator, eRender, eConsole, &win32_audio_device);
win32_check_hr(hr);
hr = IMMDevice_Activate(
win32_audio_device,
&IID_IAudioClient,
CLSCTX_ALL, 0,
(void**)&win32_audio_client
);
win32_check_hr(hr);
hr = IAudioClient_GetMixFormat(win32_audio_client, &device_base_format);
WAVEFORMATEXTENSIBLE *format_f32
= (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
WAVEFORMATEXTENSIBLE *format_s16
= (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(format_f32, device_base_format, sizeof(WAVEFORMATEX));
format_f32->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
format_f32->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
format_f32->Samples.wValidBitsPerSample = format_f32->Format.wBitsPerSample;
format_f32->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
memcpy(format_s16, format_f32, sizeof(WAVEFORMATEXTENSIBLE));
format_f32->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
format_f32->Format.wBitsPerSample = 32;
format_f32->Format.nBlockAlign
= format_f32->Format.nChannels * format_f32->Format.wBitsPerSample / 8;
format_f32->Format.nAvgBytesPerSec
= format_f32->Format.nSamplesPerSec * format_f32->Format.nBlockAlign;
format_s16->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
format_s16->Format.wBitsPerSample = 16;
format_s16->Format.nBlockAlign = format_s16->Format.nChannels * format_s16->Format.wBitsPerSample / 8;
format_s16->Format.nAvgBytesPerSec = format_s16->Format.nSamplesPerSec * format_s16->Format.nBlockAlign;
// First look for f32 support
WAVEFORMATEX *closest_match = NULL;
hr = IAudioClient_IsFormatSupported(
win32_audio_client,
AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX *)format_f32,
&closest_match
);
// If f32 fails, look for s16
if (hr != S_OK) {
hr = IAudioClient_IsFormatSupported(
win32_audio_client,
AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX *)format_s16,
&closest_match
);
if (hr != S_OK) {
win32_audio_deactivated = true;
log_error("Default audio output device is not supported.");
return;
}
output_format = (WAVEFORMATEX*)format_s16;
} else {
output_format = (WAVEFORMATEX*)format_f32;
}
const s64 BUFFER_DURATION_MS = 40;
hr = IAudioClient_Initialize(
win32_audio_client,
AUDCLNT_SHAREMODE_SHARED,
0,
BUFFER_DURATION_MS*10000ll, 0,
output_format, 0
);
win32_check_hr(hr);
hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client);
win32_check_hr(hr);
win32_output_format.channels = output_format->nChannels;
win32_output_format.sample_rate = output_format->nSamplesPerSec;
if (output_format == (WAVEFORMATEX*)format_s16) {
win32_output_format.bit_width = AUDIO_BITS_16;
} else if (output_format == (WAVEFORMATEX*)format_f32) {
win32_output_format.bit_width = AUDIO_BITS_32;
} else {
panic("What");
}
DWORD task_index;
AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &task_index);
hr = IAudioClient_GetService(win32_audio_client, &IID_ISimpleAudioVolume, (void**)&win32_audio_volume);
if (SUCCEEDED(hr)) {
hr = ISimpleAudioVolume_SetMasterVolume(win32_audio_volume, 1.0f, 0);
win32_check_hr(hr);
ISimpleAudioVolume_Release(win32_audio_volume);
}
log_info("Successfully initialized default audio device. Channels: %d, sample_rate: %d, bits: %d", win32_output_format.channels, win32_output_format.sample_rate, get_audio_bit_width_byte_size(win32_output_format.bit_width)*8);
}
void
win32_audio_thread(Thread *t) {
win32_audio_init();
timeBeginPeriod(1);
u32 buffer_frame_count;
HRESULT hr = IAudioClient_GetBufferSize(win32_audio_client, &buffer_frame_count);
if (FAILED(hr)) win32_audio_deactivated = true;
bool started = false;
while (!window.should_close) tm_scope("Audio update") {
if (win32_audio_deactivated) tm_scope("Retry audio device") {
os_sleep(100);
win32_audio_init();
started = false;
if (win32_audio_deactivated) {
hr = IAudioClient_GetBufferSize(win32_audio_client, &buffer_frame_count);
if (FAILED(hr)) win32_audio_deactivated = true;
}
continue;
}
// We gotta check if there is a new default endpoint (#Speed ?)
IMMDevice *now_default = 0;
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(win32_device_enumerator, eRender, eConsole, &now_default);
win32_check_hr(hr);
WCHAR *now_default_id = NULL;
hr = IMMDevice_GetId(now_default, &now_default_id);
win32_check_hr(hr);
WCHAR *previous_id = NULL;
hr = IMMDevice_GetId(win32_audio_device, &previous_id);
win32_check_hr(hr);
if (wcscmp(now_default_id, previous_id) != 0) {
win32_audio_deactivated = true;
}
CoTaskMemFree(now_default_id);
CoTaskMemFree(previous_id);
IMMDevice_Release(now_default);
if (win32_audio_deactivated) continue;
BYTE *buffer = 0;
u32 num_frames_available = 0;
hr = IAudioClient_GetCurrentPadding(win32_audio_client, &num_frames_available);
if (FAILED(hr)) {
win32_audio_deactivated = true;
continue;
}
u32 num_frames_to_write = buffer_frame_count - num_frames_available;
if (!started) {
hr = IAudioClient_Start(win32_audio_client);
win32_check_hr(hr);
started = true;
}
while (num_frames_to_write == 0) tm_scope("Chill") {
// We yield & sleep until we have any work to do
os_yield_thread();
os_sleep(1);
hr = IAudioClient_GetCurrentPadding(win32_audio_client, &num_frames_available);
if (FAILED(hr)) {
win32_audio_deactivated = true;
break;
}
num_frames_to_write = buffer_frame_count - num_frames_available;
}
if (win32_audio_deactivated) continue;
if (num_frames_to_write > 0) tm_scope("Output frames") {
hr = IAudioRenderClient_GetBuffer(
win32_render_client,
num_frames_to_write,
&buffer
);
if (FAILED(hr)) {
win32_audio_deactivated = true;
continue;
}
do_program_audio_sample(num_frames_to_write, win32_output_format, buffer);
//f32 s = 0.5;
//for (u32 i = 0; i < num_frames_to_write * win32_output_format.channels; ++i) {
// ((f32*)buffer)[i] = s;
//}
/*float64 time = 0;
float *fbuffer = (float *)buffer;
for (UINT32 frameIndex = 0; frameIndex < num_frames_to_write; frameIndex++) {
float amplitude = (float)(sin(time)*0.2);
*fbuffer++ = amplitude; // left
*fbuffer++ = amplitude; // right
time += 0.05;
}*/
//for (u64 i = 0; i < num_frames_to_write; i++) {
// f32 s = *(((f32*)buffer)+i*win32_output_format.channels);
// print("%f ", s);
//}
hr = IAudioRenderClient_ReleaseBuffer(
win32_render_client,
num_frames_to_write,
0
);
if (FAILED(hr)) {
win32_audio_deactivated = true;
continue;
}
}
}
}
void os_update() { void os_update() {
@ -989,7 +1262,7 @@ void os_update() {
u32 actual_x = update_rect.left; u32 actual_x = update_rect.left;
u32 actual_y = screen_height - update_rect.top - (update_rect.bottom - update_rect.top); u32 actual_y = screen_height - update_rect.top - (update_rect.bottom - update_rect.top);
SetWindowPos(window._os_handle, NULL, actual_x, actual_y, actual_width, actual_height, SWP_NOZORDER | SWP_NOACTIVATE); SetWindowPos(window._os_handle, 0, actual_x, actual_y, actual_width, actual_height, SWP_NOZORDER | SWP_NOACTIVATE);
} }
RECT client_rect; RECT client_rect;
@ -1050,7 +1323,7 @@ void os_update() {
MSG msg; MSG msg;
while (input_frame.number_of_events < MAX_EVENTS_PER_FRAME while (input_frame.number_of_events < MAX_EVENTS_PER_FRAME
&& PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) { if (msg.message == WM_QUIT) {
window.should_close = true; window.should_close = true;
break; break;

View file

@ -101,6 +101,7 @@ typedef struct Thread {
/// ///
// Thread primitive // Thread primitive
// #Cleanup this shouldn't be allocating just for the pointer!! Just do os_thread_init(*)
Thread* os_make_thread(Thread_Proc proc, Allocator allocator); Thread* os_make_thread(Thread_Proc proc, Allocator allocator);
void os_destroy_thread(Thread *t); void os_destroy_thread(Thread *t);
void os_start_thread(Thread* t); void os_start_thread(Thread* t);

View file

@ -29,20 +29,20 @@ void _profiler_report_time_cycles(string name, u64 count, u64 start) {
spinlock_release(&_profiler_lock); spinlock_release(&_profiler_lock);
} }
#if ENABLE_PROFILING #if ENABLE_PROFILING
#define tm_scope_cycles(name) \ #define tm_scope(name) \
for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \ for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \
elapsed_time == 0; \ elapsed_time == 0; \
elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, _profiler_report_time_cycles(STR(name), elapsed_time, start_time)) elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, _profiler_report_time_cycles(STR(name), elapsed_time, start_time))
#define tm_scope_cycles_var(name, var) \ #define tm_scope_var(name, var) \
for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \ for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \
elapsed_time == 0; \ elapsed_time == 0; \
elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, var=elapsed_time) elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, var=elapsed_time)
#define tm_scope_cycles_accum(name, var) \ #define tm_scope_accum(name, var) \
for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \ for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \
elapsed_time == 0; \ elapsed_time == 0; \
elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, var+=elapsed_time) elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, var+=elapsed_time)
#else #else
#define tm_scope_cycles(...) #define tm_scope(...)
#define tm_scope_cycles_var(...) #define tm_scope_var(...)
#define tm_scope_cycles_accum(...) #define tm_scope_accum(...)
#endif #endif

View file

@ -223,16 +223,6 @@ typedef void(*Logger_Proc)(Log_Level level, string s);
#define log(...) LOG_BASE(LOG_INFO, __VA_ARGS__) #define log(...) LOG_BASE(LOG_INFO, __VA_ARGS__)
void default_logger(Log_Level level, string s) {
switch (level) {
case LOG_VERBOSE: print("[VERBOSE]: %s\n", s); break;
case LOG_INFO: print("[INFO]: %s\n", s); break;
case LOG_WARNING: print("[WARNING]: %s\n", s); break;
case LOG_ERROR: print("[ERROR]: %s\n", s); break;
case LOG_LEVEL_COUNT: break;
}
}
typedef struct String_Builder { typedef struct String_Builder {
union { union {