From: Brendan Hansen Date: Tue, 1 Mar 2022 20:40:32 +0000 (-0600) Subject: started audio library; theming X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=64ba1b9f87cbc775a57f64ae10875cbce9edfc76;p=bar-game.git started audio library; theming --- diff --git a/run_tree/assets/images/background.png b/run_tree/assets/images/background.png new file mode 100644 index 0000000..d8e1a10 Binary files /dev/null and b/run_tree/assets/images/background.png differ diff --git a/run_tree/assets/images/spritesheet.png b/run_tree/assets/images/spritesheet.png index fc47fea..b5bd7b6 100644 Binary files a/run_tree/assets/images/spritesheet.png and b/run_tree/assets/images/spritesheet.png differ diff --git a/run_tree/assets/sounds/knock-1.wav b/run_tree/assets/sounds/knock-1.wav new file mode 100644 index 0000000..f654b5a Binary files /dev/null and b/run_tree/assets/sounds/knock-1.wav differ diff --git a/run_tree/assets/sounds/prompt-1.wav b/run_tree/assets/sounds/prompt-1.wav new file mode 100644 index 0000000..4214420 Binary files /dev/null and b/run_tree/assets/sounds/prompt-1.wav differ diff --git a/run_tree/assets/sounds/walk-1.wav b/run_tree/assets/sounds/walk-1.wav new file mode 100644 index 0000000..eb822ab Binary files /dev/null and b/run_tree/assets/sounds/walk-1.wav differ diff --git a/run_tree/scenes/quick_save_new.scene b/run_tree/scenes/quick_save_new.scene index 516a9a1..8c8df20 100644 --- a/run_tree/scenes/quick_save_new.scene +++ b/run_tree/scenes/quick_save_new.scene @@ -1,3 +1,15 @@ +[Background] +id = 100 +flags = 0 +pos.x = 0 +pos.y = 0 +:RenderComponent +layer = -1 +color.r = 1 +color.g = 1 +color.b = 1 +color.a = 1 + [Wall] id = 10 flags = 2 @@ -29,10 +41,10 @@ color.a = 1.0000 [Player] id = 12 flags = 2 -pos.x = 318.3422 -pos.y = 217.0257 +pos.x = 312.5422 +pos.y = 271.0389 size.x = 16.0000 -size.y = 16.0000 +size.y = 32.0000 :MovementComponent controls.up = 87 controls.down = 83 @@ -41,10 +53,12 @@ controls.right = 68 controls.interact = 70 controls.pick_up = 71 facing = 3 +velocity.x = -0.4420 +velocity.y = 0.4767 :PlayerComponent holding = 0 :RenderComponent -layer = 0 +layer = 10 color.r = 0.0000 color.g = 1.0000 color.b = 0.0000 @@ -119,26 +133,6 @@ color.a = 1.0000 item = "beer" max_timeout = 2.0000 -[Patron] -id = 22 -flags = 3 -pos.x = 392.0000 -pos.y = 408.0000 -size.x = 16.0000 -size.y = 16.0000 -:RenderComponent -layer = 5 -color.r = 1.0000 -color.g = 0.0000 -color.b = 0.0000 -color.a = 1.0000 -:PatronComponent -state = 0 -order_item = "beer" -order_show_animation = 0.0000 -holding = 0 -consume_timeout = 0.0000 - [Wall] id = 25 flags = 2 @@ -154,12 +148,12 @@ color.b = 1.0000 color.a = 1.0000 [Wall] -id = 26 +id = 27 flags = 2 -pos.x = 424.0000 -pos.y = 592.0000 -size.x = 816.0000 -size.y = 32.0000 +pos.x = 8.0000 +pos.y = 312.0000 +size.x = 16.0000 +size.y = 592.0000 :RenderComponent layer = 0 color.r = 1.0000 @@ -168,9 +162,9 @@ color.b = 1.0000 color.a = 1.0000 [Wall] -id = 27 +id = 28 flags = 2 -pos.x = 8.0000 +pos.x = 792.0000 pos.y = 312.0000 size.x = 16.0000 size.y = 592.0000 @@ -181,22 +175,86 @@ color.g = 1.0000 color.b = 1.0000 color.a = 1.0000 -[Wall] -id = 28 +[Furniture] +id = 30 +flags = 2 +pos.x = 136.0000 +pos.y = 336.0000 +size.x = 16.0000 +size.y = 32.0000 +:RenderComponent +layer = 0 +color.r = 1.0000 +color.g = 1.0000 +color.b = 1.0000 +color.a = 1.0000 +:FurnitureComponent +furniture_type = 0 +taken = true +sprite.sheet = "./assets/images/spritesheet.png" +sprite.pos.x = 32.0000 +sprite.pos.y = 32.0000 +sprite.size.x = 16.0000 +sprite.size.y = 32.0000 +sprite.color.r = 1.0000 +sprite.color.g = 1.0000 +sprite.color.b = 1.0000 +sprite.color.a = 1.0000 + +[Furniture] +id = 31 flags = 2 -pos.x = 800.0000 -pos.y = 296.0000 +pos.x = 184.0000 +pos.y = 336.0000 +size.x = 16.0000 +size.y = 32.0000 +:RenderComponent +layer = 0 +color.r = 1.0000 +color.g = 1.0000 +color.b = 1.0000 +color.a = 1.0000 +:FurnitureComponent +furniture_type = 0 +taken = false +sprite.sheet = "./assets/images/spritesheet.png" +sprite.pos.x = 48.0000 +sprite.pos.y = 32.0000 +sprite.size.x = -16.0000 +sprite.size.y = 32.0000 +sprite.color.r = 1.0000 +sprite.color.g = 1.0000 +sprite.color.b = 1.0000 +sprite.color.a = 1.0000 + +[Furniture] +id = 32 +flags = 2 +pos.x = 160.0000 +pos.y = 336.0000 size.x = 32.0000 -size.y = 560.0000 +size.y = 32.0000 :RenderComponent layer = 0 color.r = 1.0000 color.g = 1.0000 color.b = 1.0000 color.a = 1.0000 +:FurnitureComponent +furniture_type = 1 +taken = false +sprite.sheet = "./assets/images/spritesheet.png" +sprite.pos.x = 48.0000 +sprite.pos.y = 32.0000 +sprite.size.x = 32.0000 +sprite.size.y = 32.0000 +sprite.color.r = 1.0000 +sprite.color.g = 1.0000 +sprite.color.b = 1.0000 +sprite.color.a = 1.0000 [Furniture] -id = 30 +id = 40 flags = 2 pos.x = 136.0000 pos.y = 256.0000 @@ -210,7 +268,7 @@ color.b = 1.0000 color.a = 1.0000 :FurnitureComponent furniture_type = 0 -taken = false +taken = true sprite.sheet = "./assets/images/spritesheet.png" sprite.pos.x = 32.0000 sprite.pos.y = 32.0000 @@ -222,7 +280,7 @@ sprite.color.b = 1.0000 sprite.color.a = 1.0000 [Furniture] -id = 31 +id = 41 flags = 2 pos.x = 184.0000 pos.y = 256.0000 @@ -248,7 +306,7 @@ sprite.color.b = 1.0000 sprite.color.a = 1.0000 [Furniture] -id = 32 +id = 42 flags = 2 pos.x = 160.0000 pos.y = 256.0000 @@ -273,6 +331,48 @@ sprite.color.g = 1.0000 sprite.color.b = 1.0000 sprite.color.a = 1.0000 +[Wall] +id = 35 +flags = 2 +pos.x = 192.0000 +pos.y = 592.0000 +size.x = 352.0000 +size.y = 32.0000 +:RenderComponent +layer = 0 +color.r = 1.0000 +color.g = 1.0000 +color.b = 1.0000 +color.a = 1.0000 + +[Wall] +id = 36 +flags = 2 +pos.x = 608.0000 +pos.y = 592.0000 +size.x = 352.0000 +size.y = 32.0000 +:RenderComponent +layer = 0 +color.r = 1.0000 +color.g = 1.0000 +color.b = 1.0000 +color.a = 1.0000 + +[Wall] +id = 37 +flags = 2 +pos.x = 140.0000 +pos.y = -142.0000 +size.x = 16.0000 +size.y = 16.0000 +:RenderComponent +layer = 0 +color.r = 1.0000 +color.g = 1.0000 +color.b = 1.0000 +color.a = 1.0000 + [Tap] id = 14 flags = 3 @@ -290,3 +390,24 @@ color.a = 1.0000 item = "beer" max_timeout = 2.0000 +[Patron] +id = 22 +flags = 3 +pos.x = 319.2968 +pos.y = 422.7386 +size.x = 16.0000 +size.y = 32.0000 +:RenderComponent +layer = 5 +color.r = 1.0000 +color.g = 0.0000 +color.b = 0.0000 +color.a = 1.0000 +:PatronComponent +state = 0 +seat = 30 +order_item = "beer" +order_show_animation = 0.0000 +holding = 0 +consume_timeout = 0.0000 + diff --git a/src/build.onyx b/src/build.onyx index 6264c36..1485f53 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -19,6 +19,7 @@ MINOR_VERSION :: 1 #load_all "./entity/components" #load_all "./entity/schematics" #load_all "./gfx" +#load_all "./sfx" #load_all "./utils" #load "stb_image" @@ -26,3 +27,4 @@ MINOR_VERSION :: 1 #load "modules/opengles/module" #load "modules/glfw3/module" +#load "modules/openal/module" diff --git a/src/entity/components/dispenser.onyx b/src/entity/components/dispenser.onyx index 2d3698b..512e7d8 100644 --- a/src/entity/components/dispenser.onyx +++ b/src/entity/components/dispenser.onyx @@ -49,6 +49,8 @@ DispenserComponent :: struct { // This should dynamic... item.pos = this.pos; item.size = .{16, 16}; + // if only item.flags.Carryable = false was possible... + item.flags = ~~ (cast(u32) item.flags & ~(cast(u32) Entity_Flags.Carryable)); (item->get(ItemComponent)).item = dispenser_comp.item; scene->add(item); diff --git a/src/entity/components/patron.onyx b/src/entity/components/patron.onyx index 41e2f6e..90d54ef 100644 --- a/src/entity/components/patron.onyx +++ b/src/entity/components/patron.onyx @@ -90,6 +90,8 @@ PatronComponent :: struct { if interactor->has(PlayerComponent) { patron.state = .Waiting_For_Order; patron.order_show_animation = 1.0f; + + Audio_Manager.play_sound("./assets/sounds/prompt-1.wav"); } } @@ -129,7 +131,7 @@ PatronComponent :: struct { r.y += 2; r.w -= 4; r.h -= 4; - immediate_set_color(.{1, 1, 1}); + immediate_set_color(.{0.9, 0.9, 0.9}); immediate_rectangle(r.x, r.y, r.w, r.h); r.x += 2; diff --git a/src/entity/components/player.onyx b/src/entity/components/player.onyx index e552b9f..0501ba1 100644 --- a/src/entity/components/player.onyx +++ b/src/entity/components/player.onyx @@ -90,6 +90,8 @@ PlayerComponent :: struct { render :: (use this: ^Entity) { rect := Entity.get_rect(this); + rect.y -= rect.h; + rect.h *= 2; immediate_subimage(^Spritesheet, rect.x, rect.y, rect.w, rect.h, 0*16, 4*16, 16, 16); } diff --git a/src/entity/editor.onyx b/src/entity/editor.onyx index 753bb8c..17cb769 100644 --- a/src/entity/editor.onyx +++ b/src/entity/editor.onyx @@ -79,7 +79,7 @@ editor_update :: (dt: f32) { for scene.entities { if Entity.get_rect(it) |> Rect.contains(mouse_pos) { selected_entity_id = it.id; - break; + // break; } } diff --git a/src/entity/manager.onyx b/src/entity/manager.onyx index c205a23..7f45403 100644 --- a/src/entity/manager.onyx +++ b/src/entity/manager.onyx @@ -143,6 +143,8 @@ Entity_Manager :: struct { query :: entity_manager_query; query_by_flags :: entity_manager_query_by_flags; + count_by_component :: entity_manager_count_by_component; + query_by_component :: entity_manager_query_by_component; create_component :: entity_manager_create_component; create_and_add :: entity_manager_create_and_add; @@ -339,6 +341,17 @@ entity_manager_delete :: (use this: ^Entity_Manager, ent: ^Entity, delete_from_a raw_free(entity_allocator, ent); } +entity_manager_count_by_component :: (use this: ^Entity_Manager, comp_type: type_expr) -> u32 { + count := 0; + for entities { + if it->has(comp_type) { + count += 1; + } + } + + return count; +} + entity_manager_query :: (use this: ^Entity_Manager, area: Rect) -> [] ^Entity { ents: [..] ^Entity; for entities { diff --git a/src/entity/schematics/background.onyx b/src/entity/schematics/background.onyx new file mode 100644 index 0000000..0d294c4 --- /dev/null +++ b/src/entity/schematics/background.onyx @@ -0,0 +1,33 @@ + +use package core + +Background :: struct { + #struct_tag Entity_Schematic.{ + (scene) => { + this := scene->make(); + this.pos = .{0, 0}; + this.size = .{0, 0}; + + scene->create_and_add(this, RenderComponent) { + comp.func = Background.render; + } + + queue_assets(^Background.assets); + load_assets(); + + return this; + } + } + + render :: (this: ^Entity) { + size :: 10000.0f + immediate_set_color(.{1, 1, 1}); + immediate_subimage(^assets.texture, this.pos.x, this.pos.y, size, size, 0, 0, size, size); + } + + #persist assets: struct { + #tag "./assets/images/background.png" + #tag Texture_Wrap.Repeat + texture: Texture; + } +} \ No newline at end of file diff --git a/src/entity/schematics/player.onyx b/src/entity/schematics/player.onyx index 40490f2..3d51622 100644 --- a/src/entity/schematics/player.onyx +++ b/src/entity/schematics/player.onyx @@ -41,6 +41,10 @@ Player :: struct { this.size = .{32, 32}; this.flags |= .Solid; + scene->create_and_add(this, SizeComponent) { + comp.func = (use this: ^Entity) => Rect.{pos.x - size.x / 2, pos.y, size.x, size.y / 2}; + } + scene->create_and_add(this, MovementComponent) { comp.controls = controls; } diff --git a/src/game.onyx b/src/game.onyx index 242854d..fb5f832 100644 --- a/src/game.onyx +++ b/src/game.onyx @@ -16,6 +16,8 @@ scene_canvas: Canvas; Spritesheet: Texture; game_init :: () { + Audio_Manager.init(); + scene_canvas = canvas_make(800, 600); // This process of queueing the asset bucket should @@ -34,6 +36,8 @@ game_init :: () { #local quick_save_file := "scenes/quick_save_new.scene"; game_update :: (dt: f32) { + Audio_Manager.tick(); + if is_key_just_up(GLFW_KEY_F8) { debug_log(.Info, "Saving to '{}'.", quick_save_file); scene->save_to_file(quick_save_file); diff --git a/src/sfx/audio_manager.onyx b/src/sfx/audio_manager.onyx new file mode 100644 index 0000000..e7aa85a --- /dev/null +++ b/src/sfx/audio_manager.onyx @@ -0,0 +1,98 @@ + +use package core +use package openal + +Sound :: struct { + buffer: u32; +} + +Audio_Manager :: struct { + init :: () { + map.init(^loaded_sounds); + + alGetError(); + device = alcOpenDevice(null); + audio_context = alcCreateContext(device, null); + alcMakeContextCurrent(audio_context); + + if alGetError() != AL_NO_ERROR { + debug_log(.Critical, "Error creating audio context!!"); + } + } + + deinit :: () { + alcMakeContextCurrent(~~ cast(u64) 0); + alcDestroyContext(audio_context); + alcCloseDevice(device); + } + + get_sound :: (path: str) -> Sound { + if loaded_sounds->has(path) { + return loaded_sounds[path]; + } + + wav_file := load_wav_file(path); + + alGetError(); + + buffer: u32; + alGenBuffers(1, ^buffer); + if alGetError() != AL_NO_ERROR { + debug_log(.Error, "Error creating audio buffer!"); + return .{0}; + } + + al_format: u32; + switch wav_file.format { + case .Mono8 do al_format = AL_FORMAT_MONO8; + case .Mono16 do al_format = AL_FORMAT_MONO16; + case .Stereo8 do al_format = AL_FORMAT_STEREO8; + case .Stereo16 do al_format = AL_FORMAT_STEREO16; + } + + alBufferData(buffer, al_format, wav_file.data.data, wav_file.data.count, wav_file.sample_rate); + memory.free_slice(^wav_file.loaded_file_data); + + map.put(^loaded_sounds, path, .{ buffer }); + return .{ buffer }; + } + + play_sound :: (path: str, volume := 1.0f) { + sound := get_sound(path); + + source: u32; + alGenSources(1, ^source); + alSourcef(source, AL_PITCH, 1); + alSourcef(source, AL_GAIN, volume); + alSource3f(source, AL_POSITION, 0, 0, 0); + alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcei(source, AL_LOOPING, AL_FALSE); + + alSourcei(source, AL_BUFFER, sound.buffer); + alSourcePlay(source); + playing_sounds << source; + } + + tick :: () { + while i := 0; i < playing_sounds.count { + defer i += 1; + + state: i32; + alGetSourcei(playing_sounds[i], AL_SOURCE_STATE, ^state); + if state != AL_PLAYING { + array.fast_delete(^playing_sounds, i); + i -= 1; + } + } + } +} + + + +#local { + device: ALCdevice; + audio_context: ALCcontext; + + loaded_sounds: Map(str, Sound); + playing_sounds: [..] u32; // List of sources +} \ No newline at end of file diff --git a/src/sfx/wav_file.onyx b/src/sfx/wav_file.onyx new file mode 100644 index 0000000..cfc5fc1 --- /dev/null +++ b/src/sfx/wav_file.onyx @@ -0,0 +1,130 @@ + +use package core + +WAV_File :: struct { + Format :: enum { + Invalid; + Mono8; + Stereo8; + Mono16; + Stereo16; + } + + format: Format; + sample_rate: u32; + data: [] u8; + + loaded_file_data: [] u8; +} + +// +// This greedily loads the whole file +load_wav_file :: (path: str) -> WAV_File { + wav_file: WAV_File; + wav_file.format = .Invalid; + + data := os.get_contents(path); + if data.data == null do return wav_file; + wav_file.loaded_file_data = data; + + pos := 0; + if read_data(4) != "RIFF" do return wav_file; + read_data(4); // Not sure what this is suppose to be... + if read_data(4) != "WAVE" do return wav_file; + + while true { + header_name := read_data(4); + header_size := *cast(^u32) read_data(4).data; + + if header_name == "fmt " { + fmt := read_data(2); + channels := *cast(^u16) read_data(2).data; + sample_rate := *cast(^u32) read_data(4).data; + sr_bps_c_8 := *cast(^u32) read_data(4).data; + read_data(2); + bits_per_sample := *cast(^u16) read_data(2).data; + + wav_file.sample_rate = sample_rate; + + if channels == 1 && bits_per_sample == 8 do wav_file.format = .Mono8; + if channels == 1 && bits_per_sample == 16 do wav_file.format = .Mono16; + if channels == 2 && bits_per_sample == 8 do wav_file.format = .Stereo8; + if channels == 2 && bits_per_sample == 16 do wav_file.format = .Stereo16; + } + + if header_name == "data" { + wav_file.data = data; + break; + } + } + + return wav_file; + + read_data :: macro (n: u32) -> str { + defer pos += n; + return data[pos .. pos+n]; + } +} + + +#if false { +main :: (args) => { + dev := alcOpenDevice(null); + defer alcCloseDevice(dev); + + con := alcCreateContext(dev, null); + alcMakeContextCurrent(con); + defer { + alcMakeContextCurrent(~~ cast(u64) 0); + alcDestroyContext(con); + } + + alGetError(); + buf: u32; + alGenBuffers(1, ^buf); + defer alDeleteBuffers(1, ^buf); + if error := alGetError(); error != AL_NO_ERROR { + printf("AL ERROR: {}\n", error); + return; + } + + sample_rate := 44100; + +/* + wav_data := memory.make_slice(i16, sample_rate * 5); + for i: wav_data.count { + sample := math.sin((math.PI * 2.0f * ~~i * 263.2f) / ~~sample_rate) * 32768; + sample *= 1 - cast(f32) i / ~~wav_data.count; + wav_data[i] = cast(i16) cast(i32) (sample); + } + */ + + wav_file_contents := os.get_contents("/home/brendan/test.wav"); + wav_data := extract_wav_file_data(wav_file_contents); + + alBufferData(buf, AL_FORMAT_STEREO16, wav_data.data, wav_data.count, sample_rate); + + alListener3f(AL_POSITION, 0, 0, 0); + alListener3f(AL_VELOCITY, 0, 0, 0); + alListenerfv(AL_ORIENTATION, ~~ f32.[0, 0, 1, 0, 1, 0]); + + source: u32; + alGenSources(1, ^source); + defer alDeleteSources(1, ^source); + alSourcef(source, AL_PITCH, 1); + alSourcef(source, AL_GAIN, 0.7); + alSource3f(source, AL_POSITION, 0, 0, 0); + alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcei(source, AL_LOOPING, AL_FALSE); + + alSourcei(source, AL_BUFFER, buf); + alSourcePlay(source); + + state: i32; + while true { + os.sleep(1000); + alGetSourcei(source, AL_SOURCE_STATE, ^state); + if state != AL_PLAYING do break; + } +} +} \ No newline at end of file