From 5a9f632e3afd4c7c721b539c7335dcf9c1d4c445 Mon Sep 17 00:00:00 2001 From: lisk77 Date: Wed, 13 Nov 2024 03:33:02 +0100 Subject: [PATCH] feat: added a camera with orthographic projection and did some work restructuring the comet_app to make the setup system optional. Input handling is moved to the app --- Cargo.toml | 7 +- crates/comet_app/Cargo.toml | 5 +- crates/comet_app/src/app.rs | 160 ++++--- crates/comet_ecs/Cargo.toml | 5 +- crates/comet_ecs/src/component.rs | 148 ++++-- crates/comet_ecs/src/world.rs | 17 +- crates/comet_input/Cargo.toml | 5 +- crates/comet_input/src/input_handler.rs | 73 +++ crates/comet_input/src/keyboard.rs | 16 +- crates/comet_input/src/lib.rs | 1 + crates/comet_log/src/lib.rs | 68 ++- crates/comet_math/Cargo.toml | 4 +- crates/comet_math/src/matrix.rs | 161 ++++++- crates/comet_math/src/vector.rs | 497 +++++++++++++++++++- crates/comet_renderer/Cargo.toml | 3 +- crates/comet_renderer/src/camera.rs | 38 +- crates/comet_renderer/src/lib.rs | 163 ++++--- crates/comet_renderer/src/shader.wgsl | 9 +- crates/comet_resources/src/texture_atlas.rs | 3 +- crates/comet_resources/src/vertex.rs | 15 +- src/lib.rs | 6 +- src/main.rs | 118 +++-- 22 files changed, 1173 insertions(+), 349 deletions(-) create mode 100644 crates/comet_input/src/input_handler.rs diff --git a/Cargo.toml b/Cargo.toml index 1f4ee5c..d296a75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,8 @@ instant = "0.1" image = { version = "0.24", default_features = false, features = ["png", "jpeg", "hdr"] } chrono = "0.4.38" colored = "2.1.0" - +winit_input_helper = "0.16.0" +spin_sleep = "1.2.1" [build-dependencies] anyhow = "1.0" @@ -43,7 +44,7 @@ members = [ "./crates/comet_ecs", "./crates/comet_input", "./crates/comet_log" -] +, "crates/comet_ui"] [workspace.dependencies] comet_app = { path = "./crates/comet_app", workspace = true } @@ -53,4 +54,4 @@ comet_renderer = { path = "./crates/comet_renderer", workspace = true } comet_resources = { path = "./crates/comet_resources", workspace = true } comet_ecs = { path = "./crates/comet_ecs", workspace = true } comet_input = { path = "./crates/comet_input", workspace = true } -comet_log = { path = "./crates/comet_log", workspace = true } \ No newline at end of file +comet_log = { path = "./crates/comet_log", workspace = true } diff --git a/crates/comet_app/Cargo.toml b/crates/comet_app/Cargo.toml index 6e0d8e0..446a9d8 100644 --- a/crates/comet_app/Cargo.toml +++ b/crates/comet_app/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "comet_app" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] @@ -9,6 +9,7 @@ comet_renderer = { path = "../comet_renderer" } comet_resources = { path = "../comet_resources" } comet_colors = { path = "../comet_colors" } comet_log = { path = "../comet_log" } +comet_input = { path = "../comet_input" } winit = { version = "0.29", features = ["rwh_05"] } env_logger = "0.10" @@ -18,6 +19,8 @@ log = "0.4.22" anyhow = "1.0.89" bytemuck = "1.18.0" chrono = "0.4.0" +winit_input_helper = "0.16.0" +spin_sleep = "1.2.1" [dependencies.image] version = "0.24" diff --git a/crates/comet_app/src/app.rs b/crates/comet_app/src/app.rs index e795330..5d20566 100644 --- a/crates/comet_app/src/app.rs +++ b/crates/comet_app/src/app.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use std::time::{Duration, Instant}; use comet_ecs::{Component, ComponentSet, Render, Renderer2D, Transform2D, World}; use comet_resources::{ResourceManager, Vertex}; use comet_renderer::{Renderer}; @@ -13,6 +14,11 @@ use comet_colors::LinearRgba; use comet_ecs::math::Point3; use comet_log::*; use winit::dpi::{LogicalSize, PhysicalSize}; +use winit::event_loop::ControlFlow; +use winit::platform::windows::WindowBuilderExtWindows; +use winit_input_helper::WinitInputHelper; +use comet_input::input_handler::InputHandler; +use comet_input::keyboard::Key; pub enum ApplicationType { App2D, @@ -24,6 +30,10 @@ pub struct App<'a> { icon: Option, size: Option>, clear_color: Option, + setup: Option, + input_manager: WinitInputHelper, + delta_time: f32, + update_timer: f32, world: World, fullscreen: bool, should_quit: bool @@ -41,6 +51,10 @@ impl<'a> App<'a> { icon: None, size: None, clear_color: None, + setup: None, + input_manager: WinitInputHelper::new(), + delta_time: 0.0, + update_timer: 0.0166667, world, fullscreen: false, should_quit: false @@ -67,6 +81,11 @@ impl<'a> App<'a> { self } + pub fn with_setup(mut self, setup: fn(&mut World)) -> Self { + self.setup = Some(setup); + self + } + fn load_icon(path: &std::path::Path) -> Option { let image = image::open(path).expect("Failed to open icon image"); let rgba_image = image.to_rgba8(); @@ -74,51 +93,6 @@ impl<'a> App<'a> { Some(Icon::from_rgba(rgba_image.into_raw(), width, height).unwrap()) } - pub fn render_scene_2d(&self, renderer: &mut Renderer) { - let entities = self.world.get_entities_with(ComponentSet::from_ids(vec![Renderer2D::type_id()])); - let mut vertex_buffer: Vec = Vec::new(); - let mut index_buffer: Vec = Vec::new(); - - for entity in entities { - let renderer_component = self.world().get_component::(entity as usize); - let transform_component = self.world().get_component::(entity as usize); - - if renderer_component.is_visible() { - //renderer.draw_texture_at(renderer_component.get_texture(), Point3::new(transform_component.position().x(), transform_component.position().y(), 0.0)); - let position = transform_component.position(); - let region = renderer.get_texture(renderer_component.get_texture().to_string()); - let (dim_x, dim_y) = region.dimensions(); - - let (bound_x, bound_y) = - ((dim_x as f32/ renderer.config().width as f32) * 0.5, (dim_y as f32/ renderer.config().height as f32) * 0.5); - - let buffer_size = vertex_buffer.len() as u16; - - vertex_buffer.append(&mut vec![ - Vertex :: new ( [-bound_x + position.x(), bound_y + position.y(), 0.0], [region.x0(), region.y0()] ), - Vertex :: new ( [-bound_x + position.x(), -bound_y + position.y(), 0.0], [region.x0(), region.y1()] ), - Vertex :: new ( [ bound_x + position.x(), -bound_y + position.y(), 0.0], [region.x1(), region.y1()] ) , - Vertex :: new ( [ bound_x + position.x(), bound_y + position.y(), 0.0], [region.x1(), region.y0()] ) - ]); - - index_buffer.append(&mut vec![ - 0 + buffer_size, 1 + buffer_size, 3 + buffer_size, - 1 + buffer_size, 2 + buffer_size, 3 + buffer_size - ]); - } - } - - renderer.set_buffers(vertex_buffer, index_buffer); - - /*for entity in entities { - let renderer_component = self.world.get_component::(entity as usize); - let position_component = self.world.get_component::(entity as usize); - if renderer_component.is_visible() { - renderer.draw_texture_at(renderer_component.get_texture(), Point3::new(position_component.position().x(), position_component.position().y(), 0.0)); - } - }*/ - } - pub fn world(&self) -> &World { &self.world } @@ -127,10 +101,37 @@ impl<'a> App<'a> { &mut self.world } + pub fn input_manager(&self) -> &WinitInputHelper { + &self.input_manager + } + + pub fn key_pressed(&self, key: Key) -> bool { + self.input_manager.key_pressed(key) + } + + pub fn key_held(&self, key: Key) -> bool { + self.input_manager.key_held(key) + } + + pub fn key_released(&self, key: Key) -> bool { + self.input_manager.key_released(key) + } + + pub fn dt(&self) -> f32 { + self.delta_time + } + pub fn quit(&mut self) { self.should_quit = true; } + pub fn get_time_step(&self) -> f32 { + self.update_timer + } + pub fn set_time_step(&mut self, time_step: f32) { + self.update_timer = time_step; + } + fn create_window(app_title: &str, app_icon: &Option, window_size: &Option>, event_loop: &EventLoop<()>) -> winit::window::Window { let winit_window = winit::window::WindowBuilder::new() .with_title(app_title); @@ -141,6 +142,13 @@ impl<'a> App<'a> { else { winit_window }; + let winit_window = if let Some(icon) = app_icon.clone() { + winit_window.with_taskbar_icon(Some(icon)) + } + else { + winit_window + }; + let winit_window = if let Some(size) = window_size.clone() { winit_window.with_inner_size(size) } @@ -151,66 +159,64 @@ impl<'a> App<'a> { winit_window.build(event_loop).unwrap() } - async fn run_app(mut self, input_manager: F, game_manager: G) { - env_logger::init(); + async fn run_app(mut self, update: U) { let event_loop = EventLoop::new().unwrap(); let window = Self::create_window(self.title, &self.icon, &self.size ,&event_loop); - let mut renderer = Renderer::new(&window, self.clear_color.clone()).await.unwrap(); - let mut surface_configured = false; - window.set_maximized(true); + if let Some(setup) = self.setup { + setup(&mut self.world); + } + renderer.initialize_atlas(); - event_loop.run(|event, control_flow| { + let mut time_stack = 0.0; + + event_loop.run(|event, elwt| { + self.delta_time = renderer.update(); + if self.should_quit { - control_flow.exit() + elwt.exit() } - game_manager(&mut self.world, &mut renderer); - self.render_scene_2d(&mut renderer); + + self.input_manager.update(&event); + + time_stack += self.delta_time; + while time_stack > self.update_timer { + let time = self.get_time_step(); + update(&mut self, &mut renderer, time); + time_stack -= self.update_timer; + } + + renderer.render_scene_2d(self.world()); match event { - Event::WindowEvent { - ref event, - window_id, - } if window_id == renderer.window().id() => { + Event::WindowEvent { ref event, window_id, } + if window_id == renderer.window().id() => { match event { - WindowEvent::CloseRequested {} => control_flow.exit(), + WindowEvent::CloseRequested {} => elwt.exit(), WindowEvent::Resized(physical_size) => { - surface_configured = true; renderer.resize(*physical_size); } WindowEvent::RedrawRequested => { renderer.window().request_redraw(); - if !surface_configured { - return; - } - - /*if self.fullscreen && !renderer.window().fullscreen().is_some() { - renderer.resize(renderer.window().inner_size().into()); - }*/ - - renderer.update(); - //println!("{}", 1.0/dt); match renderer.render() { Ok(_) => {} Err( wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated, ) => renderer.resize(renderer.size()), Err(wgpu::SurfaceError::OutOfMemory) => { - log::error!("OutOfMemory"); - control_flow.exit(); + error!("OutOfMemory"); + elwt.exit(); } Err(wgpu::SurfaceError::Timeout) => { warn!("Surface timeout") } } } - _ => { - input_manager(event, &mut self, &mut renderer); - } + _ => {} } } _ => {} @@ -218,7 +224,7 @@ impl<'a> App<'a> { }).unwrap(); } - pub fn run(mut self, input_manager: F, game_manager: G) { - pollster::block_on(self.run_app(input_manager, game_manager)); + pub fn run(mut self, update: U) { + pollster::block_on(self.run_app(update)); } } \ No newline at end of file diff --git a/crates/comet_ecs/Cargo.toml b/crates/comet_ecs/Cargo.toml index b73c105..ca6d2f8 100644 --- a/crates/comet_ecs/Cargo.toml +++ b/crates/comet_ecs/Cargo.toml @@ -4,9 +4,10 @@ version = "0.2.0" edition = "2021" [dependencies] -bit-set = "0.8.0" component_derive = { path = "./component_derive" } comet_math = { path = "../comet_math" } comet_resources = { path = "../comet_resources" } comet_log = { path = "../comet_log" } -chrono = "0.4" \ No newline at end of file + +chrono = "0.4" +bit-set = "0.8.0" \ No newline at end of file diff --git a/crates/comet_ecs/src/component.rs b/crates/comet_ecs/src/component.rs index 3ac9e59..94399c2 100644 --- a/crates/comet_ecs/src/component.rs +++ b/crates/comet_ecs/src/component.rs @@ -1,22 +1,11 @@ -//use comet_resources::Vertex; +use std::cell::RefCell; +use std::rc::Rc; use crate::math::{ Vec2, Vec3 }; use component_derive::Component; -pub trait Component: Send + Sync + PartialEq + Default + 'static { - fn new() -> Self where Self: Sized; - - fn type_id() -> std::any::TypeId { - std::any::TypeId::of::() - } - - fn type_name() -> String { - std::any::type_name::().to_string() - } -} - // ################################################## // # BASIC # // ################################################## @@ -43,6 +32,12 @@ pub struct Rotation3D { theta_z: f32 } +#[derive(Component)] +pub struct Rectangle2D{ + position: Position2D, + size: Vec2 +} + #[derive(Component)] pub struct Renderer2D { is_visible: bool, @@ -50,6 +45,53 @@ pub struct Renderer2D { scale: Vec2 } +// ################################################## +// # BUNDLES # +// ################################################## + +#[derive(Component)] +pub struct Transform2D { + position: Position2D, + rotation: Rotation2D +} + +#[derive(Component)] +pub struct Transform3D { + position: Position3D, + rotation: Rotation3D +} + +// ################################################## +// # TRAITS # +// ################################################## + +pub trait Component: Send + Sync + PartialEq + Default + 'static { + fn new() -> Self where Self: Sized; + + fn type_id() -> std::any::TypeId { + std::any::TypeId::of::() + } + + fn type_name() -> String { + std::any::type_name::().to_string() + } +} + +pub trait Collider { + fn is_colliding(&self, other: &Self) -> bool; +} + +pub trait Render { + fn is_visible(&self) -> bool; + fn set_visibility(&mut self, is_visible: bool); + fn get_texture(&self) -> String; + fn set_texture(&mut self, texture: &'static str); +} + +// ################################################## +// # IMPLS # +// ################################################## + impl Position2D { pub fn from_vec(vec: Vec2) -> Self { Self { @@ -114,12 +156,44 @@ impl Position3D { } } -pub trait Render { - fn is_visible(&self) -> bool; - fn set_visibility(&mut self, is_visible: bool); - fn get_texture(&self) -> String; - fn set_texture(&mut self, texture: &'static str); - //fn get_vertex_data(&self) -> Vec; +impl Rectangle2D { + pub fn new(position: Position2D, size: Vec2) -> Self { + Self { + position, + size + } + } + + pub fn position(&self) -> Position2D { + self.position + } + + pub fn set_position(&mut self, position: Position2D) { + self.position = position; + } + + pub fn size(&self) -> Vec2 { + self.size + } +} + +impl Collider for Rectangle2D { + fn is_colliding(&self, other: &Self) -> bool { + let x1 = self.position().x(); + let y1 = self.position().y(); + let w1 = self.size().x(); + let h1 = self.size().y(); + + let x2 = other.position().x(); + let y2 = other.position().y(); + let w2 = other.size().x(); + let h2 = other.size().y(); + + x1 < x2 + w2 && + x1 + w1 > x2 && + y1 < y2 + h2 && + y1 + h1 > y2 + } } impl Render for Renderer2D { @@ -141,31 +215,6 @@ impl Render for Renderer2D { fn set_texture(&mut self, texture: &'static str) { self.texture = texture; } - - /*fn get_vertex_data(&self) -> Vec { - vec![ - Vertex::new([0.0, 0.0, 0.0], [0.0, 0.0]), - Vertex::new([1.0, 0.0, 0.0], [1.0, 0.0]), - Vertex::new([1.0, 1.0, 0.0], [1.0, 1.0]), - Vertex::new([0.0, 1.0, 0.0], [0.0, 1.0]) - ] - }*/ -} - -// ################################################## -// # BUNDLES # -// ################################################## - -#[derive(Component)] -pub struct Transform2D { - position: Position2D, - rotation: Rotation2D -} - -#[derive(Component)] -pub struct Transform3D { - position: Position3D, - rotation: Rotation3D } impl Transform2D { @@ -184,6 +233,13 @@ impl Transform2D { pub fn rotation_mut(&mut self) -> &mut Rotation2D { &mut self.rotation } + + pub fn translate(&mut self, displacement: Vec2) { + let x = self.position().x() + displacement.x(); + let y = self.position().y() + displacement.y(); + self.position_mut().set_x(x); + self.position_mut().set_y(y); + } } impl Transform3D { @@ -202,6 +258,4 @@ impl Transform3D { pub fn rotation_mut(&mut self) -> &mut Rotation3D { &mut self.rotation } -} - - +} \ No newline at end of file diff --git a/crates/comet_ecs/src/world.rs b/crates/comet_ecs/src/world.rs index edac407..3f62e50 100644 --- a/crates/comet_ecs/src/world.rs +++ b/crates/comet_ecs/src/world.rs @@ -23,16 +23,16 @@ pub struct World { } impl World { - pub fn new(dimension: &str) -> Self { + pub fn new(application: &str) -> Self { let mut component_storage = ComponentStorage::new(); - match dimension { + match application { "2D" => component_storage.register_component::(0), "3D" => component_storage.register_component::(0), _ => {} } Self { - dimension: dimension.to_string(), + dimension: application.to_string(), id_queue: IdQueue::new(), next_id: 0, entities: Vec::new(), @@ -118,7 +118,7 @@ impl World { self.id_queue.sorted_enqueue(entity_id as u32); self.get_next_id(); self.remove_entity_from_archetype_subsets(entity_id as u32, self.get_component_set(entity_id)); - info!(format!("Deleted entity! ID: {}", entity_id)); + info!("Deleted entity! ID: {}", entity_id); } fn create_archetype(&mut self, components: ComponentSet) { @@ -179,12 +179,12 @@ impl World { pub fn register_component(&mut self) { self.components.register_component::(self.entities.len()); self.create_archetype(ComponentSet::from_ids(vec![T::type_id()])); - info!(format!("Registered component: {}", T::type_name())); + info!("Registered component: {}", T::type_name()); } pub fn deregister_component(&mut self) { self.components.deregister_component::(); - info!(format!("Deregistered component: {}", T::type_name())); + info!("Deregistered component: {}", T::type_name()); } pub fn add_component(&mut self, entity_id: usize, component: T) { @@ -201,14 +201,13 @@ impl World { if self.get_component_set(entity_id) != ComponentSet::from_ids(vec![T::type_id()]) { self.add_entity_to_archetype(entity_id as u32, self.get_component_set(entity_id)); } - info!(format!("Added component {} to entity {}", T::type_name(), entity_id)); - debug!(format!("{:?}", self.archetypes)); + info!("Added component {} to entity {}", T::type_name(), entity_id); } pub fn remove_component(&mut self, entity_id: usize) { self.components.remove_component::(entity_id); self.remove_entity_from_archetype_subsets(entity_id as u32, self.get_component_set(entity_id)); - info!(format!("Removed component {} from entity {}", T::type_name(), entity_id)); + info!("Removed component {} from entity {}", T::type_name(), entity_id); } pub fn get_component(&self, entity_id: usize) -> &T { diff --git a/crates/comet_input/Cargo.toml b/crates/comet_input/Cargo.toml index 4e273f4..adf399a 100644 --- a/crates/comet_input/Cargo.toml +++ b/crates/comet_input/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "comet_input" -version = "0.1.0" +version = "0.1.1" edition = "2021" [dependencies] -winit = { version = "0.29", features = ["rwh_05"] } \ No newline at end of file +winit = { version = "0.29", features = ["rwh_05"] } +winit_input_helper = "0.16.0" diff --git a/crates/comet_input/src/input_handler.rs b/crates/comet_input/src/input_handler.rs new file mode 100644 index 0000000..a3113bc --- /dev/null +++ b/crates/comet_input/src/input_handler.rs @@ -0,0 +1,73 @@ +use winit::event::{ElementState, WindowEvent, KeyEvent, Event}; +use std::collections::HashSet; +use winit::event::WindowEvent::KeyboardInput; +use winit::keyboard::PhysicalKey; +use crate::keyboard::Key; + +#[derive(Debug)] +pub struct InputHandler { + keys_pressed: Vec, + keys_held: Vec, + keys_released: Vec +} + +impl InputHandler { + pub fn new() -> Self { + Self { + keys_pressed: Vec::new(), + keys_held: Vec::new(), + keys_released: Vec::new() + } + } + + pub fn update(&mut self, event: &Event) { + match event { + Event::WindowEvent { + event: WindowEvent::KeyboardInput { + event: KeyEvent { + state, + physical_key: PhysicalKey::Code(keycode), + .. + }, + .. + }, + .. + } => + { + match state { + ElementState::Pressed => { + if self.keys_pressed.contains(&PhysicalKey::Code(keycode.clone())) { + self.keys_held.push(PhysicalKey::Code(keycode.clone())); + } else { + self.keys_pressed.push(PhysicalKey::Code(keycode.clone())); + } + self.keys_pressed.push(PhysicalKey::Code(keycode.clone())); + } + ElementState::Released => { + self.keys_released = vec![]; + if let Some(index) = self.keys_pressed.iter().position(|&x| x == PhysicalKey::Code(keycode.clone())) { + self.keys_pressed.remove(index); + } + if let Some(index) = self.keys_held.iter().position(|&x| x == PhysicalKey::Code(keycode.clone())) { + self.keys_held.remove(index); + } + self.keys_released.push(PhysicalKey::Code(keycode.clone())); + } + } + } + _ => {} + } + } + + pub fn key_pressed(&self, key: Key) -> bool { + self.keys_pressed.contains(&PhysicalKey::Code(key)) + } + + pub fn key_held(&self, key: Key) -> bool { + self.keys_held.contains(&PhysicalKey::Code(key)) + } + + pub fn key_released(&self, key: Key) -> bool { + self.keys_released.contains(&PhysicalKey::Code(key)) + } +} diff --git a/crates/comet_input/src/keyboard.rs b/crates/comet_input/src/keyboard.rs index cb0b36d..f81206b 100644 --- a/crates/comet_input/src/keyboard.rs +++ b/crates/comet_input/src/keyboard.rs @@ -1,5 +1,5 @@ use winit::event::{ElementState, KeyEvent, WindowEvent}; -use winit::keyboard::{ KeyCode, PhysicalKey}; +use winit::keyboard::{ KeyCode, PhysicalKey }; pub type Key = KeyCode; @@ -29,4 +29,18 @@ pub fn key_released(event: &WindowEvent, key_code: Key) -> bool { } => *code == key_code, _ => false, } +} + +pub fn key_press(event: &WindowEvent, key_code: Key) -> bool { + match event { + WindowEvent::KeyboardInput { + event: KeyEvent { + state: ElementState::Pressed, + physical_key: PhysicalKey::Code(code), + .. + }, + .. + } => *code == key_code, + _ => false, + } } \ No newline at end of file diff --git a/crates/comet_input/src/lib.rs b/crates/comet_input/src/lib.rs index 73cdf76..1b160c5 100644 --- a/crates/comet_input/src/lib.rs +++ b/crates/comet_input/src/lib.rs @@ -1,2 +1,3 @@ pub mod keyboard; pub mod mouse; +pub mod input_handler; diff --git a/crates/comet_log/src/lib.rs b/crates/comet_log/src/lib.rs index 605a50c..eb979e0 100644 --- a/crates/comet_log/src/lib.rs +++ b/crates/comet_log/src/lib.rs @@ -1,47 +1,83 @@ #[macro_export] macro_rules! info { - ($msg:expr) => { - println!( - "{} {} : {}", + ($fmt:expr $(, $args:expr)*) => { + eprintln!( + "{} [{}::{}] [{}] : {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + std::env::var("CARGO_PKG_NAME").unwrap(), + module_path!(), "\x1b[32m\x1b[1mINFO\x1b[0m", - $msg + format!($fmt $(, $args)*) ); }; } #[macro_export] macro_rules! debug { - ($msg:expr) => { - println!( - "{} {} : {}", + ($fmt:expr $(, $args:expr)*) => { + eprintln!( + "{} [{}::{}] [{}] : {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + std::env::var("CARGO_PKG_NAME").unwrap(), + module_path!(), "\x1b[34m\x1b[1mDEBUG\x1b[0m", - $msg + format!($fmt $(, $args)*) ); }; } #[macro_export] macro_rules! warn { - ($msg:expr) => { - println!( - "{} {} : {}", + ($fmt:expr $(, $args:expr)*) => { + eprintln!( + "{} [{}::{}] [{}] : {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + std::env::var("CARGO_PKG_NAME").unwrap(), + module_path!(), "\x1b[33m\x1b[1mWARNING\x1b[0m", - $msg + format!($fmt $(, $args)*) ); }; } #[macro_export] macro_rules! error { - ($msg:expr) => { - println!( - "{} {} : {}", + ($fmt:expr $(, $args:expr)*) => { + eprintln!( + "{} [{}::{}] [{}] : {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + std::env::var("CARGO_PKG_NAME").unwrap(), + module_path!(), "\x1b[31m\x1b[1mERROR\x1b[0m", - $msg + format!($fmt $(, $args)*) + ); + }; +} + +#[macro_export] +macro_rules! fatal { + ($fmt:expr $(, $args:expr)*) => { + eprintln!( + "{} [{}::{}] [{}] : {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + std::env::var("CARGO_PKG_NAME").unwrap(), + module_path!(), + "\x1b[41mFATAL\x1b[0m", + format!($fmt $(, $args)*) + ); + }; +} + +#[macro_export] +macro_rules! trace { + ($fmt:expr $(, $args:expr)*) => { + eprintln!( + "{} [{}::{}] [{}] : {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + std::env::var("CARGO_PKG_NAME").unwrap(), + module_path!(), + "\x1b[35m\x1b[1mTRACE\x1b[0m", + format!($fmt $(, $args)*) ); }; } \ No newline at end of file diff --git a/crates/comet_math/Cargo.toml b/crates/comet_math/Cargo.toml index 8ecdd68..8cb1071 100644 --- a/crates/comet_math/Cargo.toml +++ b/crates/comet_math/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "comet_math" -version = "0.1.0" +version = "0.1.1" edition = "2021" [dependencies] +comet_log = { path = "../comet_log" } num-traits = "0.2.19" +chrono = "0.4.0" \ No newline at end of file diff --git a/crates/comet_math/src/matrix.rs b/crates/comet_math/src/matrix.rs index be3fd89..74da5d5 100644 --- a/crates/comet_math/src/matrix.rs +++ b/crates/comet_math/src/matrix.rs @@ -11,7 +11,7 @@ trait LinearTransformation { // ################################################## -/// Representation of a 2x2 Matrix in row major +/// Representation of a 2x2 Matrix #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq)] @@ -39,13 +39,20 @@ impl Mat2 { } } - pub fn from_vec(row1: Vec2, row2: Vec2) -> Self { + pub fn from_rows(row1: Vec2, row2: Vec2) -> Self { Self { x00: row1.x(), x01: row1.y(), x10: row2.x(), x11: row2.y() } } + pub fn from_cols(col1: Vec2, col2: Vec2) -> Self { + Self { + x00: col1.x(), x01: col2.x(), + x10: col1.y(), x11: col2.y() + } + } + pub fn get(&self, row: usize, col: usize) -> Option { assert!(row <= 1, "This row ({}) is out of bounds! Bounds: 0..1", row); assert!(col <= 1, "This row ({}) is out of bounds! Bounds: 0..1", col); @@ -68,6 +75,15 @@ impl Mat2 { } } + pub fn get_col(&self, col: usize) -> Option { + assert!(col <= 1, "This row ({}) is out of bounds! Bounds: 0..1", col); + match col { + 0 => Some(Vec2::new(self.x00, self.x10)), + 1 => Some(Vec2::new(self.x01, self.x11)), + _ => None + } + } + pub fn set(&mut self, row: usize, col: usize, element: f32) { assert!(row <= 1, "This row ({}) is out of bounds! Bounds: 0..1", row); assert!(col <= 1, "This row ({}) is out of bounds! Bounds: 0..1", col); @@ -91,6 +107,16 @@ impl Mat2 { } } + pub fn set_col(&mut self, col: usize, col_content: Vec2) { + assert!(col <= 1, "This row ({}) is out of bounds! Bounds: 0..1", col); + + match col { + 0 => { self.x00 = col_content.x(); self.x10 = col_content.y(); }, + 1 => { self.x01 = col_content.x(); self.x11 = col_content.y(); }, + _ => {} + } + } + pub fn det(&self) -> f32 { self.x00 * self.x11 - self.x01 * self.x10 @@ -108,6 +134,12 @@ impl Mat2 { self.set_row(row1, self.get_row(row2).expect(format!("This row ({}) is out of bounds! Bounds: 0..1", row2).as_str())); self.set_row(row2, tmp); } + + pub fn swap_cols(&mut self, col1: usize, col2: usize) { + let tmp = self.get_col(col1).expect(format!("This row ({}) is out of bounds! Bounds: 0..1", col1).as_str()); + self.set_col(col1, self.get_col(col2).expect(format!("This row ({}) is out of bounds! Bounds: 0..1", col2).as_str())); + self.set_col(col2, tmp); + } } impl Add for Mat2 { @@ -187,11 +219,12 @@ impl Div for Mat2 { } } +/// [WARN]: This will return a column-major array for wgpu use! impl Into<[[f32; 2]; 2]> for Mat2 { fn into(self) -> [[f32; 2]; 2] { [ - [self.x00, self.x01], - [self.x10, self.x11], + [self.x00, self.x10], + [self.x01, self.x11], ] } } @@ -235,7 +268,7 @@ impl Mat3 { } } - pub fn from_vec(row1: Vec3, row2: Vec3, row3: Vec3) -> Self { + pub fn from_rows(row1: Vec3, row2: Vec3, row3: Vec3) -> Self { Self { x00: row1.x(), x01: row1.y(), x02: row1.z(), x10: row2.x(), x11: row2.y(), x12: row2.z(), @@ -243,6 +276,14 @@ impl Mat3 { } } + pub fn from_cols(col1: Vec3, col2: Vec3, col3: Vec3) -> Self { + Self { + x00: col1.x(), x01: col2.x(), x02: col3.x(), + x10: col1.y(), x11: col2.y(), x12: col3.y(), + x20: col1.z(), x21: col2.z(), x22: col3.z() + } + } + pub fn get(&self, row: usize, col: usize) -> Option { assert!(row <= 2, "This row ({}) is out of bounds! Bounds: 0..2", row); assert!(col <= 2, "This row ({}) is out of bounds! Bounds: 0..2", col); @@ -270,6 +311,16 @@ impl Mat3 { } } + pub fn get_col(&self, col: usize) -> Option { + assert!(col <= 2, "This row ({}) is out of bounds! Bounds: 0..2", col); + match col { + 0 => Some(Vec3::new(self.x00, self.x10, self.x20)), + 1 => Some(Vec3::new(self.x01, self.x11, self.x21)), + 2 => Some(Vec3::new(self.x02, self.x12, self.x22)), + _ => None + } + } + pub fn set(&mut self, row: usize, col: usize, element: f32) { assert!(row <= 2, "This row ({}) is out of bounds! Bounds: 0..2", row); assert!(col <= 2, "This row ({}) is out of bounds! Bounds: 0..2", col); @@ -298,6 +349,16 @@ impl Mat3 { } } + pub fn set_col(&mut self, col: usize, col_content: Vec3) { + assert!(col <= 2, "This row ({}) is out of bounds! Bounds: 0..2", col); + match col { + 0 => { self.x00 = col_content.x; self.x10 = col_content.y; self.x20 = col_content.z; }, + 1 => { self.x01 = col_content.x; self.x11 = col_content.y; self.x21 = col_content.z; }, + 2 => { self.x02 = col_content.x; self.x12 = col_content.y; self.x22 = col_content.z; } + _ => {} + } + } + pub fn det(&self) -> f32 { self.x00 * self.x11 * self.x22 + self.x01 * self.x12 * self.x20 @@ -320,6 +381,12 @@ impl Mat3 { self.set_row(row1, self.get_row(row2).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", row2).as_str())); self.set_row(row2, tmp); } + + pub fn swap_cols(&mut self, col1: usize, col2: usize) { + let tmp = self.get_col(col1).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", col1).as_str()); + self.set_col(col1, self.get_col(col2).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", col2).as_str())); + self.set_col(col2, tmp); + } } impl Add for Mat3 { @@ -412,9 +479,9 @@ impl Div for Mat3 { impl Into<[[f32; 3]; 3]> for Mat3 { fn into(self) -> [[f32; 3]; 3] { [ - [self.x00, self.x01, self.x02], - [self.x10, self.x11, self.x12], - [self.x20, self.x21, self.x22], + [self.x00, self.x10, self.x20], + [self.x01, self.x11, self.x21], + [self.x02, self.x12, self.x22], ] } } @@ -470,7 +537,7 @@ impl Mat4 { } } - pub fn from_vec(row1: Vec4, row2: Vec4, row3: Vec4, row4: Vec4) -> Self { + pub fn from_rows(row1: Vec4, row2: Vec4, row3: Vec4, row4: Vec4) -> Self { Self { x00: row1.x(), x01: row1.y(), x02: row1.z(), x03: row1.w(), x10: row2.x(), x11: row2.y(), x12: row2.z(), x13: row2.w(), @@ -479,6 +546,15 @@ impl Mat4 { } } + pub fn from_cols(col1: Vec4, col2: Vec4, col3: Vec4, col4: Vec4) -> Self { + Self { + x00: col1.x(), x01: col2.x(), x02: col3.x(), x03: col4.x(), + x10: col1.y(), x11: col2.y(), x12: col3.y(), x13: col4.y(), + x20: col1.z(), x21: col2.z(), x22: col3.z(), x23: col4.z(), + x30: col1.w(), x31: col2.w(), x32: col3.w(), x33: col4.w() + } + } + pub fn rh_look_to(camera: Point3, dir: Vec3, up: Vec3) -> Self { let f = dir.normalize(); let s = cross(f, up).normalize(); @@ -486,19 +562,19 @@ impl Mat4 { let cam = camera.to_vec(); - /*Mat4::new( + Mat4::new( s.x().clone(), u.x().clone(), -f.x().clone(), 0.0, s.y().clone(), u.y().clone(), -f.y().clone(), 0.0, s.z().clone(), u.z().clone(), -f.z().clone(), 0.0, -dot(&cam, &s), -dot(&cam, &u), dot(&cam, &f),1.0 - )*/ + ) - Mat4::new( + /*Mat4::new( s.x().clone(), s.y().clone(), s.z().clone(), 0.0, u.x().clone(), u.y().clone(), u.z().clone(), 0.0, -f.x().clone(), -f.y().clone(), -f.z().clone(), 0.0, -dot(&cam, &s), -dot(&cam, &u), dot(&cam, &f), 1.0 - ) + )*/ } @@ -524,22 +600,31 @@ impl Mat4 { let bottom = -ymax; let top = ymax; - /*Mat4::new( + Mat4::new( (2.0 * near) / (right - left), 0.0, (right + left) / (right - left), 0.0, 0.0, (2.0 * near) / (top - bottom), (top + bottom) / (top - bottom), 0.0, 0.0, 0.0, -(far + near) / (far - near), -(2.0 * far * near) / (far - near), 0.0, 0.0, -1.0, 0.0 - )*/ + ) - Mat4::new( + /*Mat4::new( (2.0 * near) / (right - left), 0.0, 0.0, 0.0, 0.0, (2.0 * near) / (top - bottom), 0.0, 0.0, (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1.0, 0.0, 0.0, -(2.0 * far * near) / (far - near), 0.0 - ) + )*/ } + pub fn orthographic_matrix(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) -> Self { + Mat4::new( + 2.0 / (right - left), 0.0, 0.0, 0.0, + 0.0, 2.0 / (top - bottom), 0.0, 0.0, + 0.0, 0.0, -2.0 / (far - near), 0.0, + -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1.0 + ) + } + pub fn get(&self, row: usize, col: usize) -> Option { assert!(row <= 3, "This row ({}) is out of bounds! Bounds: 0..3", row); assert!(col <= 3, "This row ({}) is out of bounds! Bounds: 0..3", col); @@ -575,6 +660,17 @@ impl Mat4 { } } + pub fn get_col(&self, col: usize) -> Option { + assert!(col <= 3, "This row ({}) is out of bounds! Bounds: 0..3", col); + match col { + 0 => Some(Vec4::new(self.x00, self.x10, self.x20, self.x30)), + 1 => Some(Vec4::new(self.x01, self.x11, self.x21, self.x31)), + 2 => Some(Vec4::new(self.x02, self.x12, self.x22, self.x32)), + 3 => Some(Vec4::new(self.x03, self.x13, self.x23, self.x33)), + _ => None + } + } + pub fn set(&mut self, row: usize, col: usize, element: f32) { assert!(row <= 3, "The given row ({}) is out of bounds! Bounds: 0..3", row); assert!(col <= 3, "The given column ({}) is out of bounds! Bounds: 0..3", col); @@ -610,6 +706,17 @@ impl Mat4 { } } + pub fn set_col(&mut self, col: usize, col_content: Vec4) { + assert!(col <= 3, "This column ({}) is out of bounds! Bounds: 0..3", col); + match col { + 0 => { self.x00 = col_content.x(); self.x10 = col_content.y(); self.x20 = col_content.z(); self.x30 = col_content.w(); }, + 1 => { self.x01 = col_content.x(); self.x11 = col_content.y(); self.x21 = col_content.z(); self.x31 = col_content.w(); }, + 2 => { self.x02 = col_content.x(); self.x12 = col_content.y(); self.x22 = col_content.z(); self.x32 = col_content.w(); }, + 3 => { self.x03 = col_content.x(); self.x13 = col_content.y(); self.x23 = col_content.z(); self.x33 = col_content.w(); } + _ => {} + } + } + pub fn det(&self) -> f32 { self.x00 * (self.x11 * (self.x22* self.x33 - self.x23 * self.x32) - self.x21 * (self.x12 * self.x33 - self.x13 * self.x32) @@ -633,6 +740,18 @@ impl Mat4 { x30: self.x03, x31: self.x13, x32: self.x23, x33: self.x33 } } + + pub fn swap_rows(&mut self, row1: usize, row2: usize) { + let tmp = self.get_row(row1).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", row1).as_str()); + self.set_row(row1, self.get_row(row2).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", row2).as_str())); + self.set_row(row2, tmp); + } + + pub fn swap_cols(&mut self, col1: usize, col2: usize) { + let tmp = self.get_col(col1).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", col1).as_str()); + self.set_col(col1, self.get_col(col2).expect(format!("This row ({}) is out of bounds! Bounds: 0..2", col2).as_str())); + self.set_col(col2, tmp); + } } impl Add for Mat4 { @@ -715,10 +834,10 @@ impl Mul for Mat4 { impl Into<[[f32; 4]; 4]> for Mat4 { fn into(self) -> [[f32; 4]; 4] { [ - [self.x00, self.x01, self.x02, self.x03], - [self.x10, self.x11, self.x12, self.x13], - [self.x20, self.x21, self.x22, self.x23], - [self.x30, self.x31, self.x32, self.x33], + [self.x00, self.x10, self.x20, self.x30], + [self.x01, self.x11, self.x21, self.x31], + [self.x02, self.x12, self.x22, self.x32], + [self.x03, self.x13, self.x23, self.x33], ] } } diff --git a/crates/comet_math/src/vector.rs b/crates/comet_math/src/vector.rs index 556bd0a..25a1609 100644 --- a/crates/comet_math/src/vector.rs +++ b/crates/comet_math/src/vector.rs @@ -1,12 +1,13 @@ use crate::point::{Point2, Point3}; use crate::quaternion::Quat; use crate::utilities::acos; -use std::ops::{Add, Div, Mul, Sub}; +use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; +use comet_log::*; pub trait InnerSpace { fn dot(&self, other: &Self) -> f32; fn dist(&self, other: &Self) -> f32; - fn vAngle(&self, other: &Self) -> f32; + fn v_angle(&self, other: &Self) -> f32; } // ################################################## @@ -103,6 +104,13 @@ impl Add for Vec2 { } } +impl AddAssign for Vec2 { + fn add_assign(&mut self, other: Vec2) { + self.x += other.x; + self.y += other.y; + } +} + impl Sub for Vec2 { type Output = Vec2; @@ -114,6 +122,13 @@ impl Sub for Vec2 { } } +impl SubAssign for Vec2 { + fn sub_assign(&mut self, other: Vec2) { + self.x -= other.x; + self.y -= other.y; + } +} + impl Mul for Vec2 { type Output = Vec2; @@ -125,6 +140,228 @@ impl Mul for Vec2 { } } +impl Into<[f32;2]> for Vec2 { + fn into(self) -> [f32;2] { + [self.x, self.y] + } +} + +impl Into for [f32;2] { + fn into(self) -> Vec2 { + Vec2 { + x: self[0], + y: self[1], + } + } +} + +/// Representation of a 2D integer Vector +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct IVec2 { + x: i64, + y: i64, +} + +impl IVec2 { + pub const X: IVec2 = IVec2 { x: 1, y: 0 }; + pub const Y: IVec2 = IVec2 { x: 0, y: 1 }; + pub const ZERO: IVec2 = IVec2 { x: 0, y: 0 }; + + pub const fn new(x: i64, y: i64) -> Self { + IVec2 { x, y } + } + + pub fn from_point(p: Point2) -> Self { + Self { x: p.x() as i64, y: p.y() as i64 } + } + + pub fn as_vec2(&self) -> Vec2 { + Vec2 { + x: self.x as f32, + y: self.y as f32, + } + } + + pub fn x(&self) -> i64 { + self.x + } + + pub fn y(&self) -> i64 { + self.y + } + + pub fn set_x(&mut self, new_x: i64) { + self.x = new_x; + } + + pub fn set_y(&mut self, new_y: i64) { + self.y = new_y; + } + + pub fn length(&self) -> i64 { + ((self.x * self.x + self.y * self.y) as f32).sqrt() as i64 + } + + pub fn normalize(&self) -> Self { + let factor = 1.0 / self.length() as f32; + IVec2 { + x: (factor * self.x as f32) as i64, + y: (factor * self.y as f32) as i64, + } + } + + pub fn xx(&self) -> Self { + Self { + x: self.x, + y: self.x, + } + } + + pub fn xy(&self) -> Self { + Self { + x: self.x, + y: self.y, + } + } + + pub fn yx(&self) -> Self { + Self { + x: self.y, + y: self.x, + } + } + + pub fn yy(&self) -> Self { + Self { + x: self.y, + y: self.y, + } + } +} + +impl Add for IVec2 { + type Output = IVec2; + + fn add(self, other: IVec2) -> IVec2 { + IVec2 { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +impl Add for Vec2 { + type Output = Vec2; + + fn add(self, other: IVec2) -> Vec2 { + Vec2 { + x: self.x + other.x as f32, + y: self.y + other.y as f32, + } + } +} + +impl Add for IVec2 { + type Output = Vec2; + + fn add(self, other: Vec2) -> Vec2 { + Vec2 { + x: self.x as f32 + other.x, + y: self.y as f32 + other.y, + } + } +} + +impl AddAssign for IVec2 { + fn add_assign(&mut self, other: IVec2) { + self.x += other.x; + self.y += other.y; + } +} + +impl Sub for IVec2 { + type Output = IVec2; + + fn sub(self, other: IVec2) -> IVec2 { + IVec2 { + x: self.x - other.x, + y: self.y - other.y, + } + } +} + +impl Sub for Vec2 { + type Output = Vec2; + + fn sub(self, other: IVec2) -> Vec2 { + Vec2 { + x: self.x - other.x as f32, + y: self.y - other.y as f32, + } + } +} + +impl Sub for IVec2 { + type Output = Vec2; + + fn sub(self, other: Vec2) -> Vec2 { + Vec2 { + x: self.x as f32 - other.x, + y: self.y as f32 - other.y, + } + } +} + +impl SubAssign for IVec2 { + fn sub_assign(&mut self, other: IVec2) { + self.x -= other.x; + self.y -= other.y; + } +} + +impl Mul for IVec2 { + type Output = IVec2; + + fn mul(self, other: f32) -> IVec2 { + IVec2 { + x: self.x * other as i64, + y: self.y * other as i64, + } + } +} + +impl From for Vec2 { + fn from(v: IVec2) -> Vec2 { + Vec2 { + x: v.x as f32, + y: v.y as f32, + } + } +} + +impl From for IVec2 { + fn from(v: Vec2) -> IVec2 { + IVec2 { + x: v.x as i64, + y: v.y as i64, + } + } +} + +impl Into<[i64;2]> for IVec2 { + fn into(self) -> [i64;2] { + [self.x, self.y] + } +} + +impl Into<[f32;2]> for IVec2 { + fn into(self) -> [f32;2] { + [self.x as f32, self.y as f32] + } +} + // ################################################## // # VECTOR 3D # // ################################################## @@ -181,17 +418,6 @@ impl Vec3 { self.z = new_z; } - pub fn into_quaternion(&self) -> Quat { - Quat { - s: 0.0, - v: Vec3 { - x: self.x, - y: self.y, - z: self.z, - } - } - } - pub fn length(&self) -> f32 { (self.x * self.x + self.y * self.y + self.z * self.z).sqrt() } @@ -408,6 +634,14 @@ impl Add for Vec3 { } } +impl AddAssign for Vec3 { + fn add_assign(&mut self, other: Vec3) { + self.x += other.x; + self.y += other.y; + self.z += other.z; + } +} + impl Sub for Vec3 { type Output = Vec3; @@ -420,6 +654,14 @@ impl Sub for Vec3 { } } +impl SubAssign for Vec3 { + fn sub_assign(&mut self, other: Vec3) { + self.x -= other.x; + self.y -= other.y; + self.z -= other.z; + } +} + impl Mul for Vec3 { type Output = Vec3; @@ -432,6 +674,202 @@ impl Mul for Vec3 { } } +impl Into for Vec3 { + fn into(self) -> Quat { + Quat::new(0.0, self) + } +} + +impl Into<[f32;3]> for Vec3 { + fn into(self) -> [f32;3] { + [self.x, self.y, self.z] + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct IVec3 { + pub x: i64, + pub y: i64, + pub z: i64, +} + +impl IVec3 { + pub const X: IVec3 = IVec3 { x: 1, y: 0, z: 0 }; + pub const Y: IVec3 = IVec3 { x: 0, y: 1, z: 0 }; + pub const Z: IVec3 = IVec3 { x: 0, y: 0, z: 1 }; + pub const ZERO: IVec3 = IVec3 { x: 0, y: 0, z: 0 }; + + pub const fn new(x: i64, y: i64, z: i64) -> Self { + IVec3 { x, y, z } + } + + pub fn from_point(p: Point3) -> Self { + Self { + x: p.x() as i64, + y: p.y() as i64, + z: p.z() as i64, + } + } + + pub fn x(&self) -> i64 { + self.x + } + + pub fn y(&self) -> i64 { + self.y + } + + pub fn z(&self) -> i64 { + self.z + } + + pub fn set_x(&mut self, new_x: i64) { + self.x = new_x; + } + + pub fn set_y(&mut self, new_y: i64) { + self.y = new_y; + } + + pub fn set_z(&mut self, new_z: i64) { + self.z = new_z; + } + + pub fn length(&self) -> i64 { + ((self.x * self.x + self.y * self.y + self.z * self.z) as f32).sqrt() as i64 + } + + pub fn normalize(&self) -> Self { + let factor = 1 / self.length(); + IVec3 { + x: factor * self.x, + y: factor * self.y, + z: factor * self.z, + } + } +} + +impl Add for IVec3 { + type Output = IVec3; + + fn add(self, other: IVec3) -> IVec3 { + IVec3 { + x: self.x + other.x, + y: self.y + other.y, + z: self.z + other.z, + } + } +} + +impl Add for Vec3 { + type Output = Vec3; + + fn add(self, other: IVec3) -> Vec3 { + Vec3 { + x: self.x + other.x as f32, + y: self.y + other.y as f32, + z: self.z + other.z as f32, + } + } +} + +impl Add for IVec3 { + type Output = Vec3; + + fn add(self, other: Vec3) -> Vec3 { + Vec3 { + x: self.x as f32 + other.x, + y: self.y as f32 + other.y, + z: self.z as f32 + other.z, + } + } +} + +impl AddAssign for IVec3 { + fn add_assign(&mut self, other: IVec3) { + self.x += other.x; + self.y += other.y; + self.z += other.z; + } +} + +impl Sub for IVec3 { + type Output = IVec3; + + fn sub(self, other: IVec3) -> IVec3 { + IVec3 { + x: self.x - other.x, + y: self.y - other.y, + z: self.z - other.z, + } + } +} + +impl Sub for Vec3 { + type Output = Vec3; + + fn sub(self, other: IVec3) -> Vec3 { + Vec3 { + x: self.x - other.x as f32, + y: self.y - other.y as f32, + z: self.z - other.z as f32, + } + } +} + +impl Sub for IVec3 { + type Output = Vec3; + + fn sub(self, other: Vec3) -> Vec3 { + Vec3 { + x: self.x as f32 - other.x, + y: self.y as f32 - other.y, + z: self.z as f32 - other.z, + } + } +} + +impl SubAssign for IVec3 { + fn sub_assign(&mut self, other: IVec3) { + self.x -= other.x; + self.y -= other.y; + } +} + +impl Mul for IVec3 { + type Output = IVec3; + + fn mul(self, other: f32) -> IVec3 { + IVec3 { + x: self.x * other as i64, + y: self.y * other as i64, + z: self.z * other as i64, + } + } +} + +impl From for Vec3 { + fn from(v: IVec3) -> Vec3 { + Vec3 { + x: v.x as f32, + y: v.y as f32, + z: v.z as f32, + } + } +} + +impl From for IVec3 { + fn from(v: Vec3) -> IVec3 { + IVec3 { + x: v.x as i64, + y: v.y as i64, + z: v.z as i64, + } + } +} + // ################################################## // # VECTOR 4D # // ################################################## @@ -2568,6 +3006,15 @@ impl Add for Vec4 { } } +impl AddAssign for Vec4 { + fn add_assign(&mut self, other: Vec4) { + self.x += other.x; + self.y += other.y; + self.z += other.z; + self.w += other.w; + } +} + impl Sub for Vec4 { type Output = Vec4; @@ -2581,6 +3028,15 @@ impl Sub for Vec4 { } } +impl SubAssign for Vec4 { + fn sub_assign(&mut self, other: Vec4) { + self.x -= other.x; + self.y -= other.y; + self.z -= other.z; + self.w -= other.w; + } +} + impl Mul for Vec4 { type Output = Vec4; @@ -2594,6 +3050,12 @@ impl Mul for Vec4 { } } +impl Into<[f32;4]> for Vec4 { + fn into(self) -> [f32;4] { + [self.x, self.y, self.z, self.w] + } +} + impl InnerSpace for Vec2 { fn dot(&self, other: &Self) -> f32 { self.x * other.x + self.y * other.y @@ -2607,7 +3069,8 @@ impl InnerSpace for Vec2 { .length() } - fn vAngle(&self, other: &Self) -> f32 { + fn v_angle(&self, other: &Self) -> f32 { + //debug!("{:?}", dot(self,other)/(self.length()*other.length())); acos(dot(self, other) / (self.length() * other.length())) } } @@ -2626,7 +3089,7 @@ impl InnerSpace for Vec3 { .length() } - fn vAngle(&self, other: &Self) -> f32 { + fn v_angle(&self, other: &Self) -> f32 { acos(dot(self, other) / (self.length() * other.length())) } } @@ -2646,7 +3109,7 @@ impl InnerSpace for Vec4 { .length() } - fn vAngle(&self, other: &Self) -> f32 { + fn v_angle(&self, other: &Self) -> f32 { acos(dot(self, other) / (self.length() * other.length())) } } @@ -2672,5 +3135,5 @@ pub fn v_dist(v1: &T, v2: &T) -> f32 { } pub fn v_angle(v1: &T, v2: &T) -> f32 { - v1.vAngle(v2) + v1.v_angle(v2) } diff --git a/crates/comet_renderer/Cargo.toml b/crates/comet_renderer/Cargo.toml index dbefacd..fc79ec2 100644 --- a/crates/comet_renderer/Cargo.toml +++ b/crates/comet_renderer/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "comet_renderer" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] +comet_ecs = { path = "../comet_ecs" } comet_math = { path = "../comet_math" } comet_resources = { path = "../comet_resources" } comet_colors = { path = "../comet_colors" } diff --git a/crates/comet_renderer/src/camera.rs b/crates/comet_renderer/src/camera.rs index c5109a9..9e2a811 100644 --- a/crates/comet_renderer/src/camera.rs +++ b/crates/comet_renderer/src/camera.rs @@ -1,4 +1,4 @@ -use comet_math::Point3; +use comet_math::{Point3, Vec2, Vec3}; #[rustfmt::skip] pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( @@ -11,44 +11,30 @@ pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( const SAFE_FRAC_PI_2: f32 = std::f32::consts::FRAC_PI_2 - 0.0001; pub struct Camera { - eye: cgmath::Point3, - target: cgmath::Point3, - up: cgmath::Vector3, - aspect: f32, - fovy: f32, - znear: f32, - zfar: f32, + zoom: f32, + dimension: Vec2, + position: Vec3 } impl Camera { pub fn new( - eye: cgmath::Point3, - target: cgmath::Point3, - up: cgmath::Vector3, - aspect: f32, - fovy: f32, - znear: f32, - zfar: f32, + zoom: f32, + dimension: Vec2, + position: Vec3 ) -> Self { Self { - eye, - target, - up, - aspect, - fovy, - znear, - zfar, + zoom, + dimension, + position } } pub fn build_view_projection_matrix(&self) -> cgmath::Matrix4 { // 1. - let view = cgmath::Matrix4::look_at_rh(self.eye, self.target, self.up); - // 2. - let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar); + let proj = cgmath::ortho(self.position.x() - self.dimension.x() / 2.0, self.position.x() + self.dimension.x() / 2.0, self.position.y() - self.dimension.y() / 2.0, self.position.y() + self.dimension.y() / 2.0, 1.0, 0.0); // 3. - return OPENGL_TO_WGPU_MATRIX * proj * view; + return OPENGL_TO_WGPU_MATRIX * proj; } } diff --git a/crates/comet_renderer/src/lib.rs b/crates/comet_renderer/src/lib.rs index d7a4df1..ffba0bc 100644 --- a/crates/comet_renderer/src/lib.rs +++ b/crates/comet_renderer/src/lib.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use std::time::Instant; use cgmath::num_traits::FloatConst; use image::GenericImageView; -use log::info; use wgpu::Color; use wgpu::util::DeviceExt; use winit::{ @@ -16,9 +15,10 @@ use winit::{ }; use winit::dpi::Position; use comet_colors::LinearRgba; -use comet_log::error; +use comet_ecs::{Component, ComponentSet, Render, Renderer2D, Transform2D, World}; +use comet_log::*; use comet_math; -use comet_math::{Mat4, Point3, Vec3}; +use comet_math::{Mat4, Point3, Vec2, Vec3}; use comet_resources::{ResourceManager, texture, Vertex, Texture}; use comet_resources::texture_atlas::TextureRegion; use crate::camera::{Camera, CameraUniform}; @@ -67,10 +67,10 @@ pub struct Renderer<'a> { diffuse_texture: texture::Texture, diffuse_bind_group: wgpu::BindGroup, resource_manager: ResourceManager, - /*camera: Camera, + camera: Camera, camera_uniform: CameraUniform, camera_buffer: wgpu::Buffer, - camera_bind_group: wgpu::BindGroup,*/ + camera_bind_group: wgpu::BindGroup, } impl<'a> Renderer<'a> { @@ -199,64 +199,47 @@ impl<'a> Renderer<'a> { label: Some("diffuse_bind_group"), }); - /*let camera = Camera::new( - // position the camera 1 unit up and 2 units back - // +z is out of the screen - (0.0, 1.0, 2.0).into(), - // have it look at the origin - (0.0, 0.0, 0.0).into(), - // which way is "up" - cgmath::Vector3::unit_y(), - config.width as f32 / config.height as f32, - 45.0, - 0.1, - 100.0, - ); + let camera = Camera::new(1.0, Vec2::new(2.0, 2.0), Vec3::new(0.0, 0.0, 0.0)); - let mut camera_uniform = CameraUniform::new(); - camera_uniform.update_view_proj(&camera); + let mut camera_uniform = CameraUniform::new(); + camera_uniform.update_view_proj(&camera); - let camera_buffer = device.create_buffer_init( - &wgpu::util::BufferInitDescriptor { - label: Some("Camera Buffer"), - contents: bytemuck::cast_slice(&[camera_uniform]), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - } - ); + let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Camera Buffer"), + contents: bytemuck::cast_slice(&[camera_uniform]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); - let camera_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - } - ], - label: Some("camera_bind_group_layout"), - }); + let camera_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: Some("camera_bind_group_layout"), + }); - let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &camera_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: camera_buffer.as_entire_binding(), - } - ], - label: Some("camera_bind_group"), - });*/ + let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &camera_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: camera_buffer.as_entire_binding(), + }], + label: Some("camera_bind_group"), + }); let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Render Pipeline Layout"), bind_group_layouts: &[ &texture_bind_group_layout, - //&camera_bind_group_layout, + &camera_bind_group_layout, ], push_constant_ranges: &[], }); @@ -347,10 +330,10 @@ impl<'a> Renderer<'a> { diffuse_texture, diffuse_bind_group, resource_manager, - /*camera, + camera, camera_uniform, camera_buffer, - camera_bind_group,*/ + camera_bind_group, }) } @@ -380,10 +363,10 @@ impl<'a> Renderer<'a> { ((width/ self.config.width as f32) * 0.5, (height/ self.config.height as f32) * 0.5); vec![ - Vertex :: new ( [-bound_x, bound_y, 0.0], [0.0, 0.0] ), - Vertex :: new ( [-bound_x, -bound_y, 0.0], [0.0, 1.0] ), - Vertex :: new ( [ bound_x, -bound_y, 0.0], [1.0, 1.0]) , - Vertex :: new ( [ bound_x, bound_y, 0.0], [1.0, 0.0] ) + Vertex :: new ( [-bound_x, bound_y, 0.0], [0.0, 0.0], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [-bound_x, -bound_y, 0.0], [0.0, 1.0], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [ bound_x, -bound_y, 0.0], [1.0, 1.0], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [ bound_x, bound_y, 0.0], [1.0, 0.0], [0.0, 0.0, 0.0, 0.0] ) ] } @@ -401,10 +384,10 @@ impl<'a> Renderer<'a> { ((self.diffuse_texture.size.width as f32/ self.config.width as f32) * 0.5, (self.diffuse_texture.size.height as f32/ self.config.height as f32) * 0.5); let vertices: Vec = vec![ - Vertex :: new ( [-bound_x, bound_y, 0.0], [0.0, 0.0] ), - Vertex :: new ( [-bound_x, -bound_y, 0.0], [0.0, 1.0] ), - Vertex :: new ( [ bound_x, -bound_y, 0.0], [1.0, 1.0]) , - Vertex :: new ( [ bound_x, bound_y, 0.0], [1.0, 0.0] ) + Vertex :: new ( [-bound_x, bound_y, 0.0], [0.0, 0.0], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [-bound_x, -bound_y, 0.0], [0.0, 1.0], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [ bound_x, -bound_y, 0.0], [1.0, 1.0], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [ bound_x, bound_y, 0.0], [1.0, 0.0], [0.0, 0.0, 0.0, 0.0] ) ]; /*let vertices: Vec = vec![ @@ -494,8 +477,6 @@ impl<'a> Renderer<'a> { paths.push(texture_path.clone() + path.unwrap().file_name().to_str().unwrap()); } - error!(format!("{:?}", paths)); - self.set_texture_atlas(paths); } @@ -572,10 +553,10 @@ impl<'a> Renderer<'a> { ((dim_x as f32/ self.config.width as f32) * 0.5, (dim_y as f32/ self.config.height as f32) * 0.5); let vertices: &mut Vec = &mut vec![ - Vertex :: new ( [-bound_x + position.x(), bound_y + position.y(), 0.0 + position.z()], [region.x0(), region.y0()] ), - Vertex :: new ( [-bound_x + position.x(), -bound_y + position.y(), 0.0 + position.z()], [region.x0(), region.y1()] ), - Vertex :: new ( [ bound_x + position.x(), -bound_y + position.y(), 0.0 + position.z()], [region.x1(), region.y1()] ) , - Vertex :: new ( [ bound_x + position.x(), bound_y + position.y(), 0.0 + position.z()], [region.x1(), region.y0()] ) + Vertex :: new ( [-bound_x + position.x(), bound_y + position.y(), 0.0 + position.z()], [region.x0(), region.y0()], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [-bound_x + position.x(), -bound_y + position.y(), 0.0 + position.z()], [region.x0(), region.y1()], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [ bound_x + position.x(), -bound_y + position.y(), 0.0 + position.z()], [region.x1(), region.y1()], [0.0, 0.0, 0.0, 0.0] ) , + Vertex :: new ( [ bound_x + position.x(), bound_y + position.y(), 0.0 + position.z()], [region.x1(), region.y0()], [0.0, 0.0, 0.0, 0.0] ) ]; let buffer_size = self.vertex_data.len() as u16; @@ -588,6 +569,45 @@ impl<'a> Renderer<'a> { self.push_to_buffers(vertices, indices) } + pub fn render_scene_2d(&mut self, world: &World) { + let entities = world.get_entities_with(ComponentSet::from_ids(vec![Renderer2D::type_id()])); + let mut vertex_buffer: Vec = Vec::new(); + let mut index_buffer: Vec = Vec::new(); + + for entity in entities { + let renderer_component = world.get_component::(entity as usize); + let transform_component = world.get_component::(entity as usize); + + if renderer_component.is_visible() { + //renderer.draw_texture_at(renderer_component.get_texture(), Point3::new(transform_component.position().x(), transform_component.position().y(), 0.0)); + let mut position = transform_component.position().clone(); + position.set_x(position.x() / self.config().width as f32); + position.set_y(position.y() / self.config().height as f32); + let region = self.get_texture(renderer_component.get_texture().to_string()); + let (dim_x, dim_y) = region.dimensions(); + + let (bound_x, bound_y) = + ((dim_x as f32/ self.config().width as f32) * 0.5, (dim_y as f32/ self.config().height as f32) * 0.5); + + let buffer_size = vertex_buffer.len() as u16; + + vertex_buffer.append(&mut vec![ + Vertex :: new ( [-bound_x + position.x(), bound_y + position.y(), 0.0], [region.x0(), region.y0()], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [-bound_x + position.x(), -bound_y + position.y(), 0.0], [region.x0(), region.y1()], [0.0, 0.0, 0.0, 0.0] ), + Vertex :: new ( [ bound_x + position.x(), -bound_y + position.y(), 0.0], [region.x1(), region.y1()], [0.0, 0.0, 0.0, 0.0] ) , + Vertex :: new ( [ bound_x + position.x(), bound_y + position.y(), 0.0], [region.x1(), region.y0()], [0.0, 0.0, 0.0, 0.0] ) + ]); + + index_buffer.append(&mut vec![ + 0 + buffer_size, 1 + buffer_size, 3 + buffer_size, + 1 + buffer_size, 2 + buffer_size, 3 + buffer_size + ]); + } + } + + self.set_buffers(vertex_buffer, index_buffer); + } + pub fn window(&self) -> &Window { &self.window } @@ -606,10 +626,11 @@ impl<'a> Renderer<'a> { } } - pub fn update(&mut self) { + pub fn update(&mut self) -> f32 { let now = Instant::now(); self.deltatime = now.duration_since(self.last_frame_time).as_secs_f32(); // Time delta in seconds self.last_frame_time = now; + self.deltatime } pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> { @@ -642,7 +663,7 @@ impl<'a> Renderer<'a> { render_pass.set_pipeline(&self.render_pipeline); render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]); - //render_pass.set_bind_group(1, &self.camera_bind_group, &[]); + render_pass.set_bind_group(1, &self.camera_bind_group, &[]); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); render_pass.draw_indexed(0..self.num_indices, 0, 0..1); diff --git a/crates/comet_renderer/src/shader.wgsl b/crates/comet_renderer/src/shader.wgsl index 6c5b01c..bfe9789 100644 --- a/crates/comet_renderer/src/shader.wgsl +++ b/crates/comet_renderer/src/shader.wgsl @@ -1,18 +1,20 @@ // Vertex shader -/*struct CameraUniform { +struct CameraUniform { view_proj: mat4x4, }; @group(1) @binding(0) // 1. -var camera: CameraUniform;*/ +var camera: CameraUniform; struct VertexInput { @location(0) position: vec3, @location(1) tex_coords: vec2, + @location(2) color: vec4, } struct VertexOutput { @builtin(position) clip_position: vec4, @location(0) tex_coords: vec2, + @location(1) color: vec4, } @vertex @@ -21,7 +23,8 @@ fn vs_main( ) -> VertexOutput { var out: VertexOutput; out.tex_coords = model.tex_coords; - out.clip_position = /*camera.view_proj **/ vec4(model.position, 1.0); + out.color = model.color; + out.clip_position = camera.view_proj * vec4(model.position, 1.0); return out; } diff --git a/crates/comet_resources/src/texture_atlas.rs b/crates/comet_resources/src/texture_atlas.rs index 4e779f6..75773aa 100644 --- a/crates/comet_resources/src/texture_atlas.rs +++ b/crates/comet_resources/src/texture_atlas.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::path::Path; -use chrono::Local; use std::time::Instant; use image::{DynamicImage, GenericImage, GenericImageView, ImageFormat}; use comet_log::*; @@ -165,7 +164,7 @@ impl TextureAtlas { //base.save_with_format(output_path, ImageFormat::Png).expect("Failed to save texture atlas"); info!("Texture atlas created!"); - debug!(format!("{:?}", regions)); + //debug!(format!("{:?}", regions)); /*let t1 = Instant::now(); let delta = t1.duration_since(t0); diff --git a/crates/comet_resources/src/vertex.rs b/crates/comet_resources/src/vertex.rs index 71573f7..6436a75 100644 --- a/crates/comet_resources/src/vertex.rs +++ b/crates/comet_resources/src/vertex.rs @@ -5,13 +5,15 @@ use wgpu::Color; pub struct Vertex { position: [f32; 3], tex_coords: [f32; 2], + color: [f32; 4] } impl Vertex { - pub fn new(position: [f32; 3], tex_coords: [f32; 2]) -> Self { + pub fn new(position: [f32; 3], tex_coords: [f32; 2], color: [f32; 4]) -> Self { Self { position, - tex_coords + tex_coords, + color } } @@ -23,6 +25,10 @@ impl Vertex { self.tex_coords = new_tex_coords } + pub fn set_color(&mut self, new_color: [f32; 4]) { + self.color = new_color + } + pub fn desc() -> wgpu::VertexBufferLayout<'static> { wgpu::VertexBufferLayout { array_stride: std::mem::size_of::() as wgpu::BufferAddress, @@ -37,6 +43,11 @@ impl Vertex { offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, shader_location: 1, format: wgpu::VertexFormat::Float32x2, + }, + wgpu::VertexAttribute { + offset: std::mem::size_of::<[f32; 5]>() as wgpu::BufferAddress, + shader_location: 2, + format: wgpu::VertexFormat::Float32x4, } ] } diff --git a/src/lib.rs b/src/lib.rs index f4d879c..dc25d3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,4 +6,8 @@ pub use comet_ecs as ecs; pub use comet_app as app; pub use comet_colors as colors; pub use comet_input as input; -pub use comet_log as log; \ No newline at end of file +pub use comet_log as log; + +pub mod prelude { + pub use comet_app::App; +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 77461b4..dd52d95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,64 +4,89 @@ use comet::{ ApplicationType::* }, renderer::Renderer, - ecs::World, + ecs::*, math::*, input::keyboard::*, log::* }; -use winit::event::{WindowEvent}; -use comet_ecs::{Component, ComponentSet, Render, Renderer2D, Transform2D}; -use comet_input::mouse::{mouse_entered, mouse_pressed, Button}; -fn input(event: &WindowEvent, app: &mut App, renderer: &mut Renderer) { - match event { - _ if key_pressed(event, Key::Escape) => app.quit(), - _ if key_pressed(event, Key::KeyC) => { renderer.clear_buffers() } - _ if key_pressed(event, Key::KeyE) => { - let mut renderer2d = Renderer2D::new(); - renderer2d.set_texture(r"resources/textures/comet_icon.png"); - renderer2d.set_visibility(true); +use winit_input_helper::WinitInputHelper; +use comet_input::input_handler::InputHandler; - let id = app.world_mut().new_entity(); - app.world_mut().add_component(id as usize, renderer2d.clone()); - app.world_mut().add_component(0, renderer2d); +fn update_position(input: WinitInputHelper, transform: &mut Transform2D, dt: f32) { + let mut direction = Vec2::ZERO; + let previous = transform.position().clone(); - let transform = app.world_mut().get_component_mut::(id as usize); - transform.position_mut().set_x(0.5); + if input.key_held(Key::KeyW) { + direction += Vec2::Y; + } + if input.key_held(Key::KeyA) { + direction -= Vec2::X; + } + if input.key_held(Key::KeyS) { + direction -= Vec2::Y; + } + if input.key_held(Key::KeyD) { + direction += Vec2::X; + } - debug!(format!("{:?}", app.world().components().get_component::(0))); - }, - _ if key_pressed(event, Key::KeyW) => { - let transform = app.world_mut().get_component_mut::(0); - let y = transform.position().y(); - transform.position_mut().set_y(y + 0.1); - }, - _ if key_pressed(event, Key::KeyA) => { - let transform = app.world_mut().get_component_mut::(0); - let x = transform.position().x(); - transform.position_mut().set_x(x - 0.1); - }, - _ if key_pressed(event, Key::KeyS) => { - let transform = app.world_mut().get_component_mut::(0); - let y = transform.position().y(); - transform.position_mut().set_y(y - 0.1); - }, - _ if key_pressed(event, Key::KeyD) => { - let transform = app.world_mut().get_component_mut::(0); - let x = transform.position().x(); - transform.position_mut().set_x(x + 0.1); + if direction != Vec2::ZERO { + let normalized_dir = direction.normalize(); + if normalized_dir.x().is_nan() || normalized_dir.y().is_nan() { + error!("Direction is NaN! X: {}, Y: {}", normalized_dir.x(), normalized_dir.y()); } - _ => {} + let displacement = normalized_dir * 777.7 * dt; + transform.translate(displacement); + } + + if (transform.position().as_vec() - previous.as_vec()).x() > 13.0 { + debug!("Actual Displacement: {:?}", transform.position().as_vec() - previous.as_vec()); } } -fn update(world: &mut World, renderer: &mut Renderer) { - if !world.components().contains_components(ComponentSet::from_ids(vec![Transform2D::type_id(), Renderer2D::type_id()])) { - world.register_component::(); - } - if world.entities().len() == 0 { - let id = world.new_entity(); +fn setup(world: &mut World) { + world.register_component::(); + //world.register_component::(); + + let mut renderer2d = Renderer2D::new(); + renderer2d.set_texture(r"resources/textures/comet_icon.png"); + renderer2d.set_visibility(true); + + let id = world.new_entity(); + world.add_component(id as usize, renderer2d.clone()); + + let transform = world.get_component_mut::(id as usize); + transform.translate(Vec2::X*5.0); + + world.add_component(id as usize, renderer2d); + + /*let rectangle2d = Rectangle2D::new(*tranform.position(), Vec2::new(0.1, 0.1)); + world.add_component(id as usize, rectangle2d); + + let id2 = world.new_entity(); + let tranform2 = world.get_component_mut::(id as usize); + let rectangle = Rectangle2D::new(*tranform2.position(), Vec2::new(0.1, 0.1)); + + world.add_component(id2 as usize, rectangle);*/ + +} + +fn update(app: &mut App, renderer: &mut Renderer, dt: f32) { + if app.key_pressed(Key::Escape) { app.quit() } + if app.key_pressed(Key::KeyC) { app.set_time_step(0.0016667) } + if app.key_pressed(Key::KeyV) { app.set_time_step(0.0166667) } + if app.key_pressed(Key::KeyE) { app.world_mut().get_component_mut::(0).translate([0f32,0f32].into()) } + if app.key_held(Key::KeyW) + || app.key_held(Key::KeyA) + || app.key_held(Key::KeyS) + || app.key_held(Key::KeyD) + { + update_position(app.input_manager().clone(), app.world_mut().get_component_mut::(0), dt); } + + let mut transform = app.world_mut().get_component_mut::(0); + + } fn main() { @@ -69,6 +94,7 @@ fn main() { .with_title("Comet App") .with_icon(r"resources/textures/comet_icon.png") .with_size(1920, 1080) - .run(input, update) + .with_setup(setup) + .run(update) ; } \ No newline at end of file