Spacial audio, draw_line, vector procs
This commit is contained in:
parent
c34319796f
commit
c6bf5bc8bb
11 changed files with 288 additions and 33 deletions
7
TODO
7
TODO
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
- Audio
|
- Audio
|
||||||
- Player volume control
|
- Player volume control
|
||||||
- Spatial audio
|
|
||||||
- Optimize
|
- Optimize
|
||||||
- Spam simd
|
- Spam simd
|
||||||
- Concurrent jobs for players?
|
- Concurrent jobs for players?
|
||||||
|
@ -20,11 +19,6 @@
|
||||||
- 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.
|
- 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
|
- 24-Bit audio conversion doesn't really work
|
||||||
|
|
||||||
- Juice
|
|
||||||
- draw_line
|
|
||||||
- vx_length
|
|
||||||
- Occlude quads out of view
|
|
||||||
|
|
||||||
- General bugs & issues
|
- General bugs & issues
|
||||||
- Release freeze in run_tests
|
- Release freeze in run_tests
|
||||||
|
|
||||||
|
@ -32,3 +26,4 @@
|
||||||
- Audio format channel conversions
|
- Audio format channel conversions
|
||||||
- sample rate downsampling
|
- sample rate downsampling
|
||||||
- non stereo or mono audio
|
- non stereo or mono audio
|
||||||
|
- Audio spacialization on anything that's not stereo
|
6
build.c
6
build.c
|
@ -3,6 +3,8 @@
|
||||||
///
|
///
|
||||||
// Build config stuff
|
// Build config stuff
|
||||||
|
|
||||||
|
#define OOGABOOGA_DEV 1
|
||||||
|
|
||||||
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
|
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
|
||||||
|
|
||||||
typedef struct Context_Extra {
|
typedef struct Context_Extra {
|
||||||
|
@ -26,13 +28,13 @@ typedef struct Context_Extra {
|
||||||
//
|
//
|
||||||
|
|
||||||
// This is a minimal starting point for new projects. Copy & rename to get started
|
// This is a minimal starting point for new projects. Copy & rename to get started
|
||||||
#include "oogabooga/examples/minimal_game_loop.c"
|
// #include "oogabooga/examples/minimal_game_loop.c"
|
||||||
|
|
||||||
// #include "oogabooga/examples/text_rendering.c"
|
// #include "oogabooga/examples/text_rendering.c"
|
||||||
// #include "oogabooga/examples/custom_logger.c"
|
// #include "oogabooga/examples/custom_logger.c"
|
||||||
// #include "oogabooga/examples/renderer_stress_test.c"
|
// #include "oogabooga/examples/renderer_stress_test.c"
|
||||||
// #include "oogabooga/examples/tile_game.c"
|
// #include "oogabooga/examples/tile_game.c"
|
||||||
// #include "oogabooga/examples/audio_test.c"
|
#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"
|
||||||
|
|
|
@ -1,3 +1,23 @@
|
||||||
|
## v0.01.001 - Spacial audio,
|
||||||
|
- Audio
|
||||||
|
- Implemented spacial audio playback
|
||||||
|
Simply set player->position (it's in ndc space (-1 to 1), see audio_test.c)
|
||||||
|
Save some computation with player->disable_spacialization = true
|
||||||
|
- Added position overloads for play_one_clip
|
||||||
|
play_one_audio_clip_source_at_position(source, pos)
|
||||||
|
play_one_audio_clip_at_position(path, pos)
|
||||||
|
- Renderer
|
||||||
|
- Added draw_line(p0, p1, width, color)
|
||||||
|
- Implemented culling of quads out of view
|
||||||
|
|
||||||
|
- Misc
|
||||||
|
- Added some useful Vector procedures:
|
||||||
|
vx_length()
|
||||||
|
vx_normalize()
|
||||||
|
vx_average()
|
||||||
|
vx_dot()
|
||||||
|
vx_abs()
|
||||||
|
vx_cross()
|
||||||
|
|
||||||
## v0.01.000 - AUDIO!
|
## v0.01.000 - AUDIO!
|
||||||
- Added audio sources
|
- Added audio sources
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
void play_one_audio_clip_source(Audio_Source source);
|
void play_one_audio_clip_source(Audio_Source source);
|
||||||
void play_one_audio_clip(string path);
|
void play_one_audio_clip(string path);
|
||||||
|
void play_one_audio_clip_source_at_position(Audio_Source source, Vector3 pos);
|
||||||
|
void play_one_audio_clip_at_position(string path, Vector3 pos);
|
||||||
|
|
||||||
Playing audio (with players):
|
Playing audio (with players):
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@
|
||||||
float64 audio_player_get_current_progression_factor(Audio_Player *p);
|
float64 audio_player_get_current_progression_factor(Audio_Player *p);
|
||||||
void audio_player_set_source(Audio_Player *p, Audio_Source src, bool retain_progression_factor);
|
void audio_player_set_source(Audio_Player *p, Audio_Source src, bool retain_progression_factor);
|
||||||
void audio_player_clear_source(Audio_Player *p);
|
void audio_player_clear_source(Audio_Player *p);
|
||||||
|
void audio_player_clear_source(Audio_Player *p);
|
||||||
void audio_player_set_looping(Audio_Player *p, bool looping);
|
void audio_player_set_looping(Audio_Player *p, bool looping);
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -1154,10 +1157,14 @@ typedef struct Audio_Player {
|
||||||
u64 fade_frames;
|
u64 fade_frames;
|
||||||
u64 fade_frames_total;
|
u64 fade_frames_total;
|
||||||
bool release_when_done;
|
bool release_when_done;
|
||||||
|
|
||||||
// I think we only need to sync when audio thread samples the source, which should be
|
// I think we only need to sync when audio thread samples the source, which should be
|
||||||
// very quick and low contention, hence a spinlock.
|
// very quick and low contention, hence a spinlock.
|
||||||
Spinlock sample_lock;
|
Spinlock sample_lock;
|
||||||
|
|
||||||
|
// These can be set safely
|
||||||
|
Vector3 position; // ndc space -1 to 1
|
||||||
|
bool disable_spacialization;
|
||||||
|
|
||||||
} Audio_Player;
|
} Audio_Player;
|
||||||
#define AUDIO_PLAYERS_PER_BLOCK 128
|
#define AUDIO_PLAYERS_PER_BLOCK 128
|
||||||
typedef struct Audio_Player_Block {
|
typedef struct Audio_Player_Block {
|
||||||
|
@ -1325,14 +1332,20 @@ Hash_Table just_audio_clips;
|
||||||
bool just_audio_clips_initted = false;
|
bool just_audio_clips_initted = false;
|
||||||
|
|
||||||
void
|
void
|
||||||
play_one_audio_clip_source(Audio_Source source) {
|
play_one_audio_clip_source_at_position(Audio_Source source, Vector3 pos) {
|
||||||
Audio_Player *p = audio_player_get_one();
|
Audio_Player *p = audio_player_get_one();
|
||||||
audio_player_set_source(p, source, false);
|
audio_player_set_source(p, source, false);
|
||||||
audio_player_set_state(p, AUDIO_PLAYER_STATE_PLAYING);
|
audio_player_set_state(p, AUDIO_PLAYER_STATE_PLAYING);
|
||||||
|
p->position = pos;
|
||||||
p->release_when_done = true;
|
p->release_when_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void inline
|
||||||
|
play_one_audio_clip_source(Audio_Source source) {
|
||||||
|
play_one_audio_clip_source_at_position(source, v3(0, 0, 0));
|
||||||
|
}
|
||||||
void
|
void
|
||||||
play_one_audio_clip(string path) {
|
play_one_audio_clip_at_position(string path, Vector3 pos) {
|
||||||
if (!just_audio_clips_initted) {
|
if (!just_audio_clips_initted) {
|
||||||
just_audio_clips_initted = true;
|
just_audio_clips_initted = true;
|
||||||
just_audio_clips = make_hash_table(string, Audio_Source, get_heap_allocator());
|
just_audio_clips = make_hash_table(string, Audio_Source, get_heap_allocator());
|
||||||
|
@ -1340,7 +1353,7 @@ play_one_audio_clip(string path) {
|
||||||
|
|
||||||
Audio_Source *src_ptr = hash_table_find(&just_audio_clips, path);
|
Audio_Source *src_ptr = hash_table_find(&just_audio_clips, path);
|
||||||
if (src_ptr) {
|
if (src_ptr) {
|
||||||
play_one_audio_clip_source(*src_ptr);
|
play_one_audio_clip_source_at_position(*src_ptr, pos);
|
||||||
} else {
|
} else {
|
||||||
Audio_Source new_src;
|
Audio_Source new_src;
|
||||||
bool ok = audio_open_source_load(&new_src, path, get_heap_allocator());
|
bool ok = audio_open_source_load(&new_src, path, get_heap_allocator());
|
||||||
|
@ -1349,8 +1362,13 @@ play_one_audio_clip(string path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hash_table_add(&just_audio_clips, path, new_src);
|
hash_table_add(&just_audio_clips, path, new_src);
|
||||||
play_one_audio_clip_source(new_src);
|
play_one_audio_clip_source_at_position(new_src, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void inline
|
||||||
|
play_one_audio_clip(string path) {
|
||||||
|
play_one_audio_clip_at_position(path, v3(0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1406,6 +1424,131 @@ audio_apply_fade_out(void *frames, u64 number_of_frames, Audio_Format format,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spacialize_audio_mono(void* frames, Audio_Format format, u64 number_of_frames, Vector3 pos) {
|
||||||
|
// No idea if this actually gives the perception of audio being positioned.
|
||||||
|
// I also don't have a mono audio device to test it.
|
||||||
|
float* audio_data = (float*)frames;
|
||||||
|
|
||||||
|
float distance = sqrtf(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z);
|
||||||
|
float attenuation = 1.0f / (1.0f + distance);
|
||||||
|
|
||||||
|
float alpha = 0.1f;
|
||||||
|
float prev_sample = 0.0f;
|
||||||
|
|
||||||
|
u64 comp_size = get_audio_bit_width_byte_size(format.bit_width);
|
||||||
|
u64 frame_size = comp_size * format.channels;
|
||||||
|
|
||||||
|
for (u64 i = 0; i < number_of_frames; ++i) {
|
||||||
|
float sample = audio_data[i];
|
||||||
|
convert_one_component(
|
||||||
|
&sample,
|
||||||
|
AUDIO_BITS_32,
|
||||||
|
(u8*)frames+i*frame_size,
|
||||||
|
format.bit_width
|
||||||
|
);
|
||||||
|
|
||||||
|
sample *= attenuation;
|
||||||
|
|
||||||
|
sample = alpha * sample + (1.0f - alpha) * prev_sample;
|
||||||
|
prev_sample = sample;
|
||||||
|
|
||||||
|
convert_one_component(
|
||||||
|
(u8*)frames+i*frame_size,
|
||||||
|
format.bit_width,
|
||||||
|
&sample,
|
||||||
|
AUDIO_BITS_32
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void spacialize_audio(void* frames, Audio_Format format, u64 number_of_frames, Vector3 pos) {
|
||||||
|
|
||||||
|
if (format.channels == 1) {
|
||||||
|
spacialize_audio_mono(frames, format, number_of_frames, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance = sqrtf(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z);
|
||||||
|
float attenuation = 1.0f / (1.0f + distance);
|
||||||
|
|
||||||
|
float left_right_pan = (pos.x + 1.0f) * 0.5f;
|
||||||
|
float up_down_pan = (pos.y + 1.0f) * 0.5f;
|
||||||
|
float front_back_pan = (pos.z + 1.0f) * 0.5f;
|
||||||
|
|
||||||
|
u64 comp_size = get_audio_bit_width_byte_size(format.bit_width);
|
||||||
|
u64 frame_size = comp_size * format.channels;
|
||||||
|
|
||||||
|
float high_pass_coeff = 0.8f + 0.2f * up_down_pan;
|
||||||
|
float low_pass_coeff = 1.0f - high_pass_coeff;
|
||||||
|
|
||||||
|
// Apply gains to each frame
|
||||||
|
for (u64 i = 0; i < number_of_frames; ++i) {
|
||||||
|
for (u64 c = 0; c < format.channels; ++c) {
|
||||||
|
// Convert whatever to float -1 to 1
|
||||||
|
float sample;
|
||||||
|
convert_one_component(
|
||||||
|
&sample,
|
||||||
|
AUDIO_BITS_32,
|
||||||
|
(u8*)frames+i*frame_size+c*comp_size,
|
||||||
|
format.bit_width
|
||||||
|
);
|
||||||
|
float gain = 1.0f / format.channels;
|
||||||
|
|
||||||
|
if (format.channels == 2) {
|
||||||
|
|
||||||
|
// time delay and phase shift for vertical position
|
||||||
|
float time_delay = (up_down_pan - 0.5f) * 0.0005f; // 0.5ms delay range
|
||||||
|
float phase_shift = (up_down_pan - 0.5f) * 0.5f; // 0.5 radians phase shift range
|
||||||
|
|
||||||
|
// Stereo
|
||||||
|
if (c == 0) {
|
||||||
|
gain = (1.0f - left_right_pan) * attenuation;
|
||||||
|
sample = sample * cos(phase_shift) - sample * sin(phase_shift);
|
||||||
|
} else if (c == 1) {
|
||||||
|
gain = left_right_pan * attenuation;
|
||||||
|
sample = sample * cos(phase_shift) + sample * sin(phase_shift);
|
||||||
|
}
|
||||||
|
} else if (format.channels == 4) {
|
||||||
|
// Quadraphonic sound (left-right, front-back)
|
||||||
|
if (c == 0) {
|
||||||
|
gain = (1.0f - left_right_pan) * (1.0f - front_back_pan) * attenuation;
|
||||||
|
} else if (c == 1) {
|
||||||
|
gain = left_right_pan * (1.0f - front_back_pan) * attenuation;
|
||||||
|
} else if (c == 2) {
|
||||||
|
gain = (1.0f - left_right_pan) * front_back_pan * attenuation;
|
||||||
|
} else if (c == 3) {
|
||||||
|
gain = left_right_pan * front_back_pan * attenuation;
|
||||||
|
}
|
||||||
|
} else if (format.channels == 6) {
|
||||||
|
// 5.1 surround sound (left, right, center, LFE, rear left, rear right)
|
||||||
|
if (c == 0) {
|
||||||
|
gain = (1.0f - left_right_pan) * attenuation;
|
||||||
|
} else if (c == 1) {
|
||||||
|
gain = left_right_pan * attenuation;
|
||||||
|
} else if (c == 2) {
|
||||||
|
gain = (1.0f - front_back_pan) * attenuation;
|
||||||
|
} else if (c == 3) {
|
||||||
|
gain = 0.5f * attenuation; // LFE (subwoofer) channel
|
||||||
|
} else if (c == 4) {
|
||||||
|
gain = (1.0f - left_right_pan) * front_back_pan * attenuation;
|
||||||
|
} else if (c == 5) {
|
||||||
|
gain = left_right_pan * front_back_pan * attenuation;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No idea what device this is, just distribute equally
|
||||||
|
gain = attenuation / format.channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
sample *= gain;
|
||||||
|
// Convert back to whatever
|
||||||
|
convert_one_component(
|
||||||
|
(u8*)frames+i*frame_size+c*comp_size,
|
||||||
|
format.bit_width,
|
||||||
|
&sample,
|
||||||
|
AUDIO_BITS_32
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is supposed to be called by OS layer audio thread whenever it wants more audio samples
|
// This is supposed to be called by OS layer audio thread whenever it wants more audio samples
|
||||||
void
|
void
|
||||||
do_program_audio_sample(u64 number_of_output_frames, Audio_Format out_format,
|
do_program_audio_sample(u64 number_of_output_frames, Audio_Format out_format,
|
||||||
|
@ -1581,6 +1724,10 @@ do_program_audio_sample(u64 number_of_output_frames, Audio_Format out_format,
|
||||||
assert(converted == number_of_output_frames);
|
assert(converted == number_of_output_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!p->disable_spacialization) {
|
||||||
|
spacialize_audio(mix_buffer, out_format, number_of_output_frames, p->position);
|
||||||
|
}
|
||||||
|
|
||||||
mix_frames(output, mix_buffer, number_of_output_frames, out_format);
|
mix_frames(output, mix_buffer, number_of_output_frames, out_format);
|
||||||
|
|
||||||
mutex_release(&src.mutex_for_destroy);
|
mutex_release(&src.mutex_for_destroy);
|
||||||
|
|
|
@ -127,12 +127,23 @@ void pop_z_layer() {
|
||||||
draw_frame.z_count -= 1;
|
draw_frame.z_count -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Draw_Quad _nil_quad = {0};
|
||||||
Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip) {
|
Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip) {
|
||||||
quad.bottom_left = m4_transform(world_to_clip, v4(v2_expand(quad.bottom_left), 0, 1)).xy;
|
quad.bottom_left = m4_transform(world_to_clip, v4(v2_expand(quad.bottom_left), 0, 1)).xy;
|
||||||
quad.top_left = m4_transform(world_to_clip, v4(v2_expand(quad.top_left), 0, 1)).xy;
|
quad.top_left = m4_transform(world_to_clip, v4(v2_expand(quad.top_left), 0, 1)).xy;
|
||||||
quad.top_right = m4_transform(world_to_clip, v4(v2_expand(quad.top_right), 0, 1)).xy;
|
quad.top_right = m4_transform(world_to_clip, v4(v2_expand(quad.top_right), 0, 1)).xy;
|
||||||
quad.bottom_right = m4_transform(world_to_clip, v4(v2_expand(quad.bottom_right), 0, 1)).xy;
|
quad.bottom_right = m4_transform(world_to_clip, v4(v2_expand(quad.bottom_right), 0, 1)).xy;
|
||||||
|
|
||||||
|
bool should_cull =
|
||||||
|
(quad.bottom_left.x < -1 || quad.bottom_left.x > 1 || quad.bottom_left.y < -1 || quad.bottom_left.y > 1)
|
||||||
|
&& (quad.top_left.x < -1 || quad.top_left.x > 1 || quad.top_left.y < -1 || quad.top_left.y > 1)
|
||||||
|
&& (quad.top_right.x < -1 || quad.top_right.x > 1 || quad.top_right.y < -1 || quad.top_right.y > 1)
|
||||||
|
&& (quad.bottom_right.x < -1 || quad.bottom_right.x > 1 || quad.bottom_right.y < -1 || quad.bottom_right.y > 1);
|
||||||
|
|
||||||
|
if (should_cull) {
|
||||||
|
return &_nil_quad;
|
||||||
|
}
|
||||||
|
|
||||||
quad.image_min_filter = GFX_FILTER_MODE_NEAREST;
|
quad.image_min_filter = GFX_FILTER_MODE_NEAREST;
|
||||||
quad.image_mag_filter = GFX_FILTER_MODE_NEAREST;
|
quad.image_mag_filter = GFX_FILTER_MODE_NEAREST;
|
||||||
|
|
||||||
|
@ -272,6 +283,16 @@ Gfx_Text_Metrics draw_text_and_measure(Gfx_Font *font, string text, u32 raster_h
|
||||||
return measure_text(font, text, raster_height, scale);
|
return measure_text(font, text, raster_height, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw_line(Vector2 p0, Vector2 p1, float line_width, Vector4 color) {
|
||||||
|
Vector2 dir = v2(p1.x - p0.x, p1.y - p0.y);
|
||||||
|
float length = sqrt(dir.x * dir.x + dir.y * dir.y);
|
||||||
|
float r = atan2(-dir.y, dir.x);
|
||||||
|
Matrix4 line_xform = m4_scalar(1);
|
||||||
|
line_xform = m4_translate(line_xform, v3(p0.x, p0.y, 0));
|
||||||
|
line_xform = m4_rotate_z(line_xform, r);
|
||||||
|
line_xform = m4_translate(line_xform, v3(0, -line_width/2, 0));
|
||||||
|
draw_rect_xform(line_xform, v2(length, line_width), color);
|
||||||
|
}
|
||||||
|
|
||||||
#define COLOR_RED ((Vector4){1.0, 0.0, 0.0, 1.0})
|
#define COLOR_RED ((Vector4){1.0, 0.0, 0.0, 1.0})
|
||||||
#define COLOR_GREEN ((Vector4){0.0, 1.0, 0.0, 1.0})
|
#define COLOR_GREEN ((Vector4){0.0, 1.0, 0.0, 1.0})
|
||||||
|
|
|
@ -57,8 +57,13 @@ int entry(int argc, char **argv) {
|
||||||
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_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)) {
|
if (is_key_just_pressed(MOUSE_BUTTON_RIGHT)) {
|
||||||
|
float mx = input_frame.mouse_x;
|
||||||
|
float my = input_frame.mouse_y;
|
||||||
// Easy mode (when you don't care and just want to play a clip)
|
// Easy mode (when you don't care and just want to play a clip)
|
||||||
play_one_audio_clip(STR("oogabooga/examples/block.wav"));
|
Vector3 p = v3(mx/(f32)window.width*2.0-1, my/(f32)window.height*2.0-1, 0);
|
||||||
|
log("%f, %f", p.x, p.y);
|
||||||
|
play_one_audio_clip_at_position(STR("oogabooga/examples/block.wav"), p);
|
||||||
|
// Or just play_one_audio_clip if you don't care about spacialization
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,12 @@ int entry(int argc, char **argv) {
|
||||||
|
|
||||||
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
|
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
|
||||||
|
|
||||||
|
float aspect = (f32)window.width/(f32)window.height;
|
||||||
|
float mx = (input_frame.mouse_x/(f32)window.width * 2.0 - 1.0)*aspect;
|
||||||
|
float my = input_frame.mouse_y/(f32)window.height * 2.0 - 1.0;
|
||||||
|
|
||||||
|
draw_line(v2(-.75, -.75), v2(mx, my), 0.005, COLOR_WHITE);
|
||||||
|
|
||||||
os_update();
|
os_update();
|
||||||
gfx_update();
|
gfx_update();
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,22 +127,81 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #Simd
|
||||||
|
inline float32 v2_length(LMATH_ALIGN Vector2 a) {
|
||||||
|
return sqrt(a.x*a.x + a.y*a.y);
|
||||||
|
}
|
||||||
inline Vector2 v2_normalize(LMATH_ALIGN Vector2 a) {
|
inline Vector2 v2_normalize(LMATH_ALIGN Vector2 a) {
|
||||||
float32 length = sqrt(a.x * a.x + a.y * a.y);
|
float32 length = v2_length(a);
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return (Vector2){0, 0};
|
return (Vector2){0, 0};
|
||||||
}
|
}
|
||||||
return v2_divf(a, length);
|
return v2_divf(a, length);
|
||||||
}
|
}
|
||||||
|
inline float32 v2_average(LMATH_ALIGN Vector2 a) {
|
||||||
inline float v2_dot_product(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
|
return (a.x+a.y)/2.0;
|
||||||
|
}
|
||||||
|
inline Vector2 v2_abs(LMATH_ALIGN Vector2 a) {
|
||||||
|
return v2(fabsf(a.x), fabsf(a.y));
|
||||||
|
}
|
||||||
|
inline float32 v2_cross(LMATH_ALIGN Vector2 a, LMATH_ALIGN Vector2 b) {
|
||||||
|
return (a.x * b.y) - (a.y * b.x);
|
||||||
|
}
|
||||||
|
inline float v2_dot(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(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
|
|
||||||
|
inline float32 v3_length(LMATH_ALIGN Vector3 a) {
|
||||||
|
return sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 v3_normalize(LMATH_ALIGN Vector3 a) {
|
||||||
|
float32 length = v3_length(a);
|
||||||
|
if (length == 0) {
|
||||||
|
return (Vector3){0, 0, 0};
|
||||||
|
}
|
||||||
|
return v3_divf(a, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float32 v3_average(LMATH_ALIGN Vector3 a) {
|
||||||
|
return (a.x + a.y + a.z) / 3.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 v3_abs(LMATH_ALIGN Vector3 a) {
|
||||||
|
return v3(fabsf(a.x), fabsf(a.y), fabsf(a.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Vector3 v3_cross(LMATH_ALIGN Vector3 a, LMATH_ALIGN Vector3 b) {
|
||||||
|
return (Vector3){
|
||||||
|
(a.y * b.z) - (a.z * b.y),
|
||||||
|
(a.z * b.x) - (a.x * b.z),
|
||||||
|
(a.x * b.y) - (a.y * b.x)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
inline float v3_dot(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(LMATH_ALIGN Vector4 a, LMATH_ALIGN Vector4 b) {
|
inline float32 v4_length(LMATH_ALIGN Vector4 a) {
|
||||||
|
return sqrt(a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 v4_normalize(LMATH_ALIGN Vector4 a) {
|
||||||
|
float32 length = v4_length(a);
|
||||||
|
if (length == 0) {
|
||||||
|
return (Vector4){0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
return v4_divf(a, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float32 v4_average(LMATH_ALIGN Vector4 a) {
|
||||||
|
return (a.x + a.y + a.z + a.w) / 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector4 v4_abs(LMATH_ALIGN Vector4 a) {
|
||||||
|
return v4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
|
||||||
|
}
|
||||||
|
inline float v4_dot(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
|
|
||||||
#define OGB_VERSION_MAJOR 0
|
#define OGB_VERSION_MAJOR 0
|
||||||
#define OGB_VERSION_MINOR 1
|
#define OGB_VERSION_MINOR 1
|
||||||
#define OGB_VERSION_PATCH 0
|
#define OGB_VERSION_PATCH 1
|
||||||
|
|
||||||
#define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH)
|
#define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH)
|
||||||
|
|
||||||
|
|
|
@ -1011,13 +1011,13 @@ void test_linmath() {
|
||||||
assert(mixed_v4_result.x == 1.0f && mixed_v4_result.y == 2.0f && mixed_v4_result.z == 3.0f && mixed_v4_result.w == 4.0f, "Mixed Vector4 scalar multiplication failed");
|
assert(mixed_v4_result.x == 1.0f && mixed_v4_result.y == 2.0f && mixed_v4_result.z == 3.0f && mixed_v4_result.w == 4.0f, "Mixed Vector4 scalar multiplication failed");
|
||||||
|
|
||||||
|
|
||||||
float v2_dot = v2_dot_product(v2(2, 7), v2(3, 2));
|
float v2_dot_product = v2_dot(v2(2, 7), v2(3, 2));
|
||||||
float v3_dot = v3_dot_product(v3(2, 7, 2), v3(3, 2, 9));
|
float v3_dot_product = v3_dot(v3(2, 7, 2), v3(3, 2, 9));
|
||||||
float v4_dot = v4_dot_product(v4(2, 7, 6, 1), v4(3, 2, 1, 4));
|
float v4_dot_product = v4_dot(v4(2, 7, 6, 1), v4(3, 2, 1, 4));
|
||||||
|
|
||||||
assert(floats_roughly_match(v2_dot, 20), "Failed: v2_dot_product");
|
assert(floats_roughly_match(v2_dot_product, 20), "Failed: v2_dot");
|
||||||
assert(floats_roughly_match(v3_dot, 38), "Failed: v3_dot_product");
|
assert(floats_roughly_match(v3_dot_product, 38), "Failed: v3_dot");
|
||||||
assert(floats_roughly_match(v4_dot, 30), "Failed: v4_dot_product");
|
assert(floats_roughly_match(v4_dot_product, 30), "Failed: v4_dot");
|
||||||
}
|
}
|
||||||
void test_hash_table() {
|
void test_hash_table() {
|
||||||
Hash_Table table = make_hash_table(string, int, get_heap_allocator());
|
Hash_Table table = make_hash_table(string, int, get_heap_allocator());
|
||||||
|
|
8
oogabooga/third_party/stb_vorbis.c
vendored
8
oogabooga/third_party/stb_vorbis.c
vendored
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
- All FILE * stdio procedures are replaced with the equivalent for the oogabooga
|
- All FILE * stdio procedures are replaced with the equivalent for the oogabooga
|
||||||
file API.
|
file API.
|
||||||
|
- all draw_line -> stb_vorbis_draw_line
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -2125,7 +2125,7 @@ static float inverse_db_table[256] =
|
||||||
int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB
|
int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n)
|
static __forceinline void stb_vorbis_draw_line(float *output, int x0, int y0, int x1, int y1, int n)
|
||||||
{
|
{
|
||||||
int dy = y1 - y0;
|
int dy = y1 - y0;
|
||||||
int adx = x1 - x0;
|
int adx = x1 - x0;
|
||||||
|
@ -3186,13 +3186,13 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f
|
||||||
int hy = finalY[j] * g->floor1_multiplier;
|
int hy = finalY[j] * g->floor1_multiplier;
|
||||||
int hx = g->Xlist[j];
|
int hx = g->Xlist[j];
|
||||||
if (lx != hx)
|
if (lx != hx)
|
||||||
draw_line(target, lx,ly, hx,hy, n2);
|
stb_vorbis_draw_line(target, lx,ly, hx,hy, n2);
|
||||||
CHECK(f);
|
CHECK(f);
|
||||||
lx = hx, ly = hy;
|
lx = hx, ly = hy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lx < n2) {
|
if (lx < n2) {
|
||||||
// optimization of: draw_line(target, lx,ly, n,ly, n2);
|
// optimization of: stb_vorbis_draw_line(target, lx,ly, n,ly, n2);
|
||||||
for (j=lx; j < n2; ++j)
|
for (j=lx; j < n2; ++j)
|
||||||
LINE_OP(target[j], inverse_db_table[ly]);
|
LINE_OP(target[j], inverse_db_table[ly]);
|
||||||
CHECK(f);
|
CHECK(f);
|
||||||
|
|
Reference in a new issue