diff --git a/Cargo.lock b/Cargo.lock index d1fcf63b..3b61c28b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,12 +41,12 @@ dependencies = [ [[package]] name = "alsa" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47" +checksum = "ce34de545ad29bcc00cb1b87a94c132256dcf83aa7eeb9674482568405a6ff0a" dependencies = [ "alsa-sys", - "bitflags 1.3.2", + "bitflags 2.4.1", "libc", "nix", ] @@ -108,26 +108,6 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" -[[package]] -name = "bindgen" -version = "0.69.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" -dependencies = [ - "bitflags 2.4.1", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.38", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -183,11 +163,11 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" name = "byte_engine" version = "0.1.0" dependencies = [ + "alsa", "ash", "bitflags 2.4.1", "colored", "component_derive", - "cpal", "downcast-rs", "dual_quaternion", "futures", @@ -223,54 +203,21 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "jobserver", "libc", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "clang-sys" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "cmake" version = "0.1.50" @@ -297,16 +244,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "component_derive" version = "0.1.0" @@ -315,57 +252,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "coreaudio-rs" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" -dependencies = [ - "bitflags 1.3.2", - "core-foundation-sys", - "coreaudio-sys", -] - -[[package]] -name = "coreaudio-sys" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3120ebb80a9de008e638ad833d4127d50ea3d3a960ea23ea69bc66d9358a028" -dependencies = [ - "bindgen", -] - -[[package]] -name = "cpal" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c" -dependencies = [ - "alsa", - "core-foundation-sys", - "coreaudio-rs", - "dasp_sample", - "jni 0.19.0", - "js-sys", - "libc", - "mach2", - "ndk", - "ndk-context", - "oboe", - "once_cell", - "parking_lot", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows", -] - [[package]] name = "crc32fast" version = "1.3.2" @@ -400,12 +286,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "dasp_sample" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" - [[package]] name = "deranged" version = "0.3.9" @@ -659,12 +539,6 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "gltf" version = "1.3.0" @@ -867,49 +741,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] - [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -957,12 +788,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.149" @@ -1048,15 +873,6 @@ dependencies = [ "twox-hash", ] -[[package]] -name = "mach2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" -dependencies = [ - "libc", -] - [[package]] name = "maths-rs" version = "0.2.5" @@ -1089,12 +905,6 @@ dependencies = [ "float-cmp 0.5.3", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1117,56 +927,17 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "ndk" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" -dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys", - "num_enum 0.5.11", - "raw-window-handle", - "thiserror", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" -dependencies = [ - "jni-sys", -] - [[package]] name = "nix" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "notify" version = "6.1.1" @@ -1199,17 +970,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -1250,34 +1010,13 @@ dependencies = [ "libc", ] -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive 0.5.11", -] - [[package]] name = "num_enum" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" dependencies = [ - "num_enum_derive 0.6.1", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", + "num_enum_derive", ] [[package]] @@ -1310,29 +1049,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "oboe" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0" -dependencies = [ - "jni 0.20.0", - "ndk", - "ndk-context", - "num-derive", - "num-traits", - "oboe-sys", -] - -[[package]] -name = "oboe-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2" -dependencies = [ - "cc", -] - [[package]] name = "once_cell" version = "1.18.0" @@ -1359,15 +1075,9 @@ dependencies = [ "libc", "redox_syscall 0.4.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" version = "2.3.0" @@ -1427,7 +1137,7 @@ dependencies = [ "libc", "lz4_flex", "memmap2", - "num_enum 0.6.1", + "num_enum", "regex", "serde", "serde-wasm-bindgen", @@ -1534,12 +1244,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - [[package]] name = "redox_syscall" version = "0.3.5" @@ -1637,12 +1341,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustix" version = "0.38.21" @@ -1782,12 +1480,6 @@ dependencies = [ "roxmltree", ] -[[package]] -name = "shlex" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" - [[package]] name = "simd-adler32" version = "0.3.7" @@ -2197,15 +1889,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -2227,22 +1910,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9d08bdbe..526d3b00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ meshopt = "0.1.9" colored = "2.0.4" downcast-rs = "1.2.0" intertrait = "0.2.2" -cpal = "0.15.2" +alsa = "0.8.1" [profile.dev] incremental = true diff --git a/src/ahi/audio_hardware_interface.rs b/src/ahi/audio_hardware_interface.rs new file mode 100644 index 00000000..c5ab37b9 --- /dev/null +++ b/src/ahi/audio_hardware_interface.rs @@ -0,0 +1,73 @@ +use crate::orchestrator::{EntityReturn, Entity, System}; + +pub trait AudioHardwareInterface { + fn play(&self); + + fn pause(&self); +} + +struct ALSAAudioHardwareInterface { + pcm: Option, +} + +impl ALSAAudioHardwareInterface { + fn open() -> Self { + let name = std::ffi::CString::new("default").unwrap(); + let pcm = alsa::pcm::PCM::open(&name, alsa::Direction::Playback, false).unwrap(); + + { + let hwp = alsa::pcm::HwParams::any(&pcm).unwrap(); + hwp.set_channels(1).unwrap(); + hwp.set_rate(44100, alsa::ValueOr::Nearest).unwrap(); + hwp.set_format(alsa::pcm::Format::s16()).unwrap(); + hwp.set_access(alsa::pcm::Access::RWInterleaved).unwrap(); + pcm.hw_params(&hwp).unwrap(); + } + + { + let hwp = pcm.hw_params_current().unwrap(); + let swp = pcm.sw_params_current().unwrap(); + swp.set_start_threshold(hwp.get_buffer_size().unwrap()).unwrap(); + pcm.sw_params(&swp).unwrap(); + } + + ALSAAudioHardwareInterface { + pcm: Some(pcm), + } + } +} + +impl AudioHardwareInterface for ALSAAudioHardwareInterface { + fn play(&self) { + let pcm = if let Some(pcm) = &self.pcm { pcm } else { return; }; + + // Make a sine wave + let mut buf = [0i16; 1024]; + for (i, a) in buf.iter_mut().enumerate() { + *a = ((i as f32 * 2.0 * ::std::f32::consts::PI / 32.0).sin() * 8192.0) as i16 + } + + let io = pcm.io_i16().unwrap(); + + // Play it back for 2 seconds. + for _ in 0..2*44100/1024 { + assert_eq!(io.writei(&buf[..]).unwrap(), 1024); + } + + // In case the buffer was larger than 2 seconds, start the stream manually. + if pcm.state() != alsa::pcm::State::Running { pcm.start().unwrap() }; + // Wait for the stream to finish playback. + pcm.drain().unwrap(); + } + + fn pause(&self) { + let pcm = if let Some(pcm) = &self.pcm { pcm } else { return; }; + + pcm.pause(true).unwrap(); + } +} + +pub fn create_ahi() -> impl AudioHardwareInterface { + #[cfg(target_os = "linux")] + ALSAAudioHardwareInterface::open() +} \ No newline at end of file diff --git a/src/ahi/mod.rs b/src/ahi/mod.rs new file mode 100644 index 00000000..a1742da9 --- /dev/null +++ b/src/ahi/mod.rs @@ -0,0 +1 @@ +pub mod audio_hardware_interface; \ No newline at end of file diff --git a/src/application.rs b/src/application.rs index 83454d29..4ff5c3b6 100644 --- a/src/application.rs +++ b/src/application.rs @@ -60,7 +60,7 @@ impl Application for BaseApplication { use log::{info, trace}; use maths_rs::prelude::Base; -use crate::{orchestrator::{self, EntityHandle}, rendering::render_system, window_system, input_manager, Vector2, rendering::{self}, resource_manager, file_tracker}; +use crate::{orchestrator::{self, EntityHandle}, rendering::render_system, window_system, input_manager, Vector2, rendering::{self}, resource_manager, file_tracker, ahi}; /// An orchestrated application is an application that uses the orchestrator to manage systems. /// It is the recommended way to create a simple application. @@ -129,6 +129,7 @@ pub struct GraphicsApplication { input_system_handle: orchestrator::EntityHandle, renderer_handle: orchestrator::EntityHandle, render_system_handle: orchestrator::EntityHandle, + audio_system_handle: Box, } impl Application for GraphicsApplication { @@ -171,7 +172,9 @@ impl Application for GraphicsApplication { let _: orchestrator::EntityHandle = orchestrator.spawn(window_system::Window{ name: "Main Window".to_string(), extent: crate::Extent { width: 1920, height: 1080, depth: 1 }, id_name: "main_window".to_string() }); - GraphicsApplication { application, file_tracker_handle, window_system_handle, input_system_handle, mouse_device_handle, renderer_handle, tick_count: 0, render_system_handle } + let audio_system_handle = Box::new(ahi::audio_hardware_interface::create_ahi()); + + GraphicsApplication { application, file_tracker_handle, window_system_handle, input_system_handle, mouse_device_handle, renderer_handle, tick_count: 0, render_system_handle, audio_system_handle } } fn initialize(&mut self, _arguments: std::env::Args) { diff --git a/src/audio/audio_system.rs b/src/audio/audio_system.rs deleted file mode 100644 index 04293e76..00000000 --- a/src/audio/audio_system.rs +++ /dev/null @@ -1,36 +0,0 @@ -use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; - -struct AudioSystem { - host: cpal::Host, - stream: Option, -} - -impl AudioSystem { - fn new() -> Self { - let host = cpal::default_host(); - - let device = if let Some(e) = host.default_output_device() { - e - } else { - log::error!("No audio output device found.\n Audio playback will be disabled."); - - return AudioSystem { - host, - stream: None, - }; - }; - - let mut format = device.default_output_config().unwrap(); - - let stream = device.build_output_stream(&format.config(), move |_: &mut [u16], _| {}, move |_| {}, None).unwrap(); - - if let Err(error) = stream.play() { - log::error!("Failed to start audio stream: {}\n Audio playback will be disabled.", error); - } - - AudioSystem { - host, - stream: Some(stream), - } - } -} \ No newline at end of file diff --git a/src/audio/mod.rs b/src/audio/mod.rs index 7bbaa9db..e69de29b 100644 --- a/src/audio/mod.rs +++ b/src/audio/mod.rs @@ -1 +0,0 @@ -pub mod audio_system; \ No newline at end of file diff --git a/src/input_manager.rs b/src/input_manager.rs index e4be313e..bd8a898b 100644 --- a/src/input_manager.rs +++ b/src/input_manager.rs @@ -592,7 +592,7 @@ impl InputManager { let most_recent_record = action_records.max_by_key(|r| r.time); if let Some(record) = most_recent_record { - let value = self.resolve_action_value_from_record(action, record); + let value = self.resolve_action_value_from_record(action, record).unwrap_or(Value::Bool(false)); match value { Value::Vector2(v) => { @@ -650,7 +650,7 @@ impl InputManager { let action = &self.actions[input_event_handle.0 as usize]; if let Some(record) = self.records.iter().filter(|r| action.input_event_descriptions.iter().any(|ied| ied.input_source_handle == r.input_source_handle)).max_by_key(|r| r.time) { - let value = self.resolve_action_value_from_record(action, record); + let value = self.resolve_action_value_from_record(action, record).unwrap_or(Value::Bool(false)); InputEventState { device_handle: device_handle.clone(), @@ -683,10 +683,10 @@ impl InputManager { } } - fn resolve_action_value_from_record(&self, action: &InputAction, record: &Record) -> Value { + fn resolve_action_value_from_record(&self, action: &InputAction, record: &Record) -> Option { let mapping = action.input_event_descriptions.iter().find(|ied| ied.input_source_handle == record.input_source_handle).unwrap(); - match action.type_ { + let value = match action.type_ { Types::Float => { let float = match record.value { Value::Bool(record_value) => { @@ -720,18 +720,36 @@ impl InputManager { } } } - _ => panic!("Not implemented!"), + _ => { + log::error!("Not implemented!"); + return None; + }, }; Value::Float(float) } Types::Vector3 => { match record.value { - Value::Bool(_) => panic!("Not implemented!"), - Value::Unicode(_) => panic!("Not implemented!"), - Value::Float(_) => panic!("Not implemented!"), - Value::Int(_) => panic!("Not implemented!"), - Value::Rgba(_) => panic!("Not implemented!"), + Value::Bool(_) => { + log::error!("Not implemented!"); + return None; + }, + Value::Unicode(_) => { + log::error!("Not implemented!"); + return None; + }, + Value::Float(_) => { + log::error!("Not implemented!"); + return None; + }, + Value::Int(_) => { + log::error!("Not implemented!"); + return None; + }, + Value::Rgba(_) => { + log::error!("Not implemented!"); + return None; + }, Value::Vector2(record_value) => { if let Some(function) = mapping.function { if let Function::Sphere = function { @@ -744,22 +762,31 @@ impl InputManager { let y = y_pi.sin(); let z = x_pi.cos() * y_pi.cos(); - let transformation = if let Value::Vector3(transformation) = mapping.mapping { transformation } else { panic!("Not implemented!"); }; + let transformation = if let Value::Vector3(transformation) = mapping.mapping { transformation } else { log::error!("Not implemented!"); return None; }; Value::Vector3(Vector3 { x, y, z } * transformation) } else { - panic!("Not implemented!"); + log::error!("Not implemented!"); + return None; } } else { Value::Vector3(Vector3 { x: record_value.x, y: record_value.y, z: 0f32 }) } }, Value::Vector3(value) => Value::Vector3(value), - Value::Quaternion(_) => panic!("Not implemented!"), + Value::Quaternion(_) => { + log::error!("Not implemented!"); + return None; + }, } } - _ => panic!("Not implemented!"), - } + _ => { + log::error!("Not implemented!"); + return None; + }, + }; + + Some(value) } fn get_input_source_from_input_source_action(&self, input_source_action: &InputSourceAction) -> Option<&InputSource> { diff --git a/src/lib.rs b/src/lib.rs index bc06556f..a3d68565 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ pub mod file_tracker; pub mod executor; pub mod camera; pub mod audio; +pub mod ahi; pub mod math; pub mod rendering; diff --git a/src/orchestrator.rs b/src/orchestrator.rs index 41314a7d..863858db 100644 --- a/src/orchestrator.rs +++ b/src/orchestrator.rs @@ -638,6 +638,61 @@ mod tests { assert_eq!(unsafe { COUNTER }, 1); } + #[test] + fn events() { + let mut orchestrator = Orchestrator::new(); + + struct Component { + name: String, + value: u32, + } + + // struct ComponentParameters { + // name: String, + // } + + impl Entity for Component {} + + impl super::Component for Component { + // type Parameters<'a> = ComponentParameters; + } + + let handle: EntityHandle = orchestrator.spawn(Component { name: "test".to_string(), value: 1 }); + + struct System { + + } + + impl Entity for System {} + impl super::System for System {} + + impl System { + fn new<'c>() -> EntityReturn<'c, System> { + EntityReturn::new(System {}).add_listener::() + } + } + + static mut COUNTER: u32 = 0; + + impl EntitySubscriber for System { + fn on_create(&mut self, orchestrator: OrchestratorReference, handle: EntityHandle, component: &Component) { + unsafe { + COUNTER += 1; + } + } + + fn on_update(&mut self, orchestrator: OrchestratorReference, handle: EntityHandle, params: &Component) {} + } + + let _: Option> = orchestrator.spawn_entity(System::new()); + + assert_eq!(unsafe { COUNTER }, 0); + + let component: EntityHandle = orchestrator.spawn(Component { name: "test".to_string(), value: 1 }); + + assert_eq!(unsafe { COUNTER }, 1); + } + // #[test] // fn test_systems() { // let mut orchestrator = Orchestrator::new(); diff --git a/src/resource_manager/audio_resource_handler.rs b/src/resource_manager/audio_resource_handler.rs new file mode 100644 index 00000000..c5aa09a3 --- /dev/null +++ b/src/resource_manager/audio_resource_handler.rs @@ -0,0 +1,125 @@ +use std::io::Read; + +use serde::{Serialize, Deserialize}; + +use super::{resource_handler::ResourceHandler, Resource, ProcessedResources, GenericResourceSerialization}; + +pub struct AudioResourceHandler { +} + +impl AudioResourceHandler { + pub fn new() -> Self { + Self { + } + } +} + +impl ResourceHandler for AudioResourceHandler { + fn can_handle_type(&self, resource_type: &str) -> bool { + return resource_type == "Audio" || resource_type == "wav"; + } + + fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { + vec![("Audio", Box::new(|document| { + let audio = Audio::deserialize(polodb_core::bson::Deserializer::new(document.into())).unwrap(); + Box::new(audio) + }))] + } + + fn process(&self, resource_manager: &super::resource_manager::ResourceManager, asset_url: &str) -> Result, String> { + let (bytes, _) = resource_manager.read_asset_from_source(asset_url).unwrap(); + + let riff = &bytes[0..4]; + + if riff != b"RIFF" { + return Err("Invalid RIFF header".to_string()); + } + + let format = &bytes[8..12]; + + if format != b"WAVE" { + return Err("Invalid WAVE format".to_string()); + } + + let audio_format = &bytes[20..22]; + + if audio_format != b"\x01\x00" { + return Err("Invalid audio format".to_string()); + } + + let num_channels = &bytes[22..24]; + + let num_channels = u16::from_le_bytes([num_channels[0], num_channels[1]]); + + if num_channels != 1 && num_channels != 2 { + return Err("Invalid number of channels".to_string()); + } + + let sample_rate = &bytes[24..28]; + + let sample_rate = u32::from_le_bytes([sample_rate[0], sample_rate[1], sample_rate[2], sample_rate[3]]); + + let bits_per_sample = &bytes[34..36]; + + let bits_per_sample = u16::from_le_bytes([bits_per_sample[0], bits_per_sample[1]]); + + let bit_depth = match bits_per_sample { + 8 => BitDepths::Eight, + 16 => BitDepths::Sixteen, + 24 => BitDepths::TwentyFour, + 32 => BitDepths::ThirtyTwo, + _ => { return Err("Invalid bits per sample".to_string()); } + }; + + let data_header = &bytes[36..40]; + + if data_header != b"data" { + return Err("Invalid data header".to_string()); + } + + let data_size = &bytes[40..44]; + + let data_size = u32::from_le_bytes([data_size[0], data_size[1], data_size[2], data_size[3]]); + + let data = &bytes[44..data_size as usize]; + + let audio_resource = Audio { + bit_depth, + channel_count: num_channels, + sample_rate, + }; + + Ok( + vec![ + ProcessedResources::Generated(( + GenericResourceSerialization::new(asset_url.to_string(), audio_resource), + Vec::from(data), + )) + ] + + ) + } + + fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { + file.read_exact(buffers[0].buffer).unwrap(); + } +} + +#[derive(Debug, Serialize, Deserialize)] +enum BitDepths { + Eight, + Sixteen, + TwentyFour, + ThirtyTwo, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Audio { + bit_depth: BitDepths, + channel_count: u16, + sample_rate: u32, +} + +impl Resource for Audio { + fn get_class(&self) -> &'static str { "Audio" } +} \ No newline at end of file diff --git a/src/resource_manager/material_resource_handler.rs b/src/resource_manager/material_resource_handler.rs index e84906e1..bf4cefc5 100644 --- a/src/resource_manager/material_resource_handler.rs +++ b/src/resource_manager/material_resource_handler.rs @@ -81,7 +81,7 @@ impl ResourceHandler for MaterialResourcerHandler { } } - fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { + fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { file.read_exact(buffers[0].buffer).unwrap(); } @@ -144,7 +144,7 @@ impl ResourceHandler for MaterialResourcerHandler { } } - fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { + fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { vec![("Material", Box::new(|_document| { Box::new(Material::deserialize(polodb_core::bson::Deserializer::new(_document.into())).unwrap()) diff --git a/src/resource_manager/mesh_resource_handler.rs b/src/resource_manager/mesh_resource_handler.rs index e31865ec..38e508c4 100644 --- a/src/resource_manager/mesh_resource_handler.rs +++ b/src/resource_manager/mesh_resource_handler.rs @@ -180,14 +180,14 @@ impl ResourceHandler for MeshResourceHandler { Ok(resources) } - fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { + fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { vec![("Mesh", Box::new(|document| { let mesh = Mesh::deserialize(polodb_core::bson::Deserializer::new(document.into())).unwrap(); Box::new(mesh) }))] } - fn read(&self, resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { + fn read(&self, resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { let mesh: &Mesh = resource.downcast_ref().unwrap(); for buffer in buffers { diff --git a/src/resource_manager/mod.rs b/src/resource_manager/mod.rs index a0285c0b..f61e557f 100644 --- a/src/resource_manager/mod.rs +++ b/src/resource_manager/mod.rs @@ -8,6 +8,7 @@ pub mod resource_handler; pub mod texture_resource_handler; pub mod mesh_resource_handler; pub mod material_resource_handler; +pub mod audio_resource_handler; // https://www.yosoygames.com.ar/wp/2018/03/vertex-formats-part-1-compression/ @@ -74,7 +75,7 @@ pub struct ResourceRequest { pub size: u64, pub hash: u64, pub class: String, - pub resource: Box, + pub resource: Box, pub required_resources: Vec, } @@ -85,18 +86,20 @@ pub struct ResourceResponse { pub offset: u64, pub hash: u64, pub class: String, - pub resource: Box, + pub resource: Box, pub required_resources: Vec, } /// Trait that defines a resource. -pub trait Resource { +pub trait Resource: downcast_rs::Downcast { /// Returns the resource class (EJ: "Texture", "Mesh", "Material", etc.) /// This is used to identify the resource type. Needs to be meaningful and will be a public constant. /// Is needed by the deserialize function. fn get_class(&self) -> &'static str; } +downcast_rs::impl_downcast!(Resource); + #[derive(Debug, Clone)] pub struct SerializedResourceDocument(polodb_core::bson::Document); diff --git a/src/resource_manager/resource_handler.rs b/src/resource_manager/resource_handler.rs index 4c79537c..3da28bd0 100644 --- a/src/resource_manager/resource_handler.rs +++ b/src/resource_manager/resource_handler.rs @@ -1,4 +1,4 @@ -use super::{resource_manager, ProcessedResources, Stream}; +use super::{resource_manager, ProcessedResources, Stream, Resource}; pub trait ResourceHandler { fn can_handle_type(&self, resource_type: &str) -> bool; @@ -16,7 +16,7 @@ pub trait ResourceHandler { /// - **required_resources**(optional): A list of resources that this resource depends on. This is used to load resources that depend on other resources. fn process(&self, resource_manager: &resource_manager::ResourceManager, asset_url: &str) -> Result, String>; - fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)>; + fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)>; - fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [Stream]); + fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [Stream]); } \ No newline at end of file diff --git a/src/resource_manager/resource_manager.rs b/src/resource_manager/resource_manager.rs index a4acea95..24e9a0c8 100644 --- a/src/resource_manager/resource_manager.rs +++ b/src/resource_manager/resource_manager.rs @@ -4,7 +4,7 @@ use log::{info, warn, error, trace, debug}; use crate::orchestrator; -use super::{resource_handler, texture_resource_handler, mesh_resource_handler, material_resource_handler, Request, Response, Options, LoadResults, ProcessedResources, ResourceRequest, GenericResourceSerialization, ResourceResponse}; +use super::{resource_handler, texture_resource_handler, mesh_resource_handler, material_resource_handler, Request, Response, Options, LoadResults, ProcessedResources, ResourceRequest, GenericResourceSerialization, ResourceResponse, Resource}; /// Resource manager. /// Handles loading assets or resources from different origins (network, local, etc.). @@ -23,7 +23,7 @@ use super::{resource_handler, texture_resource_handler, mesh_resource_handler, m pub struct ResourceManager { db: polodb_core::Database, resource_handlers: Vec>, - deserializers: std::collections::HashMap<&'static str, Box Box + Send>>, + deserializers: std::collections::HashMap<&'static str, Box Box + Send>>, } impl orchestrator::Entity for ResourceManager {} diff --git a/src/resource_manager/texture_resource_handler.rs b/src/resource_manager/texture_resource_handler.rs index 326aaaf0..ca058f5a 100644 --- a/src/resource_manager/texture_resource_handler.rs +++ b/src/resource_manager/texture_resource_handler.rs @@ -70,11 +70,11 @@ impl ResourceHandler for ImageResourceHandler { Ok(vec![ProcessedResources::Generated((resource_document, intel_tex_2::bc7::compress_blocks(&settings, &rgba_surface)))]) } - fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { + fn read(&self, _resource: &Box, file: &mut std::fs::File, buffers: &mut [super::Stream]) { file.read_exact(buffers[0].buffer).unwrap(); } - fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { + fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { vec![("Texture", Box::new(|document| { let texture = Texture::deserialize(polodb_core::bson::Deserializer::new(document.into())).unwrap(); Box::new(texture) diff --git a/tests/gallery_shooter.rs b/tests/gallery_shooter.rs index ed5a46d3..ab80fa4c 100644 --- a/tests/gallery_shooter.rs +++ b/tests/gallery_shooter.rs @@ -1,6 +1,6 @@ #![feature(const_mut_refs)] -use byte_engine::{application::Application, Vec3f, input_manager, Vector3, orchestrator::{Component, EntityHandle, self,}, math, rendering::mesh, rendering::point_light::PointLight}; +use byte_engine::{application::Application, Vec3f, input_manager::{self, Action}, Vector3, orchestrator::{Component, EntityHandle, self,}, math, rendering::mesh, rendering::point_light::PointLight}; use maths_rs::prelude::{MatTranslate, MatScale, MatInverse}; #[ignore] @@ -17,13 +17,13 @@ fn gallery_shooter() { ],) ); - let _trigger_action: orchestrator::EntityHandle> = orchestrator.spawn(input_manager::Action::new("Trigger", &[ + let trigger_action: orchestrator::EntityHandle> = orchestrator.spawn(input_manager::Action::new("Trigger", &[ input_manager::ActionBindingDescription::new(input_manager::InputSourceAction::Name("Mouse.LeftButton")), // input_manager::ActionBindingDescription::new(input_manager::InputSourceAction::Name("Gamepad.RightTrigger")), ],) ); - let player: EntityHandle = orchestrator.spawn_entity(Player::new(lookaround_action_handle)).expect("Failed to spawn player"); + let _player: EntityHandle = orchestrator.spawn_entity(Player::new(lookaround_action_handle, trigger_action)).expect("Failed to spawn player"); let scale = maths_rs::Mat4f::from_scale(Vec3f::new(0.1, 0.1, 0.1)); @@ -51,7 +51,7 @@ impl Component for Player { } impl Player { - fn new(lookaround: EntityHandle>) -> orchestrator::EntityReturn<'static, Self> { + fn new(lookaround: EntityHandle>, _trigger_action: EntityHandle>) -> orchestrator::EntityReturn<'static, Self> { orchestrator::EntityReturn::new_from_closure(move |orchestrator| { let mut transform = maths_rs::Mat4f::identity();