v0.01.000 - AUDIO!

This commit is contained in:
Charlie 2024-07-15 21:40:27 +02:00
parent 2b335aee35
commit c39902d6b1
23 changed files with 1987 additions and 9198 deletions

30
TODO
View file

@ -1,5 +1,33 @@
- Audio - Audio
- Player volume control
- Optimize - Optimize
- Spam simd - Spam simd
- Concurrent jobs for players? - Concurrent jobs for players?
- Mega buffer for contiguous intermediate buffers
We definitely also want a limit to how much memory we want allocated to intermediate buffers.
- Avoid playing identical audio at the same time
- Custom audio mixing
- Fix vorbis >FILE< streaming (#StbVorbisFileStream)
- Handle audio sources which had their format defaulted to update when default device changes
For streamed audio sources this should be easy enough, because the conversion happens from raw format to source format as we stream it.
For loaded sources though, we would need to convert the source->pcm_frames.
- Bugs:
- Small fadeout on pause is slightly noisy
- Setting time stamp/progression causes noise (need fade transition like on pause/play)
- End of clip also causes noise if audio clip does not end smoothly
- Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise.
- 24-Bit audio conversion doesn't really work
- Juice
- draw_line
- vx_length
- Occlude quads out of view
- General bugs & issues
- Release freeze in run_tests
- Needs testing:
- Audio format channel conversions
- sample rate downsampling
- non stereo or mono audio

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 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -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 -ldbghelp -femit-all-decls
popd popd

10
build.c
View file

@ -3,8 +3,6 @@
/// ///
// 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 {
@ -14,7 +12,7 @@ typedef struct Context_Extra {
#define CONTEXT_EXTRA Context_Extra #define CONTEXT_EXTRA Context_Extra
// This defaults to "entry", but we can set it to anything (except "main" or other existing proc names" // This defaults to "entry", but we can set it to anything (except "main" or other existing proc names"
#define ENTRY_PROC entry #define ENTRY_PROC entry
// Ooga booga needs to be included AFTER configuration and BEFORE the program code // Ooga booga needs to be included AFTER configuration and BEFORE the program code
#include "oogabooga/oogabooga.c" #include "oogabooga/oogabooga.c"
@ -27,14 +25,14 @@ typedef struct Context_Extra {
// Comment & Uncomment these to swap projects (only include one at a time) // Comment & Uncomment these to swap projects (only include one at a time)
// //
// 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" // #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

@ -1,19 +1,50 @@
## v0.01.001 - AUDIO! ## v0.01.000 - AUDIO!
- Added audio sources - Added audio sources
- File stream sources & Fully decoded sources - File stream sources & Fully decoded sources
- 16-bit int & 32-bit float support - 16-bit int & 32-bit float support
- WAV & OGG support - WAV & OGG support (in-house wav decoder, stb_vorbis for ogg)
- Usage: - Usage:
bool audio_source_init_file_stream(*src, path, bit_width, allocator) bool audio_open_source_stream(*src, path, allocator)
bool audio_source_init_file_decode(*src, path, bit_width, allocator) bool audio_open_source_load(*src, path, allocator)
void audio_source_destroy(*src) void audio_source_destroy(*src)
- Added audio playback
- The simple way:
play_one_audio_clip_source(source);
play_one_audio_clip(path);
- With Audio_Player:
audio_player_get_one();
audio_player_release(*player);
audio_player_set_state(*player, state);
audio_player_set_time_stamp(*player, time_in_seconds);
audio_player_set_progression_factor(*player, factor);
audio_player_get_time_stamp(*player);
audio_player_get_current_progression_factor(*player);
audio_player_set_source(*player, src, bool retain_progression_factor);
audio_player_clear_source(*player);
audio_player_set_looping(*player, bool looping);
- Added some basic features in the audio system
- Conversion & resampling between audio formats
- Automatically detects new default device
- Small fade in pause/play for less noise from sudden changes in playback buffer
- Added a audio_test.c example
- More OS procuedres
- os_file_set_pos(file, pos)
- os_file_get_pos(file)
- os_file_get_size(file)
- os_get_stack_trace(allocator)
- Misc - Misc
- Win32 audio impl - Win32 audio impl
- Link to more win32 junk
- Make default logger thread safe - Make default logger thread safe
- Rename tm_scope_cycles & tm_scope_cycles_xxx -> tm_scope & tm_scope_xxx - Rename tm_scope_cycles & tm_scope_cycles_xxx -> tm_scope & tm_scope_xxx
- Minor cleanups - Minor cleanups
- Fix Vector types align woopsies
- Fix bug in heap allocator which caused internal heap corruption
- Maybe fixed spinlocks with memory barriers?
- Bunch of more asserts & better detection for heap allocation issues
- lerpf, lerpi, smerpf, smerpi
- Failed asserts now prints the stack trace.
## v0.00.005 - Z layers ## v0.00.005 - Z layers

File diff suppressed because it is too large Load diff

View file

@ -5,12 +5,15 @@
#define forward_global extern #define forward_global extern
#define alignas _Alignas
#define null 0 #define null 0
void printf(const char* fmt, ...); void printf(const char* fmt, ...);
void dump_stack_trace();
#define ASSERT_STR_HELPER(x) #x #define ASSERT_STR_HELPER(x) #x
#define ASSERT_STR(x) ASSERT_STR_HELPER(x) #define ASSERT_STR(x) ASSERT_STR_HELPER(x)
#define assert_line(line, cond, ...) {if(!(cond)) { printf("Assertion failed in file " __FILE__ " on line " ASSERT_STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); crash(); }} #define assert_line(line, cond, ...) {if(!(cond)) { printf("Assertion failed in file " __FILE__ " on line " ASSERT_STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); dump_stack_trace(); crash(); }}
#define assert(cond, ...) {assert_line(__LINE__, cond, __VA_ARGS__)} #define assert(cond, ...) {assert_line(__LINE__, cond, __VA_ARGS__)}
#define DEFER(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end)) #define DEFER(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end))
@ -93,6 +96,7 @@ forward_global thread_local Allocator temp;
void* memset(void* dest, int value, size_t amount); void* memset(void* dest, int value, size_t amount);
void* alloc(Allocator allocator, u64 size) { void* alloc(Allocator allocator, u64 size) {
assert(size > 0, "You requested an allocation of zero bytes. I'm not sure what you want with that.");
void *p = allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data); void *p = allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data);
#if DO_ZERO_INITIALIZATION #if DO_ZERO_INITIALIZATION
memset(p, 0, size); memset(p, 0, size);
@ -100,9 +104,11 @@ void* alloc(Allocator allocator, u64 size) {
return p; return p;
} }
void* alloc_uninitialized(Allocator allocator, u64 size) { void* alloc_uninitialized(Allocator allocator, u64 size) {
assert(size > 0, "You requested an allocation of zero bytes. I'm not sure what you want with that.");
return allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data); return allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data);
} }
void dealloc(Allocator allocator, void *p) { void dealloc(Allocator allocator, void *p) {
assert(p != 0, "You tried to deallocate a pointer at adress 0. That doesn't make sense!");
allocator.proc(0, p, ALLOCATOR_DEALLOCATE, allocator.data); allocator.proc(0, p, ALLOCATOR_DEALLOCATE, allocator.data);
} }

View file

@ -46,13 +46,16 @@ void spinlock_init(Spinlock *l) {
void spinlock_acquire_or_wait(Spinlock* l) { void spinlock_acquire_or_wait(Spinlock* l) {
while (true) { while (true) {
bool expected = false; bool expected = false;
MEMORY_BARRIER;
if (compare_and_swap_bool(&l->locked, true, expected)) { if (compare_and_swap_bool(&l->locked, true, expected)) {
MEMORY_BARRIER; MEMORY_BARRIER;
return; return;
} }
while (l->locked) { while (l->locked) {
// spinny boi // spinny boi
MEMORY_BARRIER;
} }
MEMORY_BARRIER;
} }
} }
// Returns true on aquired, false if timeout seconds reached // Returns true on aquired, false if timeout seconds reached
@ -60,6 +63,7 @@ bool spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds) {
f64 start = os_get_current_time_in_seconds(); f64 start = os_get_current_time_in_seconds();
while (true) { while (true) {
bool expected = false; bool expected = false;
MEMORY_BARRIER;
if (compare_and_swap_bool(&l->locked, true, expected)) { if (compare_and_swap_bool(&l->locked, true, expected)) {
MEMORY_BARRIER; MEMORY_BARRIER;
return true; return true;
@ -67,15 +71,17 @@ bool spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds) {
while (l->locked) { while (l->locked) {
// spinny boi // spinny boi
if ((os_get_current_time_in_seconds()-start) >= timeout_seconds) return false; if ((os_get_current_time_in_seconds()-start) >= timeout_seconds) return false;
MEMORY_BARRIER;
} }
} }
return true; return true;
} }
void spinlock_release(Spinlock* l) { void spinlock_release(Spinlock* l) {
bool expected = true; bool expected = true;
bool success = compare_and_swap_bool(&l->locked, false, expected);
assert(success, "This thread should have acquired the spinlock but compare_and_swap failed");
MEMORY_BARRIER; MEMORY_BARRIER;
bool success = compare_and_swap_bool(&l->locked, false, expected);
MEMORY_BARRIER;
assert(success, "This thread should have acquired the spinlock but compare_and_swap failed");
} }

View file

@ -48,6 +48,12 @@ Usage:
API: API:
// !! IMPORTANT
// The Draw_Quad* returned from draw procedures is a temporary pointer and may be
// invalid after the next draw_xxxx call. This is because quads are stored in a
// resizing buffer (because that gave us a non-trivial performance boost).
// So the purpose of returning them is to customize the quad right after the draw proc.
Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip); Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip);
Draw_Quad *draw_quad(Draw_Quad quad); Draw_Quad *draw_quad(Draw_Quad quad);
Draw_Quad *draw_quad_xform(Draw_Quad quad, Matrix4 xform); Draw_Quad *draw_quad_xform(Draw_Quad quad, Matrix4 xform);
@ -62,7 +68,7 @@ Usage:
*/ */
// We use radix sort so the exact bit count is of important // We use radix sort so the exact bit count is of importance
#define MAX_Z_BITS 21 #define MAX_Z_BITS 21
#define MAX_Z ((1 << MAX_Z_BITS)/2) #define MAX_Z ((1 << MAX_Z_BITS)/2)
#define Z_STACK_MAX 4096 #define Z_STACK_MAX 4096

View file

@ -1,3 +1,8 @@
#define FONT_HEIGHT 48
Gfx_Font *font;
bool button(string label, Vector2 pos, Vector2 size, bool enabled);
@ -12,30 +17,130 @@ int entry(int argc, char **argv) {
Allocator heap = get_heap_allocator(); Allocator heap = get_heap_allocator();
font = load_font_from_disk(STR("C:/windows/fonts/arial.ttf"), heap);
assert(font, "Failed loading arial.ttf");
Audio_Source bruh, song; Audio_Source bruh, song;
bool bruh_ok = audio_source_init_file_decode(&bruh, STR("oogabooga/examples/bruh.wav"), AUDIO_BITS_32, heap);
bool bruh_ok = audio_open_source_load(&bruh, STR("oogabooga/examples/bruh.wav"), heap);
assert(bruh_ok, "Could not load bruh.wav"); 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); bool song_ok = audio_open_source_stream(&song, STR("oogabooga/examples/song.ogg"), heap);
assert(bruh_ok, "Could not load song.ogg"); assert(song_ok, "Could not load song.ogg");
// #Temporary This is not actually how it will work, I'm just testing audio source output. // By default, audio sources will be converted to the same format as the output buffer.
current_source = &song; // However, if you want it to be a specific format (or something smaller than the
// output format), then you can call:
// audio_open_source_load_format()
// audio_open_source_stream_format()
Audio_Player *clip_player = audio_player_get_one();
Audio_Player *song_player = audio_player_get_one();
// If you ever need it, you can give the player back to be reused somewhere else.
// audio_player_release(clip_player);
// But this is probably only something you would need to care about if you had a very
// complicated audio system.
audio_player_set_source(clip_player, bruh, false);
audio_player_set_source(song_player, song, false);
audio_player_set_state(clip_player, AUDIO_PLAYER_STATE_PAUSED);
audio_player_set_state(song_player, AUDIO_PLAYER_STATE_PLAYING);
audio_player_set_looping(clip_player, true);
//play_one_audio_clip(STR("oogabooga/examples/block.wav"));
while (!window.should_close) { while (!window.should_close) {
reset_temporary_storage(); 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); draw_frame.projection = m4_make_orthographic_projection(window.pixel_width * -0.5, window.pixel_width * 0.5, window.pixel_height * -0.5, window.pixel_height * 0.5, -1, 10);
if (is_key_just_pressed(MOUSE_BUTTON_RIGHT)) {
// Easy mode (when you don't care and just want to play a clip)
play_one_audio_clip(STR("oogabooga/examples/block.wav"));
}
Vector4 rect;
rect.x = -window.width/2+40;
rect.y = window.height/2-FONT_HEIGHT-40;
rect.z = FONT_HEIGHT*5;
rect.w = FONT_HEIGHT*1.5;
bool clip_playing = clip_player->state == AUDIO_PLAYER_STATE_PLAYING;
bool song_playing = song_player->state == AUDIO_PLAYER_STATE_PLAYING;
if (button(STR("Song"), rect.xy, rect.zw, song_playing)) {
if (song_playing) audio_player_set_state(song_player, AUDIO_PLAYER_STATE_PAUSED);
else audio_player_set_state(song_player, AUDIO_PLAYER_STATE_PLAYING);
}
rect.y -= FONT_HEIGHT*1.8;
if (button(STR("Loop Bruh"), rect.xy, rect.zw, clip_playing)) {
if (clip_playing) audio_player_set_state(clip_player, AUDIO_PLAYER_STATE_PAUSED);
else audio_player_set_state(clip_player, AUDIO_PLAYER_STATE_PLAYING);
}
rect.y -= FONT_HEIGHT*1.8;
if (button(STR("One Bruh"), rect.xy, rect.zw, false)) {
play_one_audio_clip(STR("oogabooga/examples/bruh.wav"));
}
rect.y -= FONT_HEIGHT*3;
if (button(STR("Reset song"), rect.xy, rect.zw, false)) {
audio_player_set_progression_factor(song_player, 0);
}
rect.y -= FONT_HEIGHT*3;
draw_text(font, STR("Right-click for thing"), FONT_HEIGHT, v2_sub(rect.xy, v2(2, -2)), v2(1, 1), COLOR_BLACK);
draw_text(font, STR("Right-click for thing"), FONT_HEIGHT, rect.xy, v2(1, 1), COLOR_WHITE);
os_update(); os_update();
gfx_update(); gfx_update();
} }
return 0; return 0;
}
bool button(string label, Vector2 pos, Vector2 size, bool enabled) {
Vector4 color = v4(.25, .25, .25, 1);
float L = pos.x;
float R = L + size.x;
float B = pos.y;
float T = B + size.y;
float mx = input_frame.mouse_x - window.width/2;
float my = input_frame.mouse_y - window.height/2;
bool pressed = false;
if (mx >= L && mx < R && my >= B && my < T) {
color = v4(.15, .15, .15, 1);
if (is_key_down(MOUSE_BUTTON_LEFT)) {
color = v4(.05, .05, .05, 1);
}
pressed = is_key_just_released(MOUSE_BUTTON_LEFT);
}
if (enabled) {
color = v4_add(color, v4(.1, .1, .1, 0));
}
draw_rect(pos, size, color);
Gfx_Text_Metrics m = measure_text(font, label, FONT_HEIGHT, v2(1, 1));
Vector2 bottom_left = v2_sub(pos, m.functional_pos_min);
bottom_left.x += size.x/2;
bottom_left.x -= m.functional_size.x/2;
bottom_left.y += size.y/2;
bottom_left.y -= m.functional_size.y/2;
draw_text(font, label, FONT_HEIGHT, bottom_left, v2(1, 1), COLOR_WHITE);
return pressed;
} }

Binary file not shown.

Binary file not shown.

View file

@ -10,7 +10,7 @@ int entry(int argc, char **argv) {
window.clear_color = hex_to_rgba(0x6495EDff); window.clear_color = hex_to_rgba(0x6495EDff);
Gfx_Font *font = load_font_from_disk(STR("C:/windows/fonts/arial.ttf"), get_heap_allocator()); Gfx_Font *font = load_font_from_disk(STR("C:/windows/fonts/arial.ttf"), get_heap_allocator());
assert(font, "Failed loading arial.ttf, %d", GetLastError()); assert(font, "Failed loading arial.ttf");
const u32 font_height = 48; const u32 font_height = 48;

View file

@ -6,6 +6,13 @@
#define RAD_PER_DEG (PI64 / 180.0) #define RAD_PER_DEG (PI64 / 180.0)
#define DEG_PER_RAD (180.0 / PI64) #define DEG_PER_RAD (180.0 / PI64)
#if ENABLE_SIMD
// #Redundant maybe, possibly even degrades performance #Speed
#define LMATH_ALIGN alignat(16)
#else
#define LMATH_ALIGN
#endif
#define to_radians (degrees) (((float)degrees)*(float)RAD_PER_DEG) #define to_radians (degrees) (((float)degrees)*(float)RAD_PER_DEG)
#define to_degrees (radians) (((float)radians)*(float)DEG_PER_RAD) #define to_degrees (radians) (((float)radians)*(float)DEG_PER_RAD)
#define to_radians64(degrees) (((float64)degrees)*(float64)RAD_PER_DEG) #define to_radians64(degrees) (((float64)degrees)*(float64)RAD_PER_DEG)
@ -13,112 +20,115 @@
#define to_radians32 to_radians #define to_radians32 to_radians
#define to_degrees32 to_degrees #define to_degrees32 to_degrees
typedef alignat(16) union Vector2 { typedef union Vector2 {
struct {float32 x, y;}; float data[2];
struct {float32 x, y;};
} Vector2; } Vector2;
inline Vector2 v2(float32 x, float32 y) { return (Vector2){x, y}; } inline Vector2 v2(float32 x, float32 y) { return (Vector2){x, y}; }
#define v2_expand(v) (v).x, (v).y #define v2_expand(v) (v).x, (v).y
typedef alignat(16) union Vector3 { typedef union Vector3 {
struct {float32 x, y, z;}; float data[3];
struct {float32 r, g, b;}; struct {float32 x, y, z;};
struct {Vector2 xy;}; struct {float32 r, g, b;};
struct {float32 _x; Vector2 yz;}; struct {Vector2 xy;};
struct {float32 _x; Vector2 yz;};
} Vector3; } Vector3;
inline Vector3 v3(float32 x, float32 y, float32 z) { return (Vector3){x, y, z}; } inline Vector3 v3(float32 x, float32 y, float32 z) { return (Vector3){x, y, z}; }
#define v3_expand(v) (v).x, (v).y, (v).z #define v3_expand(v) (v).x, (v).y, (v).z
typedef alignat(16) union Vector4 { typedef union alignat(16) Vector4 {
struct {float32 x, y, z, w;}; float data[4];
struct {float32 x1, y1, x2, y2;}; struct {float32 x, y, z, w;};
struct {float32 r, g, b, a;}; struct {Vector2 xy; Vector2 zw;};
struct {float32 left, bottom, right, top;}; struct {float32 x1, y1, x2, y2;};
struct {Vector2 xy; Vector2 zw;}; struct {float32 r, g, b, a;};
struct {Vector3 xyz;}; struct {float32 left, bottom, right, top;};
struct {float32 _x; Vector3 yzw;}; struct {Vector3 xyz;};
struct {float32 _x; Vector3 yzw;};
} Vector4; } Vector4;
inline Vector4 v4(float32 x, float32 y, float32 z, float32 w) { return (Vector4){x, y, z, w}; } inline Vector4 v4(float32 x, float32 y, float32 z, float32 w) { return (Vector4){x, y, z, w}; }
#define v4_expand(v) (v).x, (v).y, (v).z, (v).w #define v4_expand(v) (v).x, (v).y, (v).z, (v).w
inline Vector2 v2_add(Vector2 a, Vector2 b) { inline Vector2 v2_add(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
simd_add_float32_64((f32*)&a, (f32*)&b, (f32*)&a); simd_add_float32_64((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector2 v2_sub(Vector2 a, Vector2 b) { inline Vector2 v2_sub(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
simd_sub_float32_64((f32*)&a, (f32*)&b, (f32*)&a); simd_sub_float32_64((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector2 v2_mul(Vector2 a, Vector2 b) { inline Vector2 v2_mul(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
simd_mul_float32_64((f32*)&a, (f32*)&b, (f32*)&a); simd_mul_float32_64((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector2 v2_mulf(Vector2 a, float32 s) { inline Vector2 v2_mulf(LMATH_ALIGN Vector2 a, float32 s) {
return v2_mul(a, v2(s, s)); return v2_mul(a, v2(s, s));
} }
inline Vector2 v2_div(Vector2 a, Vector2 b) { inline Vector2 v2_div(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
simd_div_float32_64((f32*)&a, (f32*)&b, (f32*)&a); simd_div_float32_64((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector2 v2_divf(Vector2 a, float32 s) { inline Vector2 v2_divf(LMATH_ALIGN Vector2 a, float32 s) {
return v2_div(a, v2(s, s)); return v2_div(a, v2(s, s));
} }
inline Vector3 v3_add(Vector3 a, Vector3 b) { inline Vector3 v3_add(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
Vector4 a128 = v4(a.x, a.y, a.z, 0.0); LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
Vector4 b128 = v4(b.x, b.y, b.z, 0.0); LMATH_ALIGN Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
simd_add_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128); simd_add_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128);
return a128.xyz; return a128.xyz;
} }
inline Vector3 v3_sub(Vector3 a, Vector3 b) { inline Vector3 v3_sub(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
Vector4 a128 = v4(a.x, a.y, a.z, 0.0); LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
Vector4 b128 = v4(b.x, b.y, b.z, 0.0); LMATH_ALIGN Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
simd_sub_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128); simd_sub_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128);
return a128.xyz; return a128.xyz;
} }
inline Vector3 v3_mul(Vector3 a, Vector3 b) { inline Vector3 v3_mul(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
Vector4 a128 = v4(a.x, a.y, a.z, 0.0); LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
Vector4 b128 = v4(b.x, b.y, b.z, 0.0); LMATH_ALIGN Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
simd_mul_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128); simd_mul_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128);
return a128.xyz; return a128.xyz;
} }
inline Vector3 v3_mulf(Vector3 a, float32 s) { inline Vector3 v3_mulf(LMATH_ALIGN Vector3 a, float32 s) {
return v3_mul(a, v3(s, s, s)); return v3_mul(a, v3(s, s, s));
} }
inline Vector3 v3_div(Vector3 a, Vector3 b) { inline Vector3 v3_div(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
Vector4 a128 = v4(a.x, a.y, a.z, 0.0); LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
Vector4 b128 = v4(b.x, b.y, b.z, 0.0); LMATH_ALIGN Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
simd_div_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128); simd_div_float32_128_aligned((f32*)&a128, (f32*)&b128, (f32*)&a128);
return a128.xyz; return a128.xyz;
} }
inline Vector3 v3_divf(Vector3 a, float32 s) { inline Vector3 v3_divf(LMATH_ALIGN Vector3 a, float32 s) {
return v3_div(a, v3(s, s, s)); return v3_div(a, v3(s, s, s));
} }
inline Vector4 v4_add(Vector4 a, Vector4 b) { inline Vector4 v4_add(LMATH_ALIGN Vector4 a, LMATH_ALIGN Vector4 b) {
simd_add_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a); simd_add_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector4 v4_sub(Vector4 a, Vector4 b) { inline Vector4 v4_sub(LMATH_ALIGN Vector4 a, LMATH_ALIGN Vector4 b) {
simd_sub_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a); simd_sub_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector4 v4_mul(Vector4 a, Vector4 b) { inline Vector4 v4_mul(LMATH_ALIGN Vector4 a, LMATH_ALIGN Vector4 b) {
simd_mul_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a); simd_mul_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector4 v4_mulf(Vector4 a, float32 s) { inline Vector4 v4_mulf(LMATH_ALIGN Vector4 a, float32 s) {
return v4_mul(a, v4(s, s, s, s)); return v4_mul(a, v4(s, s, s, s));
} }
inline Vector4 v4_div(Vector4 a, Vector4 b) { inline Vector4 v4_div(LMATH_ALIGN Vector4 a, LMATH_ALIGN Vector4 b) {
simd_div_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a); simd_div_float32_128_aligned((f32*)&a, (f32*)&b, (f32*)&a);
return a; return a;
} }
inline Vector4 v4_divf(Vector4 a, float32 s) { inline Vector4 v4_divf(LMATH_ALIGN Vector4 a, float32 s) {
return v4_div(a, v4(s, s, s, s)); return v4_div(a, v4(s, s, s, s));
} }
inline Vector2 v2_normalize(Vector2 a) { inline Vector2 v2_normalize(LMATH_ALIGN Vector2 a) {
float32 length = sqrt(a.x * a.x + a.y * a.y); float32 length = sqrt(a.x * a.x + a.y * a.y);
if (length == 0) { if (length == 0) {
return (Vector2){0, 0}; return (Vector2){0, 0};
@ -126,13 +136,13 @@ inline Vector2 v2_normalize(Vector2 a) {
return v2_divf(a, length); return v2_divf(a, length);
} }
inline float v2_dot_product(Vector2 a, Vector2 b) { inline float v2_dot_product(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
return simd_dot_product_float32_64((float*)&a, (float*)&b); return simd_dot_product_float32_64((float*)&a, (float*)&b);
} }
inline float v3_dot_product(Vector3 a, Vector3 b) { inline float v3_dot_product(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
return simd_dot_product_float32_96((float*)&a, (float*)&b); return simd_dot_product_float32_96((float*)&a, (float*)&b);
} }
inline float v4_dot_product(Vector4 a, Vector4 b) { inline float v4_dot_product(LMATH_ALIGN Vector4 a, LMATH_ALIGN Vector4 b) {
return simd_dot_product_float32_128_aligned((float*)&a, (float*)&b); return simd_dot_product_float32_128_aligned((float*)&a, (float*)&b);
} }
@ -184,7 +194,7 @@ Matrix4 m4_make_translation(Vector3 translation) {
return m; return m;
} }
Matrix4 m4_make_rotation(Vector3 axis, float32 radians) { Matrix4 m4_make_rotation(LMATH_ALIGN Vector3 axis, float32 radians) {
Matrix4 m = m4_scalar(1.0); Matrix4 m = m4_scalar(1.0);
float32 c = cosf(radians); float32 c = cosf(radians);
float32 s = sinf(radians); float32 s = sinf(radians);
@ -219,7 +229,7 @@ Matrix4 m4_make_scale(Vector3 scale) {
return m; return m;
} }
Matrix4 m4_mul(Matrix4 a, Matrix4 b) { Matrix4 m4_mul(LMATH_ALIGN Matrix4 a, LMATH_ALIGN Matrix4 b) {
Matrix4 result; Matrix4 result;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
@ -237,7 +247,7 @@ inline Matrix4 m4_translate(Matrix4 m, Vector3 translation) {
return m4_mul(m, translation_matrix); return m4_mul(m, translation_matrix);
} }
inline Matrix4 m4_rotate(Matrix4 m, Vector3 axis, float32 radians) { inline Matrix4 m4_rotate(Matrix4 m, LMATH_ALIGN Vector3 axis, float32 radians) {
Matrix4 rotation_matrix = m4_make_rotation(axis, radians); Matrix4 rotation_matrix = m4_make_rotation(axis, radians);
return m4_mul(m, rotation_matrix); return m4_mul(m, rotation_matrix);
} }
@ -273,7 +283,7 @@ Vector4 m4_transform(Matrix4 m, Vector4 v) {
result.w = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3] * v.w; result.w = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3] * v.w;
return result; return result;
} }
Matrix4 m4_inverse(Matrix4 m) { Matrix4 m4_inverse(LMATH_ALIGN Matrix4 m) {
Matrix4 inv; Matrix4 inv;
float32 det; float32 det;
@ -410,3 +420,18 @@ Matrix4 m4_inverse(Matrix4 m) {
// This isn't really linmath but just putting it here for now // This isn't really linmath but just putting it here for now
#define clamp(x, lo, hi) ((x) < (lo) ? (lo) : ((x) > (hi) ? (hi) : (x))) #define clamp(x, lo, hi) ((x) < (lo) ? (lo) : ((x) > (hi) ? (hi) : (x)))
f64 lerpf(f64 from, f64 to, f64 x) {
return (to-from)*x+from;
}
s64 lerpi(s64 from, s64 to, f64 x) {
return (s64)((round((f64)to-(f64)from)*x)+from);
}
f64 smerpf(f64 from, f64 to, f64 t) {
float64 smooth = t * t * (3.0 - 2.0 * t);
return lerpf(from, to, smooth);
}
s64 smerpi(s64 from, s64 to, f64 t) {
float64 smooth = t * t * (3.0 - 2.0 * t);
return lerpi(from, to, smooth);
}

View file

@ -74,7 +74,7 @@ typedef struct Heap_Block {
} Heap_Block; } Heap_Block;
#define HEAP_META_SIGNATURE 6969694206942069ull #define HEAP_META_SIGNATURE 6969694206942069ull
typedef struct { typedef alignat(16) struct Heap_Allocation_Metadata {
u64 size; u64 size;
Heap_Block *block; Heap_Block *block;
#if CONFIGURATION == DEBUG #if CONFIGURATION == DEBUG
@ -111,14 +111,26 @@ bool is_pointer_valid(void *p) {
} }
// Meant for debug // Meant for debug
void santiy_check_free_node_tree(Heap_Block *block) { void sanity_check_block(Heap_Block *block) {
Heap_Free_Node *node = block->free_head;
assert(is_pointer_in_program_memory(block), "Heap_Block pointer is corrupt");
assert(is_pointer_in_program_memory(block->start), "Heap_Block pointer is corrupt");
if(block->next) { assert(is_pointer_in_program_memory(block->next), "Heap_Block next pointer is corrupt"); }
assert(block->size < GB(256), "A heap block is corrupt.");
assert((u64)block->start == (u64)block + sizeof(Heap_Block), "A heap block is corrupt.");
Heap_Free_Node *node = block->free_head;
u64 total_free = 0; u64 total_free = 0;
while (node != 0) { while (node != 0) {
Heap_Free_Node *other_node = node->next; Heap_Free_Node *other_node = node->next;
assert(node->size < GB(256), "Heap is corrupt");
assert(is_pointer_in_program_memory(node), "Heap is corrupt");
while (other_node != 0) { while (other_node != 0) {
assert(is_pointer_in_program_memory(other_node), "Heap is corrupt");
assert(other_node != node, "Circular reference in heap free node tree. This is probably an internal error, or an extremely unlucky result from heap corruption."); assert(other_node != node, "Circular reference in heap free node tree. This is probably an internal error, or an extremely unlucky result from heap corruption.");
other_node = other_node->next; other_node = other_node->next;
} }
@ -192,6 +204,8 @@ Heap_Search_Result search_heap_block(Heap_Block *block, u64 size) {
Heap_Block *make_heap_block(Heap_Block *parent, u64 size) { Heap_Block *make_heap_block(Heap_Block *parent, u64 size) {
size += sizeof(Heap_Block);
size = (size) & ~(HEAP_ALIGNMENT-1); size = (size) & ~(HEAP_ALIGNMENT-1);
Heap_Block *block; Heap_Block *block;
@ -247,7 +261,7 @@ void *heap_alloc(u64 size) {
spinlock_acquire_or_wait(&heap_lock); spinlock_acquire_or_wait(&heap_lock);
size += sizeof(Heap_Allocation_Metadata); size += sizeof(Heap_Allocation_Metadata);
@ -266,7 +280,11 @@ void *heap_alloc(u64 size) {
// Maybe instead of going through EVERY free node to find best fit we do a good-enough fit // Maybe instead of going through EVERY free node to find best fit we do a good-enough fit
while (block != 0) { while (block != 0) {
if (block->size < size) { #if VERY_DEBUG
sanity_check_block(block);
#endif
if (get_heap_block_size_excluding_metadata(block) < size) {
last_block = block; last_block = block;
block = block->next; block = block->next;
continue; continue;
@ -342,7 +360,7 @@ void *heap_alloc(u64 size) {
check_meta(meta); check_meta(meta);
#if VERY_DEBUG #if VERY_DEBUG
santiy_check_free_node_tree(meta->block); sanity_check_block(meta->block);
#endif #endif
// #Sync #Speed oof // #Sync #Speed oof
@ -369,8 +387,12 @@ void heap_dealloc(void *p) {
Heap_Block *block = meta->block; Heap_Block *block = meta->block;
u64 size = meta->size; u64 size = meta->size;
#if CONFIGURATION == DEBUG
memset(p, 0x69696969, size);
#endif
#if VERY_DEBUG #if VERY_DEBUG
santiy_check_free_node_tree(block); sanity_check_block(block);
#endif #endif
Heap_Free_Node *new_node = cast(Heap_Free_Node*)p; Heap_Free_Node *new_node = cast(Heap_Free_Node*)p;
@ -428,7 +450,9 @@ void heap_dealloc(void *p) {
} }
#if VERY_DEBUG
sanity_check_block(block);
#endif
// #Sync #Speed oof // #Sync #Speed oof
spinlock_release(&heap_lock); spinlock_release(&heap_lock);
} }
@ -440,9 +464,6 @@ void* heap_allocator_proc(u64 size, void *p, Allocator_Message message, void* da
break; break;
} }
case ALLOCATOR_DEALLOCATE: { case ALLOCATOR_DEALLOCATE: {
assert(is_pointer_valid(p), "Invalid pointer passed to heap allocator deallocate");
Heap_Allocation_Metadata *meta = (Heap_Allocation_Metadata*)(((u64)p)-sizeof(Heap_Allocation_Metadata));
check_meta(meta);
heap_dealloc(p); heap_dealloc(p);
return 0; return 0;
} }

View file

@ -214,6 +214,9 @@ typedef u8 bool;
#ifdef _WIN32 #ifdef _WIN32
#define COBJMACROS #define COBJMACROS
#include <Windows.h> #include <Windows.h>
#if CONFIGURATION == DEBUG
#include <dbghelp.h>
#endif
#define TARGET_OS WINDOWS #define TARGET_OS WINDOWS
#define OS_PATHS_HAVE_BACKSLASH 1 #define OS_PATHS_HAVE_BACKSLASH 1
#elif defined(__linux__) #elif defined(__linux__)
@ -234,15 +237,6 @@ typedef u8 bool;
// This needs to be included before dependencies // This needs to be included before dependencies
#include "base.c" #include "base.c"
///
///
// Dependencies
///
#include "third_party.c"
/////
#include "simd.c" #include "simd.c"
// #Incomplete // #Incomplete
@ -274,9 +268,22 @@ typedef u8 bool;
#include "hash_table.c" #include "hash_table.c"
#include "os_interface.c" #include "os_interface.c"
///
///
// Dependencies
///
// The reason dependencies are compiled here is because we modify stb_vorbis to use our
// file API instead of the stdio.h (cmoooon Sean)
#include "third_party.c"
/////
#include "concurrency.c" #include "concurrency.c"
#include "gfx_interface.c" #include "gfx_interface.c"
#include "font.c" #include "font.c"
#include "profiling.c" #include "profiling.c"
@ -359,9 +366,13 @@ int ENTRY_PROC(int argc, char **argv);
int main(int argc, char **argv) { int main(int argc, char **argv) {
print("Ooga booga program started\n"); print("Ooga booga program started\n");
oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE); oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE);
assert(sizeof(Vector3) == 12, "%d", sizeof(Vector3));
assert(sizeof(Vector2) == 8 , "%d", sizeof(Vector2));
assert(sizeof(Vector4) == 16, "%d", sizeof(Vector4));
assert(main != ENTRY_PROC, "You've ooga'd your last booga"); assert(main != ENTRY_PROC, "You've ooga'd your last booga");

View file

@ -138,10 +138,10 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
return 0; return 0;
} }
void win32_audio_thread(Thread *t);
void void
win32_audio_init(); win32_audio_init();
void win32_init_window() { void
win32_init_window() {
memset(&window, 0, sizeof(window)); memset(&window, 0, sizeof(window));
window.title = STR("Unnamed Window"); window.title = STR("Unnamed Window");
@ -196,8 +196,20 @@ void win32_init_window() {
UpdateWindow(window._os_handle); UpdateWindow(window._os_handle);
} }
void
win32_audio_thread(Thread *t);
void
win32_audio_poll_default_device_thread(Thread *t);
bool win32_has_audio_thread_started = false;
void os_init(u64 program_memory_size) { void os_init(u64 program_memory_size) {
#if CONFIGURATION == DEBUG
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
#endif
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
win32_check_hr(hr); win32_check_hr(hr);
@ -255,7 +267,12 @@ void os_init(u64 program_memory_size) {
assert(os.crt_memset, "Missing memset in crt"); assert(os.crt_memset, "Missing memset in crt");
win32_init_window(); win32_init_window();
os_start_thread(os_make_thread(win32_audio_thread, get_heap_allocator())); os_start_thread(os_make_thread(win32_audio_thread, get_heap_allocator()));
os_start_thread(os_make_thread(win32_audio_poll_default_device_thread, get_heap_allocator()));
while (!win32_has_audio_thread_started) { os_yield_thread(); }
} }
void s64_to_null_terminated_string_reverse(char str[], int length) void s64_to_null_terminated_string_reverse(char str[], int length)
@ -764,6 +781,43 @@ bool os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_byte
return result; return result;
} }
bool os_file_set_pos(File f, s64 pos_in_bytes) {
if (pos_in_bytes < 0) return false;
LARGE_INTEGER pos;
pos.QuadPart = pos_in_bytes;
return SetFilePointerEx(f, pos, NULL, FILE_BEGIN);
}
s64
os_file_get_size(File f) {
s64 backup_pos = os_file_get_pos(f);
if (backup_pos < 0) return -1;
LARGE_INTEGER file_size;
file_size.QuadPart = 0;
if (!SetFilePointerEx(f, file_size, &file_size, FILE_END)) {
os_file_set_pos(f, backup_pos);
return -1;
}
// The new position of the file pointer is the size of the file
u64 result = (u64)file_size.QuadPart;
os_file_set_pos(f, backup_pos);
return result;
}
s64 os_file_get_pos(File f) {
LARGE_INTEGER pos = {0};
LARGE_INTEGER new_pos;
if (SetFilePointerEx(f, pos, &new_pos, FILE_CURRENT)) {
return new_pos.QuadPart;
}
return (s64)-1;
}
bool os_write_entire_file_handle(File f, string data) { bool os_write_entire_file_handle(File f, string data) {
return os_file_write_string(f, data); return os_file_write_string(f, data);
} }
@ -962,6 +1016,107 @@ void* os_get_stack_limit() {
return tib->StackLimit; return tib->StackLimit;
} }
///
///
// Debug
///
#define WIN32_MAX_STACK_FRAMES 64
#define WIN32_MAX_SYMBOL_NAME_LENGTH 256
string *
os_get_stack_trace(u64 *trace_count, Allocator allocator) {
#if CONFIGURATION == DEBUG
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT context;
STACKFRAME64 stack;
memset(&stack, 0, sizeof(STACKFRAME64));
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
#ifdef _M_IX86
int machineType = IMAGE_FILE_MACHINE_I386;
stack.AddrPC.Offset = context.Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Esp;
stack.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
int machineType = IMAGE_FILE_MACHINE_AMD64;
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rsp;
stack.AddrFrame.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
int machineType = IMAGE_FILE_MACHINE_IA64;
stack.AddrPC.Offset = context.StIIP;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.IntSp;
stack.AddrFrame.Mode = AddrModeFlat;
stack.AddrBStore.Offset = context.RsBSP;
stack.AddrBStore.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.IntSp;
stack.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif
string *stack_strings = (string *)alloc(allocator, WIN32_MAX_STACK_FRAMES * sizeof(string));
*trace_count = 0;
for (int i = 0; i < WIN32_MAX_STACK_FRAMES; i++) {
if (!StackWalk64(machineType, process, thread, &stack, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
break;
}
DWORD64 displacement = 0;
char buffer[sizeof(SYMBOL_INFO) + WIN32_MAX_SYMBOL_NAME_LENGTH * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = WIN32_MAX_SYMBOL_NAME_LENGTH;
if (SymFromAddr(process, stack.AddrPC.Offset, &displacement, symbol)) {
IMAGEHLP_LINE64 line;
DWORD displacement_line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
char *result;
if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &displacement_line, &line)) {
u64 length = (u64)(symbol->NameLen + strlen(line.FileName) + 50);
result = (char *)alloc(allocator, length);
format_string_to_buffer_va(result, length, "%cs:%d: %cs", line.FileName, line.LineNumber, symbol->Name);
} else {
u64 length = (u64)(symbol->NameLen + 1);
result = (char *)alloc(allocator, length);
memcpy(result, symbol->Name, symbol->NameLen + 1);
}
stack_strings[*trace_count].data = (u8 *)result;
stack_strings[*trace_count].count = strlen(result);
(*trace_count)++;
} else {
stack_strings[*trace_count].data = (u8 *)alloc(allocator, 32);
stack_strings[*trace_count].count = format_string_to_buffer_va((char *)stack_strings[*trace_count].data, 32, "0x%llx", stack.AddrPC.Offset);
(*trace_count)++;
}
}
return stack_strings;
#else // DEBUG
*trace_count = 1;
string *result = alloc(allocator, 3+sizeof(string));
result->count = 3;
result->data = (u8*)result+sizeof(string);
string s = STR("<0>");
memcpy(result->data, s.data, 3);
return result;
#endif // NOT DEBUG
}
// Actually fuck you bill gates // Actually fuck you bill gates
const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}}; 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_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}};
@ -973,14 +1128,17 @@ DEFINE_GUID(IID_ISimpleAudioVolume,
IAudioClient* win32_audio_client; IAudioClient* win32_audio_client;
IAudioRenderClient* win32_render_client; IAudioRenderClient* win32_render_client;
bool win32_audio_deactivated = false; bool win32_audio_deactivated = false;
Audio_Format win32_output_format; Audio_Format audio_output_format; // For use when loading audio sources
IMMDevice* win32_audio_device = 0; IMMDevice* win32_audio_device = 0;
IMMDeviceEnumerator* win32_device_enumerator = 0; IMMDeviceEnumerator* win32_device_enumerator = 0;
ISimpleAudioVolume* win32_audio_volume = 0; ISimpleAudioVolume* win32_audio_volume = 0;
Mutex audio_init_mutex;
void void
win32_audio_init() { win32_audio_init() {
win32_has_audio_thread_started = true;
win32_audio_client = 0; win32_audio_client = 0;
win32_render_client = 0; win32_render_client = 0;
win32_audio_deactivated = 0; win32_audio_deactivated = 0;
@ -1073,12 +1231,12 @@ win32_audio_init() {
hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client); hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client);
win32_check_hr(hr); win32_check_hr(hr);
win32_output_format.channels = output_format->nChannels; audio_output_format.channels = output_format->nChannels;
win32_output_format.sample_rate = output_format->nSamplesPerSec; audio_output_format.sample_rate = output_format->nSamplesPerSec;
if (output_format == (WAVEFORMATEX*)format_s16) { if (output_format == (WAVEFORMATEX*)format_s16) {
win32_output_format.bit_width = AUDIO_BITS_16; audio_output_format.bit_width = AUDIO_BITS_16;
} else if (output_format == (WAVEFORMATEX*)format_f32) { } else if (output_format == (WAVEFORMATEX*)format_f32) {
win32_output_format.bit_width = AUDIO_BITS_32; audio_output_format.bit_width = AUDIO_BITS_32;
} else { } else {
panic("What"); panic("What");
} }
@ -1093,15 +1251,63 @@ win32_audio_init() {
ISimpleAudioVolume_Release(win32_audio_volume); 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); log_info("Successfully initialized default audio device. Channels: %d, sample_rate: %d, bits: %d", audio_output_format.channels, audio_output_format.sample_rate, get_audio_bit_width_byte_size(audio_output_format.bit_width)*8);
} }
void
win32_audio_poll_default_device_thread(Thread *t) {
while (!win32_has_audio_thread_started) {
MEMORY_BARRIER;
os_yield_thread();
}
while (!window.should_close) {
while (win32_audio_deactivated) {
os_sleep(100);
}
mutex_acquire_or_wait(&audio_init_mutex);
MEMORY_BARRIER;
mutex_release(&audio_init_mutex);
MEMORY_BARRIER;
IMMDevice *now_default = 0;
HRESULT 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);
os_sleep(100);
}
}
void void
win32_audio_thread(Thread *t) { win32_audio_thread(Thread *t) {
mutex_init(&audio_init_mutex);
mutex_acquire_or_wait(&audio_init_mutex);
win32_has_audio_thread_started = true;
MEMORY_BARRIER;
win32_audio_init(); win32_audio_init();
mutex_release(&audio_init_mutex);
timeBeginPeriod(1); timeBeginPeriod(1);
@ -1114,7 +1320,9 @@ win32_audio_thread(Thread *t) {
while (!window.should_close) tm_scope("Audio update") { while (!window.should_close) tm_scope("Audio update") {
if (win32_audio_deactivated) tm_scope("Retry audio device") { if (win32_audio_deactivated) tm_scope("Retry audio device") {
os_sleep(100); os_sleep(100);
mutex_acquire_or_wait(&audio_init_mutex);
win32_audio_init(); win32_audio_init();
mutex_release(&audio_init_mutex);
started = false; started = false;
if (win32_audio_deactivated) { if (win32_audio_deactivated) {
hr = IAudioClient_GetBufferSize(win32_audio_client, &buffer_frame_count); hr = IAudioClient_GetBufferSize(win32_audio_client, &buffer_frame_count);
@ -1122,29 +1330,6 @@ win32_audio_thread(Thread *t) {
} }
continue; 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; if (win32_audio_deactivated) continue;
@ -1191,9 +1376,9 @@ win32_audio_thread(Thread *t) {
continue; continue;
} }
do_program_audio_sample(num_frames_to_write, win32_output_format, buffer); do_program_audio_sample(num_frames_to_write, audio_output_format, buffer);
//f32 s = 0.5; //f32 s = 0.5;
//for (u32 i = 0; i < num_frames_to_write * win32_output_format.channels; ++i) { //for (u32 i = 0; i < num_frames_to_write * audio_output_format.channels; ++i) {
// ((f32*)buffer)[i] = s; // ((f32*)buffer)[i] = s;
//} //}
/*float64 time = 0; /*float64 time = 0;
@ -1209,7 +1394,7 @@ win32_audio_thread(Thread *t) {
//for (u64 i = 0; i < num_frames_to_write; i++) { //for (u64 i = 0; i < num_frames_to_write; i++) {
// f32 s = *(((f32*)buffer)+i*win32_output_format.channels); // f32 s = *(((f32*)buffer)+i*audio_output_format.channels);
// print("%f ", s); // print("%f ", s);
//} //}
hr = IAudioRenderClient_ReleaseBuffer( hr = IAudioRenderClient_ReleaseBuffer(

View file

@ -192,6 +192,11 @@ bool os_file_write_bytes(File f, void *buffer, u64 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);
bool os_file_set_pos(File f, s64 pos_in_bytes);
s64 os_file_get_pos(File f);
s64 os_file_get_size(File f);
bool os_write_entire_file_handle(File f, string data); bool os_write_entire_file_handle(File f, string data);
bool os_write_entire_file_s(string path, string data); bool os_write_entire_file_s(string path, string data);
bool os_read_entire_file_handle(File f, string *result, Allocator allocator); bool os_read_entire_file_handle(File f, string *result, Allocator allocator);
@ -294,10 +299,28 @@ void fprint_va_list_buffered(File f, const string fmt, va_list args) {
/// ///
// Memory // Memory
/// ///
void* os_get_stack_base(); void*
void* os_get_stack_limit(); os_get_stack_base();
void*
os_get_stack_limit();
///
///
// Debug
///
string *
os_get_stack_trace(u64 *trace_count, Allocator allocator);
void dump_stack_trace() {
u64 count;
string *strings = os_get_stack_trace(&count, get_temporary_allocator());
for (u64 i = 0; i < count; i++) {
string s = strings[i];
print("\n%s", s);
}
}
/// ///
/// ///
@ -325,14 +348,4 @@ typedef struct Os_Window {
} Os_Window; } Os_Window;
Os_Window window; Os_Window window;
///
///
// Window input
///
void os_update(); void os_update();

View file

@ -12,6 +12,8 @@ typedef struct string {
u8 *data; u8 *data;
} string; } string;
const string null_string = {0, 0};
#define fixed_string STR #define fixed_string STR
#define STR(s) ((string){ length_of_null_terminated_string((const char*)s), (u8*)s }) #define STR(s) ((string){ length_of_null_terminated_string((const char*)s), (u8*)s })
@ -31,6 +33,7 @@ string alloc_string(Allocator allocator, u64 count) {
return s; return s;
} }
void dealloc_string(Allocator allocator, string s) { void dealloc_string(Allocator allocator, string s) {
assert(s.count > 0 && s.data, "You tried to deallocate an empty string. That's doesn't make sense.");
dealloc(allocator, s.data); dealloc(allocator, s.data);
} }
string talloc_string(u64 count) { string talloc_string(u64 count) {
@ -39,6 +42,11 @@ string talloc_string(u64 count) {
} }
string string_concat(const string left, const string right, Allocator allocator) { string string_concat(const string left, const string right, Allocator allocator) {
if (right.count + left.count == 0) return null_string;
if (left.count == 0) return right;
if (right.count == 0) return left;
string result; string result;
result.count = left.count + right.count; result.count = left.count + right.count;
result.data = cast(u8*)alloc(allocator, result.count); result.data = cast(u8*)alloc(allocator, result.count);

View file

@ -83,6 +83,13 @@ u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list ar
return bufp - buffer; return bufp - buffer;
} }
u64 format_string_to_buffer_va(char* buffer, u64 count, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
u64 r = format_string_to_buffer(buffer, count, fmt, args);
va_end(args);
return r;
}
string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 buffer_size) { string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 buffer_size) {
u64 formatted_length = format_string_to_buffer((char*)buffer, buffer_size, fmt, args); u64 formatted_length = format_string_to_buffer((char*)buffer, buffer_size, fmt, args);

View file

@ -333,8 +333,7 @@ void test_strings() {
// Test handling of empty strings // Test handling of empty strings
string empty_str = STR(""); string empty_str = STR("");
string concat_empty_str = string_concat(empty_str, empty_str, heap); string concat_empty_str = string_concat(empty_str, empty_str, heap);
assert(concat_empty_str.count == 0, "Failed: string_concat with empty strings"); assert(concat_empty_str.count == 0 && !concat_empty_str.data, "Failed: string_concat with empty strings");
dealloc_string(heap, concat_empty_str);
// Test very large strings (performance test) // Test very large strings (performance test)
string large_str1 = alloc_string(heap, 1024 * 1024); string large_str1 = alloc_string(heap, 1024 * 1024);
@ -1253,4 +1252,6 @@ void oogabooga_run_tests() {
print("Testing radix sort... "); print("Testing radix sort... ");
test_sort(); test_sort();
print("OK!\n"); print("OK!\n");
print("All tests ok!\n");
} }

View file

@ -1,4 +1,109 @@
// YOINKED FROM https://gist.github.com/LingDong-/7e4c4cae5cbbc44400a05fba65f06f23
// (stb_vorbis uses math.h log() but that collides with oogabooga log() procedure)
/////////////////////////////////////////////////////////////
// ln.c
//
// simple, fast, accurate natural log approximation
// when without <math.h>
// featuring * floating point bit level hacking,
// * x=m*2^p => ln(x)=ln(m)+ln(2)p,
// * Remez algorithm
// by Lingdong Huang, 2020. Public domain.
// ============================================
float ln(float x) {
unsigned int bx = * (unsigned int *) (&x);
unsigned int ex = bx >> 23;
signed int t = (signed int)ex-(signed int)127;
unsigned int s = (t < 0) ? (-t) : t;
bx = 1065353216 | (bx & 8388607);
x = * (float *) (&bx);
return -1.49278+(2.11263+(-0.729104+0.10969*x)*x)*x+0.6931471806*t;
}
// done.
// ============================================
// Exact same function, with added comments:
float natural_log(float x) {
// ASSUMING:
// - non-denormalized numbers i.e. x > 2^126
// - integer is 32 bit. float is IEEE 32 bit.
// INSPIRED BY:
// - https://stackoverflow.com/a/44232045
// - http://mathonweb.com/help_ebook/html/algorithms.htm#ln
// - https://en.wikipedia.org/wiki/Fast_inverse_square_root
// FORMULA:
// x = m * 2^p =>
// ln(x) = ln(m) + ln(2)p,
// first normalize the value to between 1.0 and 2.0
// assuming normalized IEEE float
// sign exp frac
// 0b 0 [00000000] 00000000000000000000000
// value = (-1)^s * M * 2 ^ (exp-127)
//
// exp = 127 for x = 1,
// so 2^(exp-127) is the multiplier
// evil floating point bit level hacking
unsigned int bx = * (unsigned int *) (&x);
// extract exp, since x>0, sign bit must be 0
unsigned int ex = bx >> 23;
signed int t = (signed int)ex-(signed int)127;
unsigned int s = (t < 0) ? (-t) : t;
// reinterpret back to float
// 127 << 23 = 1065353216
// 0b11111111111111111111111 = 8388607
bx = 1065353216 | (bx & 8388607);
x = * (float *) (&bx);
// use remez algorithm to find approximation between [1,2]
// - see this answer https://stackoverflow.com/a/44232045
// - or this usage of C++/boost's remez implementation
// https://computingandrecording.wordpress.com/2017/04/24/
// e.g.
// boost::math::tools::remez_minimax<double> approx(
// [](const double& x) { return log(x); },
// 4, 0, 1, 2, false, 0, 0, 64);
//
// 4th order is:
// { -1.74178, 2.82117, -1.46994, 0.447178, -0.0565717 }
//
// 3rd order is:
// { -1.49278, 2.11263, -0.729104, 0.10969 }
return
/* less accurate */
-1.49278+(2.11263+(-0.729104+0.10969*x)*x)*x
/* OR more accurate */
// -1.7417939+(2.8212026+(-1.4699568+(0.44717955-0.056570851*x)*x)*x)*x
/* compensate for the ln(2)s. ln(2)=0.6931471806 */
+ 0.6931471806*t;
}
//////////////////////////////////////////////////////////////////////////////
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
@ -15,6 +120,12 @@ void *third_party_malloc(size_t size) {
if (!size) return 0; if (!size) return 0;
return alloc(third_party_allocator, size); return alloc(third_party_allocator, size);
} }
void *third_party_realloc(void *p, size_t size) {
assert(third_party_allocator.proc, "No third party allocator was set, but it was used!");
if (!size) return 0;
if (!p) return third_party_malloc(size);
return third_party_allocator.proc(size, p, ALLOCATOR_REALLOCATE, 0);
}
void third_party_free(void *p) { void third_party_free(void *p) {
assert(third_party_allocator.proc, "No third party allocator was set, but it was used!"); assert(third_party_allocator.proc, "No third party allocator was set, but it was used!");
if (!p) return; if (!p) return;
@ -49,11 +160,3 @@ size_t stbtt_strlen(const char* str) {
#undef C #undef C
#undef L #undef L
#define DR_WAV_NO_STDIO
#define DR_WAV_NO_WCHAR
#define DRWAV_ASSERT(exp) assert(exp, "dr_wav assertion failed")
#define DRWAV_MALLOC(sz) third_party_malloc(sz)
#define DRWAV_REALLOC(p,newsz) third_party_allocator.proc(newsz, p, ALLOCATOR_REALLOCATE, 0)
#define DRWAV_FREE(p) third_party_free(p)
#define DR_WAV_IMPLEMENTATION
#include "third_party/dr_wav.h"

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,88 @@
/*
#Modified
INFORMATION ABOUT MODIFICATION BY THE OOGABOOGA TEAM
This file has been slightly modified from the original stb_vorbis.c (see license)
to integrate better into the oogabooga environment.
All small niche modifications are marked with #Modified and the name of whoever modified
it and at which date it was modified.
Other than that:
- All FILE * stdio procedures are replaced with the equivalent for the oogabooga
file API.
*/
// #Modified
//////////////////////////////////////
//// C stdio ports to oogabooga File API
#define EOF -1
int fgetc(File f) {
u8 ch;
u64 bytes_read;
if (os_file_read(f, &ch, 1, &bytes_read) && bytes_read == 1) {
return (int)ch;
} else {
return EOF;
}
}
size_t fread(void *buffer, size_t size, size_t count, File f) {
u64 bytes_to_read = size * count;
u64 actual_read_bytes;
if (os_file_read(f, buffer, bytes_to_read, &actual_read_bytes)) {
return actual_read_bytes / size;
} else {
return 0;
}
}
long ftell(File f) {
s64 pos = os_file_get_pos(f);
if (pos >= 0) {
return (long)pos;
} else {
return -1;
}
}
int fseek(File f, s64 offset, s64 origin) {
s64 new_pos;
switch (origin) {
case SEEK_SET:
new_pos = offset;
break;
case SEEK_CUR:
new_pos = os_file_get_pos(f) + offset;
break;
case SEEK_END:
new_pos = os_file_get_size(f) + offset;
break;
default:
return -1;
}
return os_file_set_pos(f, new_pos) ? 0 : -1;
}
File fopen(const char *filename, const char *mode) {
// Handling modes
File f = os_file_open_s(STR(filename), O_READ);
return f;
}
int fclose(File f) {
os_file_close(f);
return 0;
}
//////////////////////////////////////
// Ogg Vorbis audio decoder - v1.22 - public domain // Ogg Vorbis audio decoder - v1.22 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
@ -78,8 +163,11 @@
#define STB_VORBIS_NO_STDIO 1 #define STB_VORBIS_NO_STDIO 1
#endif #endif
// #Modified Charlie Malmqvist 2024-07-14
#undef STB_VORBIS_NO_STDIO
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
#include <stdio.h> //#include <stdio.h> // #Modified Charlie Malmqvist 2024-07-14
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -249,8 +337,8 @@ extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
#ifndef STB_VORBIS_NO_PULLDATA_API #ifndef STB_VORBIS_NO_PULLDATA_API
// This API assumes stb_vorbis is allowed to pull data from a source-- // This API assumes stb_vorbis is allowed to pull data from a source--
// either a block of memory containing the _entire_ vorbis stream, or a // either a block of memory containing the _entire_ vorbis stream, or a
// FILE * that you or it create, or possibly some other reading mechanism // File that you or it create, or possibly some other reading mechanism
// if you go modify the source to replace the FILE * case with some kind // if you go modify the source to replace the File case with some kind
// of callback to your code. (But if you don't support seeking, you may // of callback to your code. (But if you don't support seeking, you may
// just want to go ahead and use pushdata.) // just want to go ahead and use pushdata.)
@ -276,9 +364,9 @@ extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
// create an ogg vorbis decoder from a filename via fopen(). on failure, // create an ogg vorbis decoder from a filename via fopen(). on failure,
// returns NULL and sets *error (possibly to VORBIS_file_open_failure). // returns NULL and sets *error (possibly to VORBIS_file_open_failure).
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, extern stb_vorbis * stb_vorbis_open_file(File f, int close_handle_on_close,
int *error, const stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at // create an ogg vorbis decoder from an open File , looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error. // the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between // note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Moreover, if you attempt to // calls to stb_vorbis, it will become confused. Moreover, if you attempt to
@ -286,9 +374,9 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
// owns the _entire_ rest of the file after the start point. Use the next // owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it. // function, stb_vorbis_open_file_section(), to limit it.
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, extern stb_vorbis * stb_vorbis_open_file_section(File f, int close_handle_on_close,
int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len); int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at // create an ogg vorbis decoder from an open File , looking for a stream at
// the _current_ seek point (ftell); the stream will be of length 'len' bytes. // the _current_ seek point (ftell); the stream will be of length 'len' bytes.
// on failure, returns NULL and sets *error. note that stb_vorbis must "own" // on failure, returns NULL and sets *error. note that stb_vorbis must "own"
// this stream; if you seek it in between calls to stb_vorbis, it will become // this stream; if you seek it in between calls to stb_vorbis, it will become
@ -434,7 +522,7 @@ enum STBVorbisError
// #define STB_VORBIS_NO_PULLDATA_API // #define STB_VORBIS_NO_PULLDATA_API
// STB_VORBIS_NO_STDIO // STB_VORBIS_NO_STDIO
// does not compile the code for the APIs that use FILE *s internally // does not compile the code for the APIs that use File s internally
// or externally (implied by STB_VORBIS_NO_PULLDATA_API) // or externally (implied by STB_VORBIS_NO_PULLDATA_API)
// #define STB_VORBIS_NO_STDIO // #define STB_VORBIS_NO_STDIO
@ -558,6 +646,9 @@ enum STBVorbisError
#define STB_VORBIS_NO_STDIO 1 #define STB_VORBIS_NO_STDIO 1
#endif #endif
// #Modified Charlie Malmqvist 2024-07-14
#undef STB_VORBIS_NO_STDIO
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION #ifndef STB_VORBIS_NO_INTEGER_CONVERSION
#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
@ -575,11 +666,11 @@ enum STBVorbisError
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
#include <stdio.h> // #include <stdio.h> // #Modified Charlie Malmqvist 2024-07-14
#endif #endif
#ifndef STB_VORBIS_NO_CRT #ifndef STB_VORBIS_NO_CRT
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
@ -799,7 +890,7 @@ struct stb_vorbis
// input config // input config
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
FILE *f; File f;
uint32 f_start; uint32 f_start;
int close_on_free; int close_on_free;
#endif #endif
@ -928,8 +1019,8 @@ static int error(vorb *f, enum STBVorbisError e)
#define array_size_required(count,size) (count*(sizeof(void *)+(size))) #define array_size_required(count,size) (count*(sizeof(void *)+(size)))
#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) #define temp_alloc(f,size) alloca(size) // #Modified
#define temp_free(f,p) (void)0 #define temp_free(f,p) (void)0;
#define temp_alloc_save(f) ((f)->temp_offset) #define temp_alloc_save(f) ((f)->temp_offset)
#define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) #define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
@ -1241,7 +1332,8 @@ static int vorbis_validate(uint8 *data)
// (formula implied by specification) // (formula implied by specification)
static int lookup1_values(int entries, int dim) static int lookup1_values(int entries, int dim)
{ {
int r = (int) floor(exp((float) log((float) entries) / dim)); // #Modified (log -> natural_log) Charlie Malmqvist 2024-07-14
int r = (int) floor(exp((float) natural_log((float) entries) / dim));
if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning;
++r; // floor() to avoid _ftol() when non-CRT ++r; // floor() to avoid _ftol() when non-CRT
if (pow((float) r+1, dim) <= entries) if (pow((float) r+1, dim) <= entries)
@ -1344,6 +1436,7 @@ static uint8 get8(vorb *z)
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
{ {
int c = fgetc(z->f); int c = fgetc(z->f);
if (c == EOF) { z->eof = TRUE; return 0; } if (c == EOF) { z->eof = TRUE; return 0; }
return c; return c;
@ -5050,7 +5143,7 @@ int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) stb_vorbis * stb_vorbis_open_file_section(File file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
vorbis_init(&p, alloc); vorbis_init(&p, alloc);
@ -5071,7 +5164,7 @@ stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *er
return NULL; return NULL;
} }
stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_file(File file, int close_on_free, int *error, const stb_vorbis_alloc *alloc)
{ {
unsigned int len, start; unsigned int len, start;
start = (unsigned int) ftell(file); start = (unsigned int) ftell(file);
@ -5083,13 +5176,9 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
{ {
FILE *f; File f;
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) // #Modified (no open_s) Charlie Malmqvist 2024-07-14
if (0 != fopen_s(&f, filename, "rb"))
f = NULL;
#else
f = fopen(filename, "rb"); f = fopen(filename, "rb");
#endif
if (f) if (f)
return stb_vorbis_open_file(f, TRUE, error, alloc); return stb_vorbis_open_file(f, TRUE, error, alloc);
if (error) *error = VORBIS_file_open_failure; if (error) *error = VORBIS_file_open_failure;
@ -5356,7 +5445,7 @@ int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_
*sample_rate = v->sample_rate; *sample_rate = v->sample_rate;
offset = data_len = 0; offset = data_len = 0;
total = limit; total = limit;
data = (short *) malloc(total * sizeof(*data)); data = (short *) third_party_malloc(total * sizeof(*data)); // #Modified (malloc -> third_party_malloc) Charlie Malmqvist 2024-07-14
if (data == NULL) { if (data == NULL) {
stb_vorbis_close(v); stb_vorbis_close(v);
return -2; return -2;
@ -5369,9 +5458,9 @@ int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_
if (offset + limit > total) { if (offset + limit > total) {
short *data2; short *data2;
total *= 2; total *= 2;
data2 = (short *) realloc(data, total * sizeof(*data)); data2 = (short *) third_party_realloc(data, total * sizeof(*data)); // #Modified (realloc -> third_party_realloc) Charlie Malmqvist 2024-07-14
if (data2 == NULL) { if (data2 == NULL) {
free(data); third_party_free(data); // #Modified (free -> third_party_free) Charlie Malmqvist 2024-07-14
stb_vorbis_close(v); stb_vorbis_close(v);
return -2; return -2;
} }
@ -5396,7 +5485,7 @@ int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *samp
*sample_rate = v->sample_rate; *sample_rate = v->sample_rate;
offset = data_len = 0; offset = data_len = 0;
total = limit; total = limit;
data = (short *) malloc(total * sizeof(*data)); data = (short *) third_party_malloc(total * sizeof(*data)); // #Modified (malloc -> third_party_malloc) Charlie Malmqvist 2024-07-14
if (data == NULL) { if (data == NULL) {
stb_vorbis_close(v); stb_vorbis_close(v);
return -2; return -2;
@ -5409,9 +5498,9 @@ int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *samp
if (offset + limit > total) { if (offset + limit > total) {
short *data2; short *data2;
total *= 2; total *= 2;
data2 = (short *) realloc(data, total * sizeof(*data)); data2 = (short *) third_party_realloc(data, total * sizeof(*data)); // #Modified (realloc -> third_party_realloc) Charlie Malmqvist 2024-07-14
if (data2 == NULL) { if (data2 == NULL) {
free(data); third_party_free(data); // #Modified (free -> third_party_free) Charlie Malmqvist 2024-07-14
stb_vorbis_close(v); stb_vorbis_close(v);
return -2; return -2;
} }
@ -5583,3 +5672,4 @@ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */