diff --git a/Cargo.lock b/Cargo.lock index b8aa964..8b637df 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -1716,12 +1716,12 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.0.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8183e2a..4f755b4 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ tobj = { version = "3.2.1", features = [ instant = "0.1" async-trait = "0.1.65" glam = { version = "0.24.0", features = ["bytemuck"] } -petgraph = "0.6.3" gilrs-core = "0.5.6" syn = "2.0.26" quote = "1.0.29" @@ -36,3 +35,4 @@ atomicell = "0.1.9" aligned-vec = "0.5.0" tracing-appender = "0.2.2" stopwatch = "0.0.7" +petgraph = "0.6.4" diff --git a/lyra-resource/src/loader/mod.rs b/lyra-resource/src/loader/mod.rs index c5c9723..78e5e23 100644 --- a/lyra-resource/src/loader/mod.rs +++ b/lyra-resource/src/loader/mod.rs @@ -28,7 +28,7 @@ impl From for LoaderError { } } -pub trait ResourceLoader { +pub trait ResourceLoader: Send + Sync { fn extensions(&self) -> &[&str]; fn does_support_file(&self, path: &str) -> bool; fn load(&self, path: &str) -> Result, LoaderError>; diff --git a/src/ecs/mod.rs b/src/ecs/mod.rs index 7ea540e..4821b86 100755 --- a/src/ecs/mod.rs +++ b/src/ecs/mod.rs @@ -1,31 +1,29 @@ -use std::collections::HashMap; - -use petgraph::{prelude::StableDiGraph, stable_graph::NodeIndex, visit::Topo}; -use tracing::warn; - -use crate::game::Controls; - pub use edict::*; pub mod components; pub mod events; pub use events::*; +use std::collections::HashMap; + +use petgraph::{stable_graph::{StableDiGraph, NodeIndex}, visit::Topo}; +use tracing::warn; + /// A trait that represents a simple system pub trait SimpleSystem { - fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> { + fn setup(&mut self, world: &mut World) -> anyhow::Result<()> { Ok(()) } // todo: make async? - fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()>; + fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()>; } impl SimpleSystem for S where S: FnMut(&mut edict::World) -> anyhow::Result<()> { - fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { - self(controls.world) + fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { + self(world) } } @@ -44,9 +42,9 @@ impl BatchedSystem { } impl SimpleSystem for BatchedSystem { - fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { + fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { for system in self.systems.iter_mut() { - system.execute_mut(controls)?; + system.execute_mut(world)?; } Ok(()) @@ -122,13 +120,13 @@ impl SystemDispatcher { true } - pub(crate) fn execute_systems(&mut self, controls: &mut Controls) { + pub(crate) fn execute_systems(&mut self, world: &mut World) { let mut topo = Topo::new(&self.graph); while let Some(nx) = topo.next(&self.graph) { let node = self.graph.node_weight_mut(nx).unwrap(); - match node.system.execute_mut(controls) { + match node.system.execute_mut(world) { Ok(()) => {}, Err(e) => { warn!("System execution of {} resulted in an error! '{}'.", node.name, e); @@ -144,8 +142,8 @@ impl SystemDispatcher { } impl SimpleSystem for SystemDispatcher { - fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { - self.execute_systems(controls); + fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { + self.execute_systems(world); Ok(()) } diff --git a/src/game.rs b/src/game.rs index ab157b2..e670246 100755 --- a/src/game.rs +++ b/src/game.rs @@ -68,15 +68,11 @@ impl GameLoop { } async fn update(&mut self) { - let mut controls = Controls { - world: &mut self.world, - }; - - if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) { + if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut self.world) { error!("Error when executing engine ecs systems: '{}'", e); } - if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut controls) { + if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut self.world) { error!("Error when executing user ecs systems: '{}'", e); } } @@ -224,9 +220,10 @@ impl GameLoop { } pub struct Game { - pub world: Option, + world: Option, plugins: VecDeque>, system_dispatcher: Option, + startup_systems: VecDeque>, } impl Default for Game { @@ -235,6 +232,7 @@ impl Default for Game { world: Some(edict::World::new()), plugins: VecDeque::new(), system_dispatcher: Some(SystemDispatcher::new()), + startup_systems: VecDeque::new(), } } } @@ -244,6 +242,13 @@ impl Game { Self::default() } + /// Get the world of this game + pub fn world(&mut self) -> &mut edict::World { + // world is always `Some`, so unwrapping is safe + self.world.as_mut().unwrap() + } + + /// Add a system to the ecs world pub fn with_system(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self where S: SimpleSystem + 'static @@ -254,7 +259,18 @@ impl Game { self } - /// Add a plugin to the game + /// Add a startup system that will be ran right after plugins are setup. + /// They will only be ran once + pub fn with_startup_system(&mut self, system: S) -> &mut Self + where + S: SimpleSystem + 'static + { + self.startup_systems.push_back(Box::new(system)); + + self + } + + /// Add a plugin to the game. These will be executed before the window is initiated and opened pub fn with_plugin

(&mut self, plugin: P) -> &mut Self where P: Plugin + 'static @@ -264,12 +280,16 @@ impl Game { self } + /// Override the default (empty) world + /// + /// This isn't recommended, you should create a startup system and add it to `with_startup_system` pub fn with_world(&mut self, world: edict::World) -> &mut Self { self.world = Some(world); self } + /// Start the game pub async fn run(&mut self) { // init logging let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout()); @@ -286,11 +306,19 @@ impl Game { plugin.as_ref().setup(self); } + let mut world = self.world.take().unwrap_or_else(|| edict::World::new()); + + // run startup systems + while let Some(mut startup) = self.startup_systems.pop_front() { + let startup = startup.as_mut(); + startup.setup(&mut world).expect("World returned an error!"); + startup.execute_mut(&mut world).expect("World returned an error!"); + } + // start winit event loops let event_loop = EventLoop::new(); let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap()); - - let world = self.world.take().unwrap_or_else(|| edict::World::new()); + let system_dispatcher = self.system_dispatcher.take().unwrap(); let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await; g_loop.on_init().await; diff --git a/src/input.rs b/src/input.rs index fabdef8..ce0e67a 100755 --- a/src/input.rs +++ b/src/input.rs @@ -313,9 +313,7 @@ impl InputSystem { } impl SimpleSystem for InputSystem { - fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> { - let world = &mut controls.world; - + fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> { let queue = world.get_resource_mut::() .map(|q| q.read_events::()).flatten(); diff --git a/src/lib.rs b/src/lib.rs index eefaaca..d599eed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,17 +8,6 @@ pub mod input; pub mod castable_any; pub mod plugin; -use plugin::Plugin; +pub use lyra_resource as assets; -use crate::input::InputPlugin; - -/// Default plugins of Lyra. Make sure to have these added to the Game first -#[derive(Default)] -pub struct DefaultPlugins; - -impl Plugin for DefaultPlugins { - fn setup(&self, game: &mut game::Game) { - // setup input - InputPlugin::default().setup(game); - } -} \ No newline at end of file +pub use plugin::DefaultPlugins; \ No newline at end of file diff --git a/src/plugin.rs b/src/plugin.rs index 1f28220..8be0e8e 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,4 +1,7 @@ +use lyra_resource::ResourceManager; + use crate::game::Game; +use crate::input::InputPlugin; /// A Plugin is something you can add to a `Game` that can be used to define systems, or spawn initial entities. pub trait Plugin { @@ -73,4 +76,25 @@ impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) } impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) } impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) } -impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) (C14, 14) } \ No newline at end of file +impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) (C14, 14) } + +#[derive(Default)] +pub struct ResourceManagerPlugin; + +impl Plugin for ResourceManagerPlugin { + fn setup(&self, game: &mut Game) { + game.world().insert_resource(ResourceManager::new()); + } +} + +/// Default plugins of Lyra. Make sure to have these added to the Game first +#[derive(Default)] +pub struct DefaultPlugins; + +impl Plugin for DefaultPlugins { + fn setup(&self, game: &mut Game) { + // setup input + InputPlugin::default().setup(game); + ResourceManagerPlugin::default().setup(game); + } +} \ No newline at end of file diff --git a/src/render/material.rs b/src/render/material.rs index d89ae1c..fa5de81 100755 --- a/src/render/material.rs +++ b/src/render/material.rs @@ -1,7 +1,9 @@ -use super::texture::Texture; +use std::sync::Arc; + +use lyra_resource::{Texture, Resource}; #[derive(Clone)] pub struct Material { pub shader_id: u32, - pub texture: Texture, + pub texture: Arc>, } \ No newline at end of file diff --git a/src/render/renderer.rs b/src/render/renderer.rs index bd2f117..0d1aec1 100755 --- a/src/render/renderer.rs +++ b/src/render/renderer.rs @@ -462,8 +462,9 @@ impl BasicRenderer { let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); - let texture_img = &model.material.texture; - let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, &texture_img.img, 0, None).unwrap(); + let model_texture = &model.material.texture; + let image = &model_texture.data.as_ref().unwrap().image; + let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, image, None).unwrap(); let texture_bind_group_layout = self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { diff --git a/src/render/texture.rs b/src/render/texture.rs index 0d8d689..bf69703 100755 --- a/src/render/texture.rs +++ b/src/render/texture.rs @@ -1,8 +1,9 @@ use std::sync::Arc; use image::GenericImageView; +use lyra_resource::{Resource, Texture}; -#[derive(Clone)] +/* #[derive(Clone)] pub struct Texture { texture_id: u32, pub img: image::DynamicImage, @@ -17,14 +18,13 @@ impl Texture { img, }) } -} +} */ #[derive(Clone)] #[allow(dead_code)] pub struct RenderTexture { - texture_id: u32, texture: Arc, view: Arc, sampler: Arc, @@ -33,12 +33,12 @@ pub struct RenderTexture { impl RenderTexture { pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], texture_id: u32, label: &str) -> anyhow::Result { + pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str) -> anyhow::Result { let img = image::load_from_memory(bytes)?; - Self::from_image(device, queue, &img, texture_id, Some(label)) + Self::from_image(device, queue, &img, Some(label)) } - pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, texture_id: u32, label: Option<&str>) -> anyhow::Result { + pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str>) -> anyhow::Result { let rgba = img.to_rgba8(); let dimensions = img.dimensions(); @@ -90,16 +90,16 @@ impl RenderTexture { ); Ok(Self { - texture_id, texture: Arc::new(texture), view: Arc::new(view), sampler: Arc::new(sampler), }) } - pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Texture) { - let rgba = texture.img.to_rgba8(); - let dimensions = texture.img.dimensions(); + pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Arc>) { + let texture = &texture.data.as_ref().unwrap().image; + let rgba = texture.to_rgba8(); + let dimensions = texture.dimensions(); let size = wgpu::Extent3d { width: dimensions.0, height: dimensions.1, @@ -162,7 +162,6 @@ impl RenderTexture { texture: Arc::new(texture), view: Arc::new(view), sampler: Arc::new(sampler), - texture_id: 0 } }