v0.01.000 - AUDIO!
This commit is contained in:
parent
2b335aee35
commit
c39902d6b1
23 changed files with 1987 additions and 9198 deletions
28
TODO
28
TODO
|
@ -1,5 +1,33 @@
|
|||
|
||||
- Audio
|
||||
- Player volume control
|
||||
- Optimize
|
||||
- Spam simd
|
||||
- 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
|
|
@ -6,6 +6,6 @@ mkdir 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
|
10
build.c
10
build.c
|
@ -3,8 +3,6 @@
|
|||
///
|
||||
// Build config stuff
|
||||
|
||||
#define OOGABOOGA_DEV 1
|
||||
|
||||
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
|
||||
|
||||
typedef struct Context_Extra {
|
||||
|
@ -14,7 +12,7 @@ typedef struct 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"
|
||||
#define ENTRY_PROC entry
|
||||
#define ENTRY_PROC entry
|
||||
|
||||
// Ooga booga needs to be included AFTER configuration and BEFORE the program code
|
||||
#include "oogabooga/oogabooga.c"
|
||||
|
@ -27,14 +25,14 @@ typedef struct Context_Extra {
|
|||
// 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
|
||||
// #include "oogabooga/examples/minimal_game_loop.c"
|
||||
// This is a minimal starting point for new projects. Copy & rename to get started
|
||||
#include "oogabooga/examples/minimal_game_loop.c"
|
||||
|
||||
// #include "oogabooga/examples/text_rendering.c"
|
||||
// #include "oogabooga/examples/custom_logger.c"
|
||||
// #include "oogabooga/examples/renderer_stress_test.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!
|
||||
// #include "entry_yourepicgamename.c"
|
||||
|
|
|
@ -1,19 +1,50 @@
|
|||
|
||||
## v0.01.001 - AUDIO!
|
||||
## v0.01.000 - AUDIO!
|
||||
- Added audio sources
|
||||
- File stream sources & Fully decoded sources
|
||||
- 16-bit int & 32-bit float support
|
||||
- WAV & OGG support
|
||||
- WAV & OGG support (in-house wav decoder, stb_vorbis for ogg)
|
||||
- Usage:
|
||||
bool audio_source_init_file_stream(*src, path, bit_width, allocator)
|
||||
bool audio_source_init_file_decode(*src, path, bit_width, allocator)
|
||||
bool audio_open_source_stream(*src, path, allocator)
|
||||
bool audio_open_source_load(*src, path, allocator)
|
||||
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
|
||||
- Win32 audio impl
|
||||
- Link to more win32 junk
|
||||
- Make default logger thread safe
|
||||
- Rename tm_scope_cycles & tm_scope_cycles_xxx -> tm_scope & tm_scope_xxx
|
||||
- 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
|
||||
|
|
1293
oogabooga/audio.c
1293
oogabooga/audio.c
File diff suppressed because it is too large
Load diff
|
@ -5,12 +5,15 @@
|
|||
|
||||
#define forward_global extern
|
||||
|
||||
#define alignas _Alignas
|
||||
|
||||
#define null 0
|
||||
|
||||
void printf(const char* fmt, ...);
|
||||
void dump_stack_trace();
|
||||
#define ASSERT_STR_HELPER(x) #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 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* 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);
|
||||
#if DO_ZERO_INITIALIZATION
|
||||
memset(p, 0, size);
|
||||
|
@ -100,9 +104,11 @@ void* alloc(Allocator allocator, u64 size) {
|
|||
return p;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,13 +46,16 @@ void spinlock_init(Spinlock *l) {
|
|||
void spinlock_acquire_or_wait(Spinlock* l) {
|
||||
while (true) {
|
||||
bool expected = false;
|
||||
MEMORY_BARRIER;
|
||||
if (compare_and_swap_bool(&l->locked, true, expected)) {
|
||||
MEMORY_BARRIER;
|
||||
return;
|
||||
}
|
||||
while (l->locked) {
|
||||
// spinny boi
|
||||
MEMORY_BARRIER;
|
||||
}
|
||||
MEMORY_BARRIER;
|
||||
}
|
||||
}
|
||||
// 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();
|
||||
while (true) {
|
||||
bool expected = false;
|
||||
MEMORY_BARRIER;
|
||||
if (compare_and_swap_bool(&l->locked, true, expected)) {
|
||||
MEMORY_BARRIER;
|
||||
return true;
|
||||
|
@ -67,15 +71,17 @@ bool spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds) {
|
|||
while (l->locked) {
|
||||
// spinny boi
|
||||
if ((os_get_current_time_in_seconds()-start) >= timeout_seconds) return false;
|
||||
MEMORY_BARRIER;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void spinlock_release(Spinlock* l) {
|
||||
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;
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,6 +48,12 @@ Usage:
|
|||
|
||||
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(Draw_Quad quad);
|
||||
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 ((1 << MAX_Z_BITS)/2)
|
||||
#define Z_STACK_MAX 4096
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
#define FONT_HEIGHT 48
|
||||
|
||||
Gfx_Font *font;
|
||||
|
||||
bool button(string label, Vector2 pos, Vector2 size, bool enabled);
|
||||
|
||||
|
||||
|
||||
|
@ -12,26 +17,83 @@ int entry(int argc, char **argv) {
|
|||
|
||||
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;
|
||||
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");
|
||||
|
||||
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");
|
||||
bool song_ok = audio_open_source_stream(&song, STR("oogabooga/examples/song.ogg"), heap);
|
||||
assert(song_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;
|
||||
// By default, audio sources will be converted to the same format as the output buffer.
|
||||
// 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) {
|
||||
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_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);
|
||||
|
||||
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
|
||||
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();
|
||||
gfx_update();
|
||||
|
@ -39,3 +101,46 @@ int entry(int argc, char **argv) {
|
|||
|
||||
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;
|
||||
}
|
BIN
oogabooga/examples/block.wav
Normal file
BIN
oogabooga/examples/block.wav
Normal file
Binary file not shown.
Binary file not shown.
|
@ -10,7 +10,7 @@ int entry(int argc, char **argv) {
|
|||
window.clear_color = hex_to_rgba(0x6495EDff);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
#define RAD_PER_DEG (PI64 / 180.0)
|
||||
#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_degrees (radians) (((float)radians)*(float)DEG_PER_RAD)
|
||||
#define to_radians64(degrees) (((float64)degrees)*(float64)RAD_PER_DEG)
|
||||
|
@ -13,13 +20,15 @@
|
|||
#define to_radians32 to_radians
|
||||
#define to_degrees32 to_degrees
|
||||
|
||||
typedef alignat(16) union Vector2 {
|
||||
typedef union Vector2 {
|
||||
float data[2];
|
||||
struct {float32 x, y;};
|
||||
} Vector2;
|
||||
inline Vector2 v2(float32 x, float32 y) { return (Vector2){x, y}; }
|
||||
#define v2_expand(v) (v).x, (v).y
|
||||
|
||||
typedef alignat(16) union Vector3 {
|
||||
typedef union Vector3 {
|
||||
float data[3];
|
||||
struct {float32 x, y, z;};
|
||||
struct {float32 r, g, b;};
|
||||
struct {Vector2 xy;};
|
||||
|
@ -28,97 +37,98 @@ typedef alignat(16) union Vector3 {
|
|||
inline Vector3 v3(float32 x, float32 y, float32 z) { return (Vector3){x, y, z}; }
|
||||
#define v3_expand(v) (v).x, (v).y, (v).z
|
||||
|
||||
typedef alignat(16) union Vector4 {
|
||||
typedef union alignat(16) Vector4 {
|
||||
float data[4];
|
||||
struct {float32 x, y, z, w;};
|
||||
struct {Vector2 xy; Vector2 zw;};
|
||||
struct {float32 x1, y1, x2, y2;};
|
||||
struct {float32 r, g, b, a;};
|
||||
struct {float32 left, bottom, right, top;};
|
||||
struct {Vector2 xy; Vector2 zw;};
|
||||
struct {Vector3 xyz;};
|
||||
struct {float32 _x; Vector3 yzw;};
|
||||
} Vector4;
|
||||
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
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
}
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
inline Vector3 v3_add(Vector3 a, Vector3 b) {
|
||||
Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
|
||||
Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
|
||||
inline Vector3 v3_add(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
|
||||
LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.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);
|
||||
return a128.xyz;
|
||||
}
|
||||
inline Vector3 v3_sub(Vector3 a, Vector3 b) {
|
||||
Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
|
||||
Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
|
||||
inline Vector3 v3_sub(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
|
||||
LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.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);
|
||||
return a128.xyz;
|
||||
}
|
||||
inline Vector3 v3_mul(Vector3 a, Vector3 b) {
|
||||
Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
|
||||
Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
|
||||
inline Vector3 v3_mul(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
|
||||
LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.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);
|
||||
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));
|
||||
}
|
||||
inline Vector3 v3_div(Vector3 a, Vector3 b) {
|
||||
Vector4 a128 = v4(a.x, a.y, a.z, 0.0);
|
||||
Vector4 b128 = v4(b.x, b.y, b.z, 0.0);
|
||||
inline Vector3 v3_div(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
|
||||
LMATH_ALIGN Vector4 a128 = v4(a.x, a.y, a.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);
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
}
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (length == 0) {
|
||||
return (Vector2){0, 0};
|
||||
|
@ -126,13 +136,13 @@ inline Vector2 v2_normalize(Vector2 a) {
|
|||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -184,7 +194,7 @@ Matrix4 m4_make_translation(Vector3 translation) {
|
|||
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);
|
||||
float32 c = cosf(radians);
|
||||
float32 s = sinf(radians);
|
||||
|
@ -219,7 +229,7 @@ Matrix4 m4_make_scale(Vector3 scale) {
|
|||
return m;
|
||||
}
|
||||
|
||||
Matrix4 m4_mul(Matrix4 a, Matrix4 b) {
|
||||
Matrix4 m4_mul(LMATH_ALIGN Matrix4 a, LMATH_ALIGN Matrix4 b) {
|
||||
Matrix4 result;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
return result;
|
||||
}
|
||||
Matrix4 m4_inverse(Matrix4 m) {
|
||||
Matrix4 m4_inverse(LMATH_ALIGN Matrix4 m) {
|
||||
Matrix4 inv;
|
||||
float32 det;
|
||||
|
||||
|
@ -410,3 +420,18 @@ Matrix4 m4_inverse(Matrix4 m) {
|
|||
// This isn't really linmath but just putting it here for now
|
||||
#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);
|
||||
}
|
|
@ -74,7 +74,7 @@ typedef struct Heap_Block {
|
|||
} Heap_Block;
|
||||
|
||||
#define HEAP_META_SIGNATURE 6969694206942069ull
|
||||
typedef struct {
|
||||
typedef alignat(16) struct Heap_Allocation_Metadata {
|
||||
u64 size;
|
||||
Heap_Block *block;
|
||||
#if CONFIGURATION == DEBUG
|
||||
|
@ -111,14 +111,26 @@ bool is_pointer_valid(void *p) {
|
|||
}
|
||||
|
||||
// Meant for debug
|
||||
void santiy_check_free_node_tree(Heap_Block *block) {
|
||||
void sanity_check_block(Heap_Block *block) {
|
||||
|
||||
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;
|
||||
while (node != 0) {
|
||||
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) {
|
||||
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.");
|
||||
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) {
|
||||
|
||||
size += sizeof(Heap_Block);
|
||||
|
||||
size = (size) & ~(HEAP_ALIGNMENT-1);
|
||||
|
||||
Heap_Block *block;
|
||||
|
@ -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
|
||||
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;
|
||||
block = block->next;
|
||||
continue;
|
||||
|
@ -342,7 +360,7 @@ void *heap_alloc(u64 size) {
|
|||
check_meta(meta);
|
||||
|
||||
#if VERY_DEBUG
|
||||
santiy_check_free_node_tree(meta->block);
|
||||
sanity_check_block(meta->block);
|
||||
#endif
|
||||
|
||||
// #Sync #Speed oof
|
||||
|
@ -369,8 +387,12 @@ void heap_dealloc(void *p) {
|
|||
Heap_Block *block = meta->block;
|
||||
u64 size = meta->size;
|
||||
|
||||
#if CONFIGURATION == DEBUG
|
||||
memset(p, 0x69696969, size);
|
||||
#endif
|
||||
|
||||
#if VERY_DEBUG
|
||||
santiy_check_free_node_tree(block);
|
||||
sanity_check_block(block);
|
||||
#endif
|
||||
|
||||
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
|
||||
spinlock_release(&heap_lock);
|
||||
}
|
||||
|
@ -440,9 +464,6 @@ void* heap_allocator_proc(u64 size, void *p, Allocator_Message message, void* da
|
|||
break;
|
||||
}
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -214,6 +214,9 @@ typedef u8 bool;
|
|||
#ifdef _WIN32
|
||||
#define COBJMACROS
|
||||
#include <Windows.h>
|
||||
#if CONFIGURATION == DEBUG
|
||||
#include <dbghelp.h>
|
||||
#endif
|
||||
#define TARGET_OS WINDOWS
|
||||
#define OS_PATHS_HAVE_BACKSLASH 1
|
||||
#elif defined(__linux__)
|
||||
|
@ -234,15 +237,6 @@ typedef u8 bool;
|
|||
// This needs to be included before dependencies
|
||||
#include "base.c"
|
||||
|
||||
///
|
||||
///
|
||||
// Dependencies
|
||||
///
|
||||
|
||||
#include "third_party.c"
|
||||
|
||||
/////
|
||||
|
||||
#include "simd.c"
|
||||
|
||||
// #Incomplete
|
||||
|
@ -274,9 +268,22 @@ typedef u8 bool;
|
|||
#include "hash_table.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 "gfx_interface.c"
|
||||
|
||||
|
||||
#include "font.c"
|
||||
|
||||
#include "profiling.c"
|
||||
|
@ -359,9 +366,13 @@ int ENTRY_PROC(int argc, char **argv);
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
|
||||
print("Ooga booga program started\n");
|
||||
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");
|
||||
|
||||
|
|
|
@ -138,10 +138,10 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
|
|||
return 0;
|
||||
}
|
||||
|
||||
void win32_audio_thread(Thread *t);
|
||||
void
|
||||
win32_audio_init();
|
||||
void win32_init_window() {
|
||||
void
|
||||
win32_init_window() {
|
||||
memset(&window, 0, sizeof(window));
|
||||
|
||||
window.title = STR("Unnamed Window");
|
||||
|
@ -196,8 +196,20 @@ void win32_init_window() {
|
|||
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) {
|
||||
|
||||
#if CONFIGURATION == DEBUG
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
#endif
|
||||
|
||||
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
win32_check_hr(hr);
|
||||
|
||||
|
@ -255,7 +267,12 @@ void os_init(u64 program_memory_size) {
|
|||
assert(os.crt_memset, "Missing memset in crt");
|
||||
|
||||
win32_init_window();
|
||||
|
||||
|
||||
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)
|
||||
|
@ -764,6 +781,43 @@ bool os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_byte
|
|||
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) {
|
||||
return os_file_write_string(f, data);
|
||||
}
|
||||
|
@ -962,6 +1016,107 @@ void* os_get_stack_limit() {
|
|||
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
|
||||
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}};
|
||||
|
@ -973,14 +1128,17 @@ DEFINE_GUID(IID_ISimpleAudioVolume,
|
|||
IAudioClient* win32_audio_client;
|
||||
IAudioRenderClient* win32_render_client;
|
||||
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;
|
||||
IMMDeviceEnumerator* win32_device_enumerator = 0;
|
||||
ISimpleAudioVolume* win32_audio_volume = 0;
|
||||
Mutex audio_init_mutex;
|
||||
|
||||
void
|
||||
win32_audio_init() {
|
||||
|
||||
win32_has_audio_thread_started = true;
|
||||
|
||||
win32_audio_client = 0;
|
||||
win32_render_client = 0;
|
||||
win32_audio_deactivated = 0;
|
||||
|
@ -1073,12 +1231,12 @@ win32_audio_init() {
|
|||
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;
|
||||
audio_output_format.channels = output_format->nChannels;
|
||||
audio_output_format.sample_rate = output_format->nSamplesPerSec;
|
||||
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) {
|
||||
win32_output_format.bit_width = AUDIO_BITS_32;
|
||||
audio_output_format.bit_width = AUDIO_BITS_32;
|
||||
} else {
|
||||
panic("What");
|
||||
}
|
||||
|
@ -1093,40 +1251,29 @@ win32_audio_init() {
|
|||
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_thread(Thread *t) {
|
||||
win32_audio_poll_default_device_thread(Thread *t) {
|
||||
while (!win32_has_audio_thread_started) {
|
||||
MEMORY_BARRIER;
|
||||
os_yield_thread();
|
||||
}
|
||||
|
||||
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") {
|
||||
while (!window.should_close) {
|
||||
while (win32_audio_deactivated) {
|
||||
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 ?)
|
||||
mutex_acquire_or_wait(&audio_init_mutex);
|
||||
MEMORY_BARRIER;
|
||||
mutex_release(&audio_init_mutex);
|
||||
MEMORY_BARRIER;
|
||||
|
||||
IMMDevice *now_default = 0;
|
||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(win32_device_enumerator, eRender, eConsole, &now_default);
|
||||
HRESULT hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(win32_device_enumerator, eRender, eConsole, &now_default);
|
||||
win32_check_hr(hr);
|
||||
|
||||
WCHAR *now_default_id = NULL;
|
||||
|
@ -1146,6 +1293,44 @@ win32_audio_thread(Thread *t) {
|
|||
|
||||
IMMDevice_Release(now_default);
|
||||
|
||||
os_sleep(100);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
void
|
||||
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();
|
||||
mutex_release(&audio_init_mutex);
|
||||
|
||||
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);
|
||||
mutex_acquire_or_wait(&audio_init_mutex);
|
||||
win32_audio_init();
|
||||
mutex_release(&audio_init_mutex);
|
||||
started = false;
|
||||
if (win32_audio_deactivated) {
|
||||
hr = IAudioClient_GetBufferSize(win32_audio_client, &buffer_frame_count);
|
||||
if (FAILED(hr)) win32_audio_deactivated = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (win32_audio_deactivated) continue;
|
||||
|
||||
BYTE *buffer = 0;
|
||||
|
@ -1191,9 +1376,9 @@ win32_audio_thread(Thread *t) {
|
|||
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;
|
||||
//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;
|
||||
//}
|
||||
/*float64 time = 0;
|
||||
|
@ -1209,7 +1394,7 @@ win32_audio_thread(Thread *t) {
|
|||
|
||||
|
||||
//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);
|
||||
//}
|
||||
hr = IAudioRenderClient_ReleaseBuffer(
|
||||
|
|
|
@ -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_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_s(string path, string data);
|
||||
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
|
||||
///
|
||||
void* os_get_stack_base();
|
||||
void* os_get_stack_limit();
|
||||
void*
|
||||
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 window;
|
||||
|
||||
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
// Window input
|
||||
///
|
||||
|
||||
|
||||
|
||||
void os_update();
|
|
@ -12,6 +12,8 @@ typedef struct string {
|
|||
u8 *data;
|
||||
} string;
|
||||
|
||||
const string null_string = {0, 0};
|
||||
|
||||
#define fixed_string STR
|
||||
#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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
||||
if (right.count + left.count == 0) return null_string;
|
||||
if (left.count == 0) return right;
|
||||
if (right.count == 0) return left;
|
||||
|
||||
string result;
|
||||
result.count = left.count + right.count;
|
||||
result.data = cast(u8*)alloc(allocator, result.count);
|
||||
|
|
|
@ -83,6 +83,13 @@ u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list ar
|
|||
|
||||
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) {
|
||||
u64 formatted_length = format_string_to_buffer((char*)buffer, buffer_size, fmt, args);
|
||||
|
||||
|
|
|
@ -333,8 +333,7 @@ void test_strings() {
|
|||
// Test handling of empty strings
|
||||
string empty_str = STR("");
|
||||
string concat_empty_str = string_concat(empty_str, empty_str, heap);
|
||||
assert(concat_empty_str.count == 0, "Failed: string_concat with empty strings");
|
||||
dealloc_string(heap, concat_empty_str);
|
||||
assert(concat_empty_str.count == 0 && !concat_empty_str.data, "Failed: string_concat with empty strings");
|
||||
|
||||
// Test very large strings (performance test)
|
||||
string large_str1 = alloc_string(heap, 1024 * 1024);
|
||||
|
@ -1253,4 +1252,6 @@ void oogabooga_run_tests() {
|
|||
print("Testing radix sort... ");
|
||||
test_sort();
|
||||
print("OK!\n");
|
||||
|
||||
print("All tests ok!\n");
|
||||
}
|
|
@ -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_IMAGE_IMPLEMENTATION
|
||||
|
||||
|
@ -15,6 +120,12 @@ void *third_party_malloc(size_t size) {
|
|||
if (!size) return 0;
|
||||
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) {
|
||||
assert(third_party_allocator.proc, "No third party allocator was set, but it was used!");
|
||||
if (!p) return;
|
||||
|
@ -49,11 +160,3 @@ size_t stbtt_strlen(const char* str) {
|
|||
#undef C
|
||||
#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"
|
8816
oogabooga/third_party/dr_wav.h
vendored
8816
oogabooga/third_party/dr_wav.h
vendored
File diff suppressed because it is too large
Load diff
144
oogabooga/third_party/stb_vorbis.c
vendored
144
oogabooga/third_party/stb_vorbis.c
vendored
|
@ -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
|
||||
// http://nothings.org/stb_vorbis/
|
||||
//
|
||||
|
@ -78,8 +163,11 @@
|
|||
#define STB_VORBIS_NO_STDIO 1
|
||||
#endif
|
||||
|
||||
// #Modified Charlie Malmqvist 2024-07-14
|
||||
#undef STB_VORBIS_NO_STDIO
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h> // #Modified Charlie Malmqvist 2024-07-14
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -249,8 +337,8 @@ extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
|||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// of callback to your code. (But if you don't support seeking, you may
|
||||
// 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,
|
||||
// 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);
|
||||
// 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.
|
||||
// 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
|
||||
|
@ -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
|
||||
// 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);
|
||||
// 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.
|
||||
// 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
|
||||
|
@ -434,7 +522,7 @@ enum STBVorbisError
|
|||
// #define STB_VORBIS_NO_PULLDATA_API
|
||||
|
||||
// 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)
|
||||
// #define STB_VORBIS_NO_STDIO
|
||||
|
||||
|
@ -558,6 +646,9 @@ enum STBVorbisError
|
|||
#define STB_VORBIS_NO_STDIO 1
|
||||
#endif
|
||||
|
||||
// #Modified Charlie Malmqvist 2024-07-14
|
||||
#undef STB_VORBIS_NO_STDIO
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
|
||||
|
||||
|
@ -575,7 +666,7 @@ enum STBVorbisError
|
|||
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
#include <stdio.h>
|
||||
// #include <stdio.h> // #Modified Charlie Malmqvist 2024-07-14
|
||||
#endif
|
||||
|
||||
#ifndef STB_VORBIS_NO_CRT
|
||||
|
@ -799,7 +890,7 @@ struct stb_vorbis
|
|||
|
||||
// input config
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
FILE *f;
|
||||
File f;
|
||||
uint32 f_start;
|
||||
int close_on_free;
|
||||
#endif
|
||||
|
@ -928,8 +1019,8 @@ static int error(vorb *f, enum STBVorbisError e)
|
|||
|
||||
#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_free(f,p) (void)0
|
||||
#define temp_alloc(f,size) alloca(size) // #Modified
|
||||
#define temp_free(f,p) (void)0;
|
||||
#define temp_alloc_save(f) ((f)->temp_offset)
|
||||
#define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
|
||||
|
||||
|
@ -1241,7 +1332,8 @@ static int vorbis_validate(uint8 *data)
|
|||
// (formula implied by specification)
|
||||
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;
|
||||
++r; // floor() to avoid _ftol() when non-CRT
|
||||
if (pow((float) r+1, dim) <= entries)
|
||||
|
@ -1344,6 +1436,7 @@ static uint8 get8(vorb *z)
|
|||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
{
|
||||
|
||||
int c = fgetc(z->f);
|
||||
if (c == EOF) { z->eof = TRUE; return 0; }
|
||||
return c;
|
||||
|
@ -5050,7 +5143,7 @@ int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
|
|||
|
||||
#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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
|
||||
if (0 != fopen_s(&f, filename, "rb"))
|
||||
f = NULL;
|
||||
#else
|
||||
File f;
|
||||
// #Modified (no open_s) Charlie Malmqvist 2024-07-14
|
||||
f = fopen(filename, "rb");
|
||||
#endif
|
||||
if (f)
|
||||
return stb_vorbis_open_file(f, TRUE, error, alloc);
|
||||
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;
|
||||
offset = data_len = 0;
|
||||
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) {
|
||||
stb_vorbis_close(v);
|
||||
return -2;
|
||||
|
@ -5369,9 +5458,9 @@ int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_
|
|||
if (offset + limit > total) {
|
||||
short *data2;
|
||||
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) {
|
||||
free(data);
|
||||
third_party_free(data); // #Modified (free -> third_party_free) Charlie Malmqvist 2024-07-14
|
||||
stb_vorbis_close(v);
|
||||
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;
|
||||
offset = data_len = 0;
|
||||
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) {
|
||||
stb_vorbis_close(v);
|
||||
return -2;
|
||||
|
@ -5409,9 +5498,9 @@ int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *samp
|
|||
if (offset + limit > total) {
|
||||
short *data2;
|
||||
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) {
|
||||
free(data);
|
||||
third_party_free(data); // #Modified (free -> third_party_free) Charlie Malmqvist 2024-07-14
|
||||
stb_vorbis_close(v);
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
Reference in a new issue