diff --git a/Cargo.toml b/Cargo.toml index a1b273a..d1f70c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "promise", "ring_buffer", "scene_update_macros", + "skybox", "transaction_derive", ] diff --git a/asset/src/imageformatchecker.rs b/asset/src/imageformatchecker.rs index 9dcccc5..684c039 100644 --- a/asset/src/imageformatchecker.rs +++ b/asset/src/imageformatchecker.rs @@ -21,7 +21,8 @@ impl ImageFormatChecker { self.image_data.height, ) .format(initial_format) - .attach_sampler(Sampler::pretty_sampler().build(device)?); + .max_mip_map_levels() + .attach_pretty_sampler(device)?; let mut format = initial_format; @@ -35,7 +36,7 @@ impl ImageFormatChecker { return Err(anyhow::Error::msg(format!( "Image format {:?} for asset does not work", format - ))) + ))); } }; diff --git a/context/src/core/context.rs b/context/src/core/context.rs index ee1357f..ad27ce3 100644 --- a/context/src/core/context.rs +++ b/context/src/core/context.rs @@ -22,14 +22,6 @@ use std::rc::Rc; use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::time::{Duration, Instant}; -pub trait ContextObject { - fn name(&self) -> &str; - - fn update(&mut self) -> Result<()>; - - fn event(&mut self, event: Event) -> Result<()>; -} - pub struct Context { core: VulkanCore, pub(crate) presentation: PresentationCore, @@ -65,18 +57,17 @@ impl Context { &mut self.sound_handler } - pub fn next_frame(&mut self, world: &mut World) -> Result { + pub fn next_frame(&mut self, world: &mut World, mut f: F) -> Result + where + C: Send + Sync + 'static, + F: FnMut(&mut World, &mut C, Event) -> Result<()> + Send + Sync + 'static, + { let render_core = self.render_core.clone(); + let consumer = world.resources.get_mut_unchecked::(); + let w = unsafe { remove_life_time_mut(world) }; match self.presentation.poll_events( - |event| { - // TODO - // if let Some(ctx_obj) = world.resources.get_mut_opt::() { - // ctx_obj.event(event)?; - // } - - Ok(()) - }, + |event| f(w, consumer, event), |w, h| render_core.write().unwrap().resize(world, w, h), ) { Ok(res) => { diff --git a/context/src/lib.rs b/context/src/lib.rs index 03a22ac..31d84eb 100644 --- a/context/src/lib.rs +++ b/context/src/lib.rs @@ -2,5 +2,3 @@ pub mod core; pub mod prelude; - -pub use crate::core::context::ContextObject; diff --git a/engine/src/engine/engine.rs b/engine/src/engine/engine.rs index d5095c0..8f57020 100644 --- a/engine/src/engine/engine.rs +++ b/engine/src/engine/engine.rs @@ -1,6 +1,6 @@ #![allow(clippy::type_complexity)] -use super::engine_object::*; +use super::engine_event_handling::*; use super::engine_settings::EngineSettings; use anyhow::Result; @@ -11,7 +11,7 @@ use crate::assets::asset_manager::AssetManager; use crate::prelude::*; use std::collections::HashMap; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; struct GuiPostProcess(Arc); @@ -34,8 +34,6 @@ impl context::prelude::PostProcess for GuiPostProcess { } pub struct Engine { - input: Arc>, - // loads and keeps track of raw data asset_manager: AssetManager, @@ -43,7 +41,7 @@ pub struct Engine { } impl Engine { - pub fn new( + pub fn new( #[allow(unused)] mut create_info: EngineCreateInfo<'_>, world: &mut WorldBuilder, ) -> Result<()> { @@ -188,13 +186,12 @@ impl Engine { direction_mapping.insert(Keycode::Down, GuiDirection::Down); let engine = Engine { - input: Arc::new(RwLock::new(Input { direction_mapping })), - asset_manager, resource_base_path: create_info.resource_base_path, }; + world.resources.insert(InputMap { direction_mapping }); world.resources.insert(context); world.resources.insert(engine); world.resources.insert(engine_settings); @@ -208,7 +205,7 @@ impl Engine { world.resources.insert(scene); - world.add_system(Self::main_system); + world.add_system(Self::main_system::); Ok(()) } @@ -251,10 +248,25 @@ impl Engine { } impl Engine { - fn main_system(world: &mut World) -> Result { + fn main_system(world: &mut World) -> Result { world .resources - .get_mut_unchecked::() - .next_frame::<()>(world) + .get::>() + .process_callbacks()?; + + let gui_handler = world.resources.get_unchecked::>(); + let input_map = world.resources.get_unchecked::(); + let context = world.resources.get_unchecked::(); + + let res = world.resources.get_mut_unchecked::().next_frame( + world, + |world, consumer: &mut T, event| { + Self::event(world, context, gui_handler, input_map, consumer, event) + }, + )?; + + gui_handler.process_callbacks()?; + + Ok(res) } } diff --git a/engine/src/engine/engine_event_handling.rs b/engine/src/engine/engine_event_handling.rs new file mode 100644 index 0000000..cecc6d3 --- /dev/null +++ b/engine/src/engine/engine_event_handling.rs @@ -0,0 +1,332 @@ +use crate::prelude::*; + +use anyhow::Result; + +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; + +// use super::engine_object_data::{EngineObjectAccess, EngineObjectDataHandle}; + +#[derive(Debug)] +pub enum EngineEvent { + MouseMotion(u32, u32), + MouseButtonDown(MouseButton), + MouseButtonUp(MouseButton), + MouseWheel(i32, i32, MouseWheelDirection), + + KeyDown(Keycode), + KeyUp(Keycode), + + ButtonDown(ControllerButton), + ButtonUp(ControllerButton), + ControllerAxis(ControllerAxis), + + ControllerAdded(Arc>), + ControllerRemoved(Arc>), + + FileDrop(String), +} + +pub trait EventConsumer: Send + Sync + 'static { + fn event(&mut self, world: &mut World, event: EngineEvent) -> Result<()>; +} + +pub struct InputMap { + pub direction_mapping: HashMap, +} + +impl Engine { + pub(crate) fn event( + world: &mut World, + context: &Context, + gui_handler: &GuiHandler, + input: &InputMap, + consumer: &mut T, + event: Event, + ) -> anyhow::Result<()> { + match event { + Event::MouseMotion(x, y) => { + gui_handler.set_mouse_pos(x, y)?; + consumer.event(world, EngineEvent::MouseMotion(x, y))?; + } + Event::MouseButtonDown(mouse_button) => { + if !gui_handler.mouse_down(mouse_button)? { + consumer.event(world, EngineEvent::MouseButtonDown(mouse_button))?; + } + } + Event::MouseButtonUp(mouse_button) => { + if !gui_handler.mouse_up(mouse_button)? { + consumer.event(world, EngineEvent::MouseButtonUp(mouse_button))?; + } + } + Event::MouseWheel(x, y, direction) => { + consumer.event(world, EngineEvent::MouseWheel(x, y, direction))? + } + Event::KeyDown(keycode) => { + Self::key_down_event(world, context, gui_handler, input, consumer, keycode)?; + } + Event::KeyUp(keycode) => { + Self::key_up_event(world, gui_handler, input, consumer, keycode)?; + } + Event::TextInput(text) => { + Self::text_input(gui_handler, text)?; + } + Event::ControllerButtonDown(button) => { + Self::button_down_event(world, gui_handler, consumer, button)?; + } + Event::ControllerButtonUp(button) => { + Self::button_up_event(world, consumer, button)?; + } + Event::ControllerAxis(controller) => { + let controller = controller.read().unwrap(); + + if !gui_handler.check_navigatable()? { + Self::axis_event(world, consumer, &controller)? + } else { + gui_handler.update_selection(controller.direction())?; + } + } + Event::ControllerAdded(controller) => { + Self::controller_added(world, consumer, controller)? + } + Event::ControllerRemoved(controller) => { + Self::controller_removed(world, consumer, controller)? + } + Event::FileDrop(filename) => consumer.event(world, EngineEvent::FileDrop(filename))?, + } + + Ok(()) + } +} + +impl Engine { + #[inline] + fn controller_added( + world: &mut World, + consumer: &mut T, + controller: Arc>, + ) -> Result<()> { + consumer.event(world, EngineEvent::ControllerAdded(controller))?; + + Ok(()) + } + + #[inline] + fn controller_removed( + world: &mut World, + consumer: &mut T, + controller: Arc>, + ) -> Result<()> { + consumer.event(world, EngineEvent::ControllerRemoved(controller))?; + + Ok(()) + } + + #[inline] + fn key_up_event( + world: &mut World, + gui_handler: &GuiHandler, + input: &InputMap, + consumer: &mut T, + keycode: Keycode, + ) -> Result<()> { + if input.direction_mapping.get(&keycode).is_some() + && gui_handler.update_selection(GuiDirection::None)? + { + return Ok(()); + } + + consumer.event(world, EngineEvent::KeyUp(keycode))?; + + Ok(()) + } + + #[inline] + fn key_down_event( + world: &mut World, + context: &Context, + gui_handler: &GuiHandler, + input: &InputMap, + consumer: &mut T, + keycode: Keycode, + ) -> Result<()> { + if let Some(direction) = input.direction_mapping.get(&keycode) { + if gui_handler.update_selection(*direction)? { + return Ok(()); + } + } + + match keycode { + Keycode::Backspace => { + if gui_handler.remove_char()? { + return Ok(()); + } + } + Keycode::Return => { + if gui_handler.accept_selection()? { + return Ok(()); + } + } + Keycode::Escape => { + if gui_handler.decline_topgui()? { + return Ok(()); + } + } + Keycode::V => { + if let Some(writeable) = gui_handler.writeable()? { + if let Some(content) = context.window_config().clipboard_content()? { + writeable.set_text(content)?; + } + } + } + + _ => (), + } + + consumer.event(world, EngineEvent::KeyDown(keycode))?; + + Ok(()) + } + + #[inline] + fn button_up_event( + world: &mut World, + consumer: &mut T, + button: ControllerButton, + ) -> Result<()> { + consumer.event(world, EngineEvent::ButtonUp(button))?; + + Ok(()) + } + + #[inline] + fn button_down_event( + world: &mut World, + gui_handler: &GuiHandler, + consumer: &mut T, + button: ControllerButton, + ) -> Result<()> { + if gui_handler.check_navigatable()? { + Self::check_button_down(world, gui_handler, consumer, button)?; + } else { + consumer.event(world, EngineEvent::ButtonDown(button))?; + } + + Ok(()) + } + + #[inline] + fn axis_event( + world: &mut World, + consumer: &mut T, + controller: &Controller, + ) -> Result<()> { + consumer.event( + world, + EngineEvent::ControllerAxis(controller.controller_axis()), + )?; + + Ok(()) + } + + #[inline] + fn check_button_down( + world: &mut World, + gui_handler: &GuiHandler, + consumer: &mut T, + button: ControllerButton, + ) -> Result<()> { + match button { + ControllerButton::A => { + if gui_handler.accept_selection()? { + return Ok(()); + } + } + + ControllerButton::B => { + if gui_handler.decline_topgui()? { + return Ok(()); + } + } + + ControllerButton::RightButton => { + if gui_handler.next_tab_topgui(false)? { + return Ok(()); + } + } + + ControllerButton::LeftButton => { + if gui_handler.previous_tab_topgui(false)? { + return Ok(()); + } + } + + ControllerButton::RightTrigger => { + if gui_handler.next_tab_topgui(true)? { + return Ok(()); + } + } + + ControllerButton::LeftTrigger => { + if gui_handler.previous_tab_topgui(true)? { + return Ok(()); + } + } + + ControllerButton::DPadDown => { + let selection_res = gui_handler.update_selection(GuiDirection::Down)?; + gui_handler.update_selection(GuiDirection::None)?; + + if selection_res { + return Ok(()); + } + } + + ControllerButton::DPadUp => { + let selection_res = gui_handler.update_selection(GuiDirection::Up)?; + gui_handler.update_selection(GuiDirection::None)?; + + if selection_res { + return Ok(()); + } + } + + ControllerButton::DPadRight => { + let selection_res = gui_handler.update_selection(GuiDirection::Right)?; + gui_handler.update_selection(GuiDirection::None)?; + + if selection_res { + return Ok(()); + } + } + + ControllerButton::DPadLeft => { + let selection_res = gui_handler.update_selection(GuiDirection::Left)?; + gui_handler.update_selection(GuiDirection::None)?; + + if selection_res { + return Ok(()); + } + } + + _ => (), + } + + if !gui_handler.accept_custom_selection(button)? { + consumer.event(world, EngineEvent::ButtonDown(button))?; + } + + Ok(()) + } + + #[inline] + fn text_input(gui_handler: &GuiHandler, text: String) -> Result<()> { + if let Some(writeable) = gui_handler.writeable()? { + for c in text.chars() { + writeable.add_letter(c)?; + } + } + + Ok(()) + } +} diff --git a/engine/src/engine/engine_object.rs b/engine/src/engine/engine_object.rs deleted file mode 100644 index e715312..0000000 --- a/engine/src/engine/engine_object.rs +++ /dev/null @@ -1,420 +0,0 @@ -use crate::prelude::*; - -use anyhow::Result; -use context::ContextObject; - -use std::any::Any; -use std::collections::HashMap; -use std::sync::{Arc, RwLock}; - -// use super::engine_object_data::{EngineObjectAccess, EngineObjectDataHandle}; - -#[derive(Debug)] -pub enum EngineEvent { - MouseMotion(u32, u32), - MouseButtonDown(MouseButton), - MouseButtonUp(MouseButton), - MouseWheel(i32, i32, MouseWheelDirection), - - KeyDown(Keycode), - KeyUp(Keycode), - - ButtonDown(ControllerButton), - ButtonUp(ControllerButton), - ControllerAxis(ControllerAxis), - - ControllerAdded(Arc>), - ControllerRemoved(Arc>), - - FileDrop(String), -} - -// pub trait EngineObjectHelper: Any { -// type Payload: Send + Sync; - -// fn access(&self) -> EngineObjectAccess<'_, Self::Payload>; -// fn payload(&self) -> EngineObjectDataHandle; -// fn ui(&self) -> &States; -// fn ui_mut(&mut self) -> &mut States; - -// fn access_callback_mut<'a, F>( -// &'a self, -// f: F, -// ) -> impl FnMut() -> Result<()> + Send + Sync + 'static -// where -// F: FnMut(EngineObjectAccess<'a, Self::Payload>) -> Result<()> + Send + Sync + 'static, -// { -// self.payload().access_callback_mut(f) -// } - -// fn access_callback(&self, f: F) -> impl Fn() -> Result<()> + Send + Sync + 'static -// where -// F: Fn(EngineObjectAccess<'_, Self::Payload>) -> Result<()> + Send + Sync + 'static, -// { -// self.payload().access_callback(f) -// } - -// fn handle_callback_mut(&self, mut f: F) -> impl FnMut() -> Result<()> + Send + Sync + 'static -// where -// F: FnMut( -// EngineObjectDataHandle, -// EngineObjectAccess<'_, Self::Payload>, -// ) -> Result<()> -// + Send -// + Sync -// + 'static, -// { -// let handle = self.payload(); - -// move || { -// let data = handle.as_data(); -// let access = data.access(); - -// f(handle.copy(), access) -// } -// } - -// fn handle_callback(&self, f: F) -> impl Fn() -> Result<()> + Send + Sync + 'static -// where -// F: Fn( -// EngineObjectDataHandle, -// EngineObjectAccess<'_, Self::Payload>, -// ) -> Result<()> -// + Send -// + Sync -// + 'static, -// { -// let handle = self.payload(); - -// move || { -// let data = handle.as_data(); -// let access = data.access(); - -// f(handle.copy(), access) -// } -// } -// } - -pub trait EngineObject: Any { - fn name(&self) -> &str; - - fn update(&mut self) -> Result<()>; - fn event(&mut self, event: EngineEvent) -> Result<()>; -} - -pub struct Input { - pub direction_mapping: HashMap, -} - -pub struct ContextObjectImpl -where - E: EngineObject + Send + Sync, -{ - engine_object: E, - - context: Arc, - input: Arc>, - gui_handler: Arc, - - ctrl_pressed: bool, -} - -impl ContextObjectImpl -where - E: EngineObject + Send + Sync, -{ - pub fn new( - context: Arc, - engine_object: E, - input: Arc>, - gui_handler: Arc, - ) -> Result { - Ok(ContextObjectImpl { - context, - engine_object, - input, - gui_handler, - ctrl_pressed: false, - }) - } -} - -impl ContextObject for ContextObjectImpl -where - E: EngineObject + Send + Sync, -{ - fn name(&self) -> &str { - self.engine_object.name() - } - - fn update(&mut self) -> anyhow::Result<()> { - self.gui_handler.process_callbacks()?; - self.engine_object.update() - } - - fn event(&mut self, event: Event) -> anyhow::Result<()> { - match event { - Event::MouseMotion(x, y) => { - self.gui_handler.set_mouse_pos(x, y)?; - self.engine_object.event(EngineEvent::MouseMotion(x, y))?; - } - Event::MouseButtonDown(mouse_button) => { - if !self.gui_handler.mouse_down(mouse_button)? { - self.engine_object - .event(EngineEvent::MouseButtonDown(mouse_button))?; - } - } - Event::MouseButtonUp(mouse_button) => { - if !self.gui_handler.mouse_up(mouse_button)? { - self.engine_object - .event(EngineEvent::MouseButtonUp(mouse_button))?; - } - } - Event::MouseWheel(x, y, direction) => self - .engine_object - .event(EngineEvent::MouseWheel(x, y, direction))?, - Event::KeyDown(keycode) => { - self.key_down_event(keycode)?; - } - Event::KeyUp(keycode) => { - self.key_up_event(keycode)?; - } - Event::TextInput(text) => { - self.text_input(text)?; - } - Event::ControllerButtonDown(button) => { - self.button_down_event(button)?; - } - Event::ControllerButtonUp(button) => { - self.button_up_event(button)?; - } - Event::ControllerAxis(controller) => { - let controller = controller.read().unwrap(); - - if !self.gui_handler.check_navigatable()? { - self.axis_event(&controller)? - } else { - self.gui_handler.update_selection(controller.direction())?; - } - } - Event::ControllerAdded(controller) => self.controller_added(controller)?, - Event::ControllerRemoved(controller) => self.controller_removed(controller)?, - Event::FileDrop(filename) => { - self.engine_object.event(EngineEvent::FileDrop(filename))? - } - } - - Ok(()) - } -} - -impl ContextObjectImpl -where - E: EngineObject + Send + Sync, -{ - #[inline] - fn controller_added(&mut self, controller: Arc>) -> Result<()> { - self.engine_object - .event(EngineEvent::ControllerAdded(controller))?; - - Ok(()) - } - - #[inline] - fn controller_removed(&mut self, controller: Arc>) -> Result<()> { - self.engine_object - .event(EngineEvent::ControllerRemoved(controller))?; - - Ok(()) - } - - #[inline] - fn key_up_event(&mut self, keycode: Keycode) -> Result<()> { - let input = self.input.read().unwrap(); - - if input.direction_mapping.get(&keycode).is_some() - && self.gui_handler.update_selection(GuiDirection::None)? - { - return Ok(()); - } - - match keycode { - Keycode::RCtrl | Keycode::LCtrl => { - self.ctrl_pressed = false; - } - - _ => (), - } - - self.engine_object.event(EngineEvent::KeyUp(keycode))?; - - Ok(()) - } - - #[inline] - fn key_down_event(&mut self, keycode: Keycode) -> Result<()> { - let input = self.input.read().unwrap(); - - if let Some(direction) = input.direction_mapping.get(&keycode) { - if self.gui_handler.update_selection(*direction)? { - return Ok(()); - } - } - - match keycode { - Keycode::Backspace => { - if self.gui_handler.remove_char()? { - return Ok(()); - } - } - Keycode::Return => { - if self.gui_handler.accept_selection()? { - return Ok(()); - } - } - Keycode::Escape => { - if self.gui_handler.decline_topgui()? { - return Ok(()); - } - } - Keycode::RCtrl | Keycode::LCtrl => { - self.ctrl_pressed = true; - } - Keycode::V => { - if let Some(writeable) = self.gui_handler.writeable()? { - if let Some(content) = self.context.window_config().clipboard_content()? { - writeable.set_text(content)?; - } - } - } - - _ => (), - } - - self.engine_object.event(EngineEvent::KeyDown(keycode))?; - - Ok(()) - } - - #[inline] - fn button_up_event(&mut self, button: ControllerButton) -> Result<()> { - self.engine_object.event(EngineEvent::ButtonUp(button))?; - - Ok(()) - } - - #[inline] - fn button_down_event(&mut self, button: ControllerButton) -> Result<()> { - if self.gui_handler.check_navigatable()? { - self.check_button_down(button)?; - } else { - self.engine_object.event(EngineEvent::ButtonDown(button))?; - } - - Ok(()) - } - - #[inline] - fn axis_event(&mut self, controller: &Controller) -> Result<()> { - self.engine_object - .event(EngineEvent::ControllerAxis(controller.controller_axis()))?; - - Ok(()) - } - - #[inline] - fn check_button_down(&mut self, button: ControllerButton) -> Result<()> { - match button { - ControllerButton::A => { - if self.gui_handler.accept_selection()? { - return Ok(()); - } - } - - ControllerButton::B => { - if self.gui_handler.decline_topgui()? { - return Ok(()); - } - } - - ControllerButton::RightButton => { - if self.gui_handler.next_tab_topgui(false)? { - return Ok(()); - } - } - - ControllerButton::LeftButton => { - if self.gui_handler.previous_tab_topgui(false)? { - return Ok(()); - } - } - - ControllerButton::RightTrigger => { - if self.gui_handler.next_tab_topgui(true)? { - return Ok(()); - } - } - - ControllerButton::LeftTrigger => { - if self.gui_handler.previous_tab_topgui(true)? { - return Ok(()); - } - } - - ControllerButton::DPadDown => { - let selection_res = self.gui_handler.update_selection(GuiDirection::Down)?; - self.gui_handler.update_selection(GuiDirection::None)?; - - if selection_res { - return Ok(()); - } - } - - ControllerButton::DPadUp => { - let selection_res = self.gui_handler.update_selection(GuiDirection::Up)?; - self.gui_handler.update_selection(GuiDirection::None)?; - - if selection_res { - return Ok(()); - } - } - - ControllerButton::DPadRight => { - let selection_res = self.gui_handler.update_selection(GuiDirection::Right)?; - self.gui_handler.update_selection(GuiDirection::None)?; - - if selection_res { - return Ok(()); - } - } - - ControllerButton::DPadLeft => { - let selection_res = self.gui_handler.update_selection(GuiDirection::Left)?; - self.gui_handler.update_selection(GuiDirection::None)?; - - if selection_res { - return Ok(()); - } - } - - _ => (), - } - - if !self.gui_handler.accept_custom_selection(button)? { - self.engine_object.event(EngineEvent::ButtonDown(button))?; - } - - Ok(()) - } - - #[inline] - fn text_input(&self, text: String) -> Result<()> { - if let Some(writeable) = self.gui_handler.writeable()? { - for c in text.chars() { - writeable.add_letter(c)?; - } - } - - Ok(()) - } -} diff --git a/engine/src/engine/mod.rs b/engine/src/engine/mod.rs index 38d99be..3a596be 100644 --- a/engine/src/engine/mod.rs +++ b/engine/src/engine/mod.rs @@ -1,7 +1,7 @@ pub mod engine; pub mod engine_settings; -pub mod engine_object; +pub mod engine_event_handling; pub mod asset_handler; pub mod engine_create_info; diff --git a/engine/src/prelude.rs b/engine/src/prelude.rs index 4d2ee91..ea7a546 100644 --- a/engine/src/prelude.rs +++ b/engine/src/prelude.rs @@ -10,7 +10,7 @@ pub use crate::engine::{ asset_handler::{AssetHandler, AssetLoader}, engine::*, engine_create_info::EngineCreateInfo, - engine_object::{EngineEvent, EngineObject}, + engine_event_handling::{EngineEvent, EventConsumer}, engine_settings::*, }; diff --git a/engine/src/scene/general/free_camera_control.rs b/engine/src/scene/general/free_camera_control.rs new file mode 100644 index 0000000..ef2800e --- /dev/null +++ b/engine/src/scene/general/free_camera_control.rs @@ -0,0 +1,36 @@ +use crate::prelude::*; +use anyhow::Result; + +pub struct FreeCameraControl {} + +impl Default for FreeCameraControl { + fn default() -> Self { + Self {} + } +} + +impl FreeCameraControl { + pub fn roll(&mut self, view: &View) -> Result<()> { + Ok(()) + } + + pub fn pitch(&mut self, view: &View) -> Result<()> { + Ok(()) + } + + pub fn yaw(&mut self, view: &View) -> Result<()> { + Ok(()) + } + + pub fn forward_back(&mut self, view: &View) -> Result<()> { + Ok(()) + } + + pub fn left_right(&mut self, view: &View) -> Result<()> { + Ok(()) + } + + pub fn up_down(&mut self, view: &View) -> Result<()> { + Ok(()) + } +} diff --git a/engine/src/scene/general/mod.rs b/engine/src/scene/general/mod.rs index be143cd..021a44c 100644 --- a/engine/src/scene/general/mod.rs +++ b/engine/src/scene/general/mod.rs @@ -6,8 +6,9 @@ pub mod validcommandbuffer; pub mod view; -pub mod camera_control; +pub mod top_down_camera_control; pub mod view_frustum; +pub mod free_camera_control; pub mod prelude; diff --git a/engine/src/scene/general/prelude.rs b/engine/src/scene/general/prelude.rs index dfb864c..04e52e4 100644 --- a/engine/src/scene/general/prelude.rs +++ b/engine/src/scene/general/prelude.rs @@ -6,6 +6,6 @@ pub use super::validcommandbuffer::*; pub use super::view::*; -pub use super::camera_control::*; +pub use super::top_down_camera_control::*; pub use super::view_frustum::*; diff --git a/engine/src/scene/general/camera_control.rs b/engine/src/scene/general/top_down_camera_control.rs similarity index 88% rename from engine/src/scene/general/camera_control.rs rename to engine/src/scene/general/top_down_camera_control.rs index 17a2bf7..e73b57e 100644 --- a/engine/src/scene/general/camera_control.rs +++ b/engine/src/scene/general/top_down_camera_control.rs @@ -1,8 +1,8 @@ use crate::prelude::*; use anyhow::Result; -use cgmath::{num_traits::clamp, vec3, Deg, Matrix4, Vector2, Vector3}; +use cgmath::{Deg, Matrix4, Vector2, Vector3, num_traits::clamp, vec3}; -pub struct CameraControl { +pub struct TopDownCameraControl { zoom_levels: Vec, current_zoom_level: usize, @@ -17,7 +17,7 @@ pub struct CameraControl { mouse_position_start: Option<(u32, u32)>, } -impl CameraControl { +impl TopDownCameraControl { const SCALE: f32 = 0.3; const MIN_PITCH: f32 = 10.0; const MAX_PITCH: f32 = 80.0; @@ -91,8 +91,8 @@ impl CameraControl { self.rotation = Deg((self.rotation.0 + (self.stick_direction.x * factors.x)) % 360.0); self.arc = Deg(clamp( self.arc.0 - (self.stick_direction.y * factors.y), - CameraControl::MIN_PITCH, - CameraControl::MAX_PITCH, + TopDownCameraControl::MIN_PITCH, + TopDownCameraControl::MAX_PITCH, )); self.set_camera_offset(view) @@ -102,14 +102,14 @@ impl CameraControl { self.mouse_position = (x, y); if let Some((start_x, start_y)) = self.mouse_position_start { - let x_diff = (start_x as i32 - x as i32) as f32 * CameraControl::SCALE; - let y_diff = (start_y as i32 - y as i32) as f32 * CameraControl::SCALE; + let x_diff = (start_x as i32 - x as i32) as f32 * TopDownCameraControl::SCALE; + let y_diff = (start_y as i32 - y as i32) as f32 * TopDownCameraControl::SCALE; self.rotation = Deg((self.rotation_start.0 + x_diff) % 360.0); self.arc = Deg(clamp( self.arc_start.0 - y_diff, - CameraControl::MIN_PITCH, - CameraControl::MAX_PITCH, + TopDownCameraControl::MIN_PITCH, + TopDownCameraControl::MAX_PITCH, )); self.set_camera_offset(view)?; diff --git a/examples/simple_window/Cargo.toml b/examples/simple_window/Cargo.toml index 30d9629..72d6abf 100644 --- a/examples/simple_window/Cargo.toml +++ b/examples/simple_window/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +plexus = "0.0.11" anyhow.workspace = true ecs = { path = "../../ecs" } diff --git a/examples/simple_window/src/main.rs b/examples/simple_window/src/main.rs index ac8a572..8db66e9 100644 --- a/examples/simple_window/src/main.rs +++ b/examples/simple_window/src/main.rs @@ -6,7 +6,55 @@ use engine::prelude::*; fn main() -> Result<()> { let mut world_builder = World::builder(); - Engine::new(EngineCreateInfo::default(), &mut world_builder)?; + Engine::new::(EngineCreateInfo::default(), &mut world_builder)?; + + world_builder.add_system(GameState::update); + world_builder.resources.insert(GameState::Startup); world_builder.build().run() } + +enum GameState { + Startup, + Loading, + Menu, + Game(Game), +} + +impl GameState { + fn update(world: &mut World) -> Result { + match world.resources.get_mut_unchecked::() { + GameState::Startup => (), + GameState::Loading => (), + GameState::Menu => (), + GameState::Game(game) => game.update(world)?, + } + + Ok(true) + } +} + +impl EventConsumer for GameState { + fn event(&mut self, world: &mut World, event: EngineEvent) -> Result<()> { + match self { + GameState::Startup => (), + GameState::Loading => (), + GameState::Menu => (), + GameState::Game(game) => game.event(world, event)?, + } + + Ok(()) + } +} + +struct Game {} + +impl Game { + fn update(&mut self, world: &mut World) -> Result<()> { + Ok(()) + } + + fn event(&mut self, world: &mut World, event: EngineEvent) -> Result<()> { + Ok(()) + } +} diff --git a/presentation/src/input/eventsystem.rs b/presentation/src/input/eventsystem.rs index 7bd4881..803c554 100644 --- a/presentation/src/input/eventsystem.rs +++ b/presentation/src/input/eventsystem.rs @@ -178,9 +178,9 @@ impl EventSystem { .map_err(|s| anyhow::Error::msg(s))?) } - pub fn poll_events(&mut self, event_callback: F, mut resize: R) -> Result + pub fn poll_events(&mut self, mut event_callback: F, mut resize: R) -> Result where - F: Fn(Event) -> Result<()>, + F: FnMut(Event) -> Result<()>, R: FnMut(u32, u32) -> Result<()>, { let mut controller_axis_changed = false; diff --git a/presentation/src/presentationcore.rs b/presentation/src/presentationcore.rs index 49059a6..2f86797 100644 --- a/presentation/src/presentationcore.rs +++ b/presentation/src/presentationcore.rs @@ -113,7 +113,7 @@ impl PresentationCore { pub fn poll_events(&mut self, event_callback: F, resize_event: R) -> Result where - F: Fn(Event) -> Result<()>, + F: FnMut(Event) -> Result<()>, R: FnMut(u32, u32) -> Result<()>, { self.event_system.poll_events(event_callback, resize_event) diff --git a/skybox/Cargo.toml b/skybox/Cargo.toml new file mode 100644 index 0000000..57c71e1 --- /dev/null +++ b/skybox/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "skybox" +version = "0.1.0" +authors = ["hodasemi "] +edition = "2024" + +[dependencies] +anyhow.workspace = true + +ecs = { path = "../ecs" } +context = { path = "../context" } diff --git a/skybox/src/lib.rs b/skybox/src/lib.rs new file mode 100644 index 0000000..1c046fc --- /dev/null +++ b/skybox/src/lib.rs @@ -0,0 +1,54 @@ +use std::{path::PathBuf, sync::Arc}; + +use anyhow::Result; +use context::prelude::*; +use ecs::*; + +pub struct SkyBoxImages { + left: PathBuf, + right: PathBuf, + front: PathBuf, + back: PathBuf, + top: PathBuf, + bottom: PathBuf, +} + +impl> From for SkyBoxImages { + fn from(mut paths: T) -> Self { + debug_assert_eq!(paths.len(), 6); + + Self { + left: paths.next().unwrap(), + right: paths.next().unwrap(), + front: paths.next().unwrap(), + back: paths.next().unwrap(), + top: paths.next().unwrap(), + bottom: paths.next().unwrap(), + } + } +} + +pub struct SkyBox { + cube_map: Arc, +} + +impl SkyBox { + pub fn new(world: &mut WorldBuilder, images: impl Into) -> Result { + let images = images.into(); + let context = world.resources.get::(); + + let cube_map = Image::cube_map([ + images.left.try_into()?, + images.right.try_into()?, + images.front.try_into()?, + images.back.try_into()?, + images.top.try_into()?, + images.bottom.try_into()?, + ])? + .max_mip_map_levels() + .attach_pretty_sampler(context.device())? + .build(context.device(), context.queue())?; + + Ok(Self { cube_map }) + } +}