From 189805dd136ef819fc3b37f70a009606e36d9a3e Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Fri, 12 Feb 2021 00:27:11 -0800 Subject: [PATCH] lots of skeleton stuff. lots of hacking. mostly hacking --- Cargo.toml | 3 +- src/camera.rs | 173 ++++++++++++++++++++++++++++++++++++ src/components.rs | 64 ++++++++++++++ src/light.rs | 3 +- src/main.rs | 193 ++++++++++++++++++++++------------------ src/owned_event.rs | 213 +++++++++++++++++++++++++++++++++++++++++++++ src/physics.rs | 18 +++- src/render.rs | 175 ++++++++++++++++++++++--------------- 8 files changed, 687 insertions(+), 155 deletions(-) create mode 100644 src/camera.rs create mode 100644 src/components.rs create mode 100644 src/owned_event.rs diff --git a/Cargo.toml b/Cargo.toml index f27e9b0..f0371b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,4 +29,5 @@ wgpu-subscriber = "0.1.0" tobj = "2.0.3" legion = "0.3.1" nalgebra = "0.24.1" -rapier3d = { version = "0.5.0", features = [ "simd-nightly", "parallel" ] } \ No newline at end of file +rapier3d = { version = "0.5.0", features = [ "simd-nightly", "parallel" ] } +gilrs = "0.8.0" \ No newline at end of file diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..34d0747 --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,173 @@ +use cgmath::{Matrix4, Vector3, Point3, Rad, InnerSpace}; +use winit::event::{MouseScrollDelta, VirtualKeyCode, ElementState}; +use winit::dpi::{PhysicalPosition, LogicalPosition}; +use std::time::{Duration, Instant}; +use std::f32::consts::FRAC_PI_2; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Camera { + pub position: Point3, + pub yaw: Rad, + pub pitch: Rad, +} + +impl Camera { + pub fn new< + V: Into>, + Y: Into>, + P: Into>, + >( + position: V, + yaw: Y, + pitch: P, + ) -> Self { + Self { + position: position.into(), + yaw: yaw.into(), + pitch: pitch.into(), + } + } + + pub fn calc_matrix(&self) -> Matrix4 { + Matrix4::look_at_dir( + self.position, + Vector3::new( + self.yaw.0.cos(), + self.pitch.0.sin(), + self.yaw.0.sin(), + ).normalize(), + Vector3::unit_y(), + ) + } +} + + +#[derive(Debug)] +pub struct CameraController { + amount_left: f32, + amount_right: f32, + amount_forward: f32, + amount_backward: f32, + amount_up: f32, + amount_down: f32, + rotate_horizontal: f32, + rotate_vertical: f32, + scroll: f32, + speed: f32, + sensitivity: f32, + last_frame: Instant, +} + +impl CameraController { + pub fn new(speed: f32, sensitivity: f32) -> Self { + Self { + amount_left: 0.0, + amount_right: 0.0, + amount_forward: 0.0, + amount_backward: 0.0, + amount_up: 0.0, + amount_down: 0.0, + rotate_horizontal: 0.0, + rotate_vertical: 0.0, + scroll: 0.0, + speed, + sensitivity, + last_frame: Instant::now(), + } + } + + pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool{ + let amount = if state == ElementState::Pressed { 1.0 } else { 0.0 }; + match key { + VirtualKeyCode::W | VirtualKeyCode::Up => { + self.amount_forward = amount; + true + } + VirtualKeyCode::S | VirtualKeyCode::Down => { + self.amount_backward = amount; + true + } + VirtualKeyCode::A | VirtualKeyCode::Left => { + self.amount_left = amount; + true + } + VirtualKeyCode::D | VirtualKeyCode::Right => { + self.amount_right = amount; + true + } + VirtualKeyCode::Space => { + self.amount_up = amount; + true + } + VirtualKeyCode::LShift => { + self.amount_down = amount; + true + } + _ => false, + } + } + + pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { + self.rotate_horizontal = mouse_dx as f32; + self.rotate_vertical = mouse_dy as f32; + } + + pub fn process_scroll(&mut self, delta: &MouseScrollDelta) { + self.scroll = -match delta { + // I'm assuming a line is about 100 pixels + MouseScrollDelta::LineDelta(_, scroll) => scroll * 100.0, + MouseScrollDelta::PixelDelta(LogicalPosition { + y: scroll, + .. + }) => *scroll as f32, + }; + } + + pub fn update_camera(&mut self, camera: &mut Camera, dt: Duration) { + + + let dt = dt.as_secs_f32(); + + // Move forward/backward and left/right + let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); + let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); + let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); + camera.position += forward * (self.amount_forward - self.amount_backward) * self.speed * dt; + camera.position += right * (self.amount_right - self.amount_left) * self.speed * dt; + + // Move in/out (aka. "zoom") + // Note: this isn't an actual zoom. The camera's position + // changes when zooming. I've added this to make it easier + // to get closer to an object you want to focus on. + let (pitch_sin, pitch_cos) = camera.pitch.0.sin_cos(); + let scrollward = Vector3::new(pitch_cos * yaw_cos, pitch_sin, pitch_cos * yaw_sin).normalize(); + camera.position += scrollward * self.scroll * self.speed * self.sensitivity * dt; + self.scroll = 0.0; + + // Move up/down. Since we don't use roll, we can just + // modify the y coordinate directly. + camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; + + // Rotate + camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; + camera.pitch += Rad(-self.rotate_vertical) * self.sensitivity * dt; + + // If process_mouse isn't called every frame, these values + // will not get set to zero, and the camera will rotate + // when moving in a non cardinal direction. + self.rotate_horizontal = 0.0; + self.rotate_vertical = 0.0; + + // Keep the camera's angle from going too high/low. + if camera.pitch < -Rad(FRAC_PI_2) { + camera.pitch = -Rad(FRAC_PI_2); + } else if camera.pitch > Rad(FRAC_PI_2) { + camera.pitch = Rad(FRAC_PI_2); + } + } +} + + + + + diff --git a/src/components.rs b/src/components.rs new file mode 100644 index 0000000..89b5b9b --- /dev/null +++ b/src/components.rs @@ -0,0 +1,64 @@ +use wgpu::{TextureView, Buffer, BindGroup}; +use std::sync::Arc; +use rapier3d::dynamics::{RigidBody, RigidBodyHandle}; +use rapier3d::geometry::ColliderHandle; +use rapier3d::geometry::Collider as r3dCollider; + +// a component is any type that is 'static, sized, send and sync +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Position { + pub x: f32, + pub y: f32, + pub z: f32, + pub rot: cgmath::Quaternion, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Color { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Velocity { + pub dx: f32, + pub dy: f32, + pub rs: f32, +} + +#[derive(Clone, Default, PartialEq, Eq, Hash, Copy, Debug)] +pub struct RangeCopy { + pub start: Idx, + pub end: Idx, +} + +#[derive(Clone, Debug)] +pub struct DirectionalLight { + pub color: wgpu::Color, + pub fov: f32, + pub depth: RangeCopy, + pub target_view: Arc, +} + +#[derive(Clone, Debug)] +pub struct Mesh { + pub index_buffer: Arc, + pub index_count: usize, + pub vertex_buffer: Arc, + pub uniform_buffer: Arc, + pub bind_group: Arc, +} + +#[derive(Clone, Debug)] +pub struct Physics { + pub rigid_body: RigidBody, + pub rigid_body_handle: Option, +} + +#[derive(Clone)] +pub struct Collider { + pub collider: r3dCollider, + pub collider_handle: Option, +} \ No newline at end of file diff --git a/src/light.rs b/src/light.rs index f3b1b52..71d3105 100644 --- a/src/light.rs +++ b/src/light.rs @@ -1,7 +1,8 @@ use bytemuck::__core::ops::Range; use bytemuck::{Zeroable, Pod}; -use crate::{OPENGL_TO_WGPU_MATRIX, DirectionalLight, Position}; use cgmath::Point3; +use crate::render::OPENGL_TO_WGPU_MATRIX; +use crate::components::DirectionalLight; #[repr(C)] diff --git a/src/main.rs b/src/main.rs index 20cd88e..dab36ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,12 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use bytemuck::__core::ops::Range; -use cgmath::{Decomposed, Deg, Euler, InnerSpace, Quaternion, Rotation3, SquareMatrix}; +use cgmath::{Decomposed, Deg, Euler, InnerSpace, Quaternion, Rotation3, SquareMatrix, Point3, Rad}; use futures::task::LocalSpawn; use legion::*; use rapier3d::dynamics::{ IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, }; -use rapier3d::geometry::Collider as r3dCollider; use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderHandle, ColliderSet, NarrowPhase}; use rapier3d::math; use rapier3d::na::{Isometry, Isometry3, Vector, Vector3}; @@ -28,13 +27,23 @@ use winit::{ event_loop::{ControlFlow, EventLoop}, }; +use gilrs::Event as GilEvent; + +use crate::camera::{CameraController, Camera}; +use crate::components::{Collider, Color, Physics, Position}; use crate::physics::PhysicsState; use crate::render::Renderer; +use crate::owned_event::TrEventExtension; +use gilrs::{Gamepad, Gilrs}; +use rapier3d::counters::Timer; +mod camera; +mod components; mod geometry; mod light; mod physics; mod render; +mod owned_event; /* @@ -58,81 +67,13 @@ mvp: ECS animation - render 3d + render 3d (good!) input/io - collision / physics - entities & behaviours + collision / physics (yep!) + entities & behaviours (got the entities!) */ -#[cfg_attr(rustfmt, rustfmt_skip)] -#[allow(unused)] -pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.0, 0.0, 0.5, 1.0, -); - -// a component is any type that is 'static, sized, send and sync -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Position { - x: f32, - y: f32, - z: f32, - rot: cgmath::Quaternion, - //mx: cgmath::Matrix4, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Color { - r: f32, - g: f32, - b: f32, - a: f32, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Velocity { - dx: f32, - dy: f32, - rs: f32, -} - -#[derive(Clone, Default, PartialEq, Eq, Hash, Copy, Debug)] -pub struct RangeCopy { - pub start: Idx, - pub end: Idx, -} - -#[derive(Clone, Debug)] -pub struct DirectionalLight { - color: wgpu::Color, - fov: f32, - depth: RangeCopy, - target_view: Arc, -} - -#[derive(Clone, Debug)] -pub struct Mesh { - index_buffer: Arc, - index_count: usize, - vertex_buffer: Arc, - uniform_buffer: Arc, - bind_group: Arc, -} - -#[derive(Clone, Debug)] -pub struct Physics { - rigid_body: RigidBody, - rigid_body_handle: Option, -} - -#[derive(Clone)] -pub struct Collider { - collider: r3dCollider, - collider_handle: Option, -} //log::info!(""); fn main() { @@ -151,12 +92,13 @@ fn main() { // TODO schedule for the update system and others let mut update_schedule = Schedule::builder() + .add_system(physics::update_camera_system()) .add_system(physics::run_physics_system()) .add_system(physics::update_models_system()) // next system here, gamelogic update system? .build(); - let event_loop = EventLoop::new(); + let event_loop = EventLoop::::with_user_event(); let mut builder = winit::window::WindowBuilder::new(); builder = builder.with_title("MVGE"); @@ -169,8 +111,6 @@ fn main() { let window = builder.build(&event_loop).unwrap(); - let mut last_update_inst = Instant::now(); - // Load up the renderer (and the resources) let mut renderer = { let mut renderer = render::Renderer::init(&window); @@ -186,20 +126,94 @@ fn main() { resources.insert(physics_state); resources.insert(physics_pipeline); + resources.insert(CameraController::new(1.0, 1.0)); + resources.insert(Instant::now()); + + + let event_loop_proxy = event_loop.create_proxy(); + + std::thread::spawn(move || { + let mut gilrs = Gilrs::new().unwrap(); + // Iterate over all connected gamepads + let mut gamepad: Option = None; + for (_id, gamepad_) in gilrs.gamepads() { + if gamepad_.name() == "PS4" { + gamepad = Some(gamepad_); + } + println!("{} is {:?} {:?}", gamepad_.name(), gamepad_.power_info(), gamepad_.id()); + } + let mut active_gamepad = None; + + loop { + while let Some(GilEvent { id, event, time }) = gilrs.next_event() { + println!("{:?} New event from {}: {:?}", time, id, event); + active_gamepad = Some(id); + event_loop_proxy.send_event(TrEventExtension::GamepadEvent { + gil_event: GilEvent { id, event, time } + }).ok(); + } + + // // You can also use cached gamepad state + // if let Some(gamepad) = active_gamepad.map(|id| gilrs.gamepad(id)) { + // if gamepad.is_pressed(Button::South) { + // println!("Button South is pressed (XBox - A, PS - X)"); + // } + // } + + std::thread::sleep(std::time::Duration::from_millis(50)); + } + }); + + + + let step_size: f32 = 0.005; + let mut elapsed_time: f32 = { // deltatime since last frame + let last_frame = resources.get::().unwrap(); + last_frame.elapsed() + }.as_secs_f32(); + + let mut delta_time: f32 = 0.0; + let mut accumulator_time: f32 = 0.0; + let mut current_time: f32 = elapsed_time; + + event_loop.run(move |event, _, control_flow| { // Artificially slows the loop rate to 10 millis // This is called after redraw events cleared - *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::from_millis(10)); + //*control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::from_millis(10)); + *control_flow = ControlFlow::Poll; match event { event::Event::MainEventsCleared => { - // ask for a redraw every 20 millis - if last_update_inst.elapsed() > Duration::from_millis(20) { - window.request_redraw(); - last_update_inst = Instant::now(); + + elapsed_time = { // deltatime since last frame + let last_frame = resources.get::().unwrap(); + last_frame.elapsed() + }.as_secs_f32(); + delta_time = elapsed_time - current_time; + current_time = elapsed_time; + if delta_time > 0.02 { + delta_time = 0.02; } + accumulator_time += delta_time; + + + let dt = { // deltatime since last frame + let last_frame = resources.get::().unwrap(); + last_frame.elapsed() + }; + update_schedule.execute(&mut world, &mut resources); - pool.run_until_stalled(); + + // ask for a redraw every 20 millis + if dt > Duration::from_millis(20) { + + } + + // update the world time here for next update + resources.insert(Instant::now()); + + render_schedule.execute(&mut world, &mut resources); } event::Event::DeviceEvent { event: MouseMotion { delta }, @@ -257,7 +271,20 @@ fn main() { pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { let monkey_mesh = renderer.load_mesh_to_buffer("./resources/monkey.obj"); - // This could be used for relationships between entities...??? + + + // let camera_ent: Entity = world.push(( + // Camera { + // position: Point3 { + // x: 5.0, + // y: 5.0, + // z: 5.0 + // }, + // yaw: Rad(45.0), + // pitch: Rad(45.0) + // } + // )); + let light_entity: Entity = world.push(( cgmath::Point3 { x: 7.0 as f32, diff --git a/src/owned_event.rs b/src/owned_event.rs new file mode 100644 index 0000000..b0ad4ad --- /dev/null +++ b/src/owned_event.rs @@ -0,0 +1,213 @@ +use winit::window::{WindowId, Theme}; +use winit::event::{WindowEvent, DeviceId, DeviceEvent, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, ElementState, MouseButton, AxisId, Touch, StartCause, Event}; +use winit::dpi::{PhysicalPosition, PhysicalSize}; +use gilrs::Event as GilEvent; +use std::path::PathBuf; + +#[derive(Clone)] +pub enum TrUIEvent { + UIEvent(T) +} + +#[derive(Clone)] +pub enum TrEventExtension { + + /// Custom events here + MouseHeldEvent {}, + KeyHeldEvent {}, + GamepadEvent { + gil_event: GilEvent, + }, +} + +#[derive(Clone, Debug)] +pub enum TrEvent { + + /// Custom events here + MouseHeldEvent {}, + KeyHeldEvent {}, + GamepadEvent { + gil_event: GilEvent, + }, + + /// Winit events here + NewEvents(StartCause), + WindowEvent { + window_id: WindowId, + event: TrWindowEvent, + }, + DeviceEvent { + device_id: DeviceId, + event: DeviceEvent, + }, + UserEvent(T), + Suspended, + Resumed, + MainEventsCleared, + RedrawRequested(WindowId), + RedrawEventsCleared, + LoopDestroyed, +} + + +impl From> for TrEvent { + fn from(event: Event) -> Self { + match event { + Event::NewEvents(cause) => { + TrEvent::NewEvents(cause) + }, + Event::WindowEvent { window_id: window_id, event: event } => { + TrEvent::WindowEvent { + window_id: window_id, + event: match event { + WindowEvent::AxisMotion { device_id, axis, value } => { + TrWindowEvent::AxisMotion { device_id, axis, value } + }, + WindowEvent::Resized(physical_size) => { + TrWindowEvent::Resized(physical_size) + } + WindowEvent::Moved(physical_position) => { + TrWindowEvent::Moved(physical_position) + } + WindowEvent::CloseRequested => { + TrWindowEvent::CloseRequested + } + WindowEvent::Destroyed => { + TrWindowEvent::Destroyed + } + WindowEvent::DroppedFile(path_buf) => { + TrWindowEvent::DroppedFile(path_buf) + } + WindowEvent::HoveredFile(path_buf) => { + TrWindowEvent::HoveredFile(path_buf) + } + WindowEvent::HoveredFileCancelled => { + TrWindowEvent::HoveredFileCancelled + } + WindowEvent::ReceivedCharacter(char) => { + TrWindowEvent::ReceivedCharacter(char) + } + WindowEvent::Focused(bool) => { + TrWindowEvent::Focused(bool) + } + WindowEvent::KeyboardInput { device_id: device_id, input: input, is_synthetic: is_synthetic } => { + TrWindowEvent::KeyboardInput { device_id, input, is_synthetic } + } + WindowEvent::ModifiersChanged(modifiers_state) => { + TrWindowEvent::ModifiersChanged(modifiers_state) + } + WindowEvent::CursorMoved { device_id: device_id, position: position, modifiers: modifiers } => { + TrWindowEvent::CursorMoved { device_id, position, modifiers } + } + WindowEvent::CursorEntered { device_id: device_id } => { + TrWindowEvent::CursorEntered { device_id } + } + WindowEvent::CursorLeft { device_id: device_id } => { + TrWindowEvent::CursorLeft { device_id } + } + WindowEvent::MouseWheel { device_id: device_id, delta: delta, phase: phase, modifiers: modifiers } => { + TrWindowEvent::MouseWheel { device_id, delta, phase, modifiers } + } + WindowEvent::MouseInput { device_id: device_id, state: state, button: button, modifiers: modifiers } => { + TrWindowEvent::MouseInput { device_id, state, button, modifiers } + } + WindowEvent::TouchpadPressure { device_id: device_id, pressure: pressure, stage: stage } => { + TrWindowEvent::TouchpadPressure { device_id, pressure, stage } + } + WindowEvent::Touch(touch) => { + TrWindowEvent::Touch(touch) + } + WindowEvent::ScaleFactorChanged { scale_factor: scale_factor, new_inner_size: new_inner_size } => { + TrWindowEvent::ScaleFactorChanged { scale_factor, new_inner_size: PhysicalSize { width: new_inner_size.width, height: new_inner_size.height } } + } + WindowEvent::ThemeChanged(theme) => { + TrWindowEvent::ThemeChanged(theme) + } + } + } + } + Event::DeviceEvent { device_id: device_id, event: event } => { + TrEvent::DeviceEvent { device_id, event } + } + Event::UserEvent(user_event) => { + TrEvent::UserEvent(user_event) + } + Event::Suspended => { + TrEvent::Suspended + } + Event::Resumed => { + TrEvent::Resumed + } + Event::MainEventsCleared => { + TrEvent::MainEventsCleared + } + Event::RedrawRequested(window_id) => { + TrEvent::RedrawRequested(window_id) + } + Event::RedrawEventsCleared => { + TrEvent::RedrawEventsCleared + } + Event::LoopDestroyed => { + TrEvent::LoopDestroyed + } + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum TrWindowEvent { + + Resized(PhysicalSize), + Moved(PhysicalPosition), + CloseRequested, + Destroyed, + DroppedFile(PathBuf), + HoveredFile(PathBuf), + HoveredFileCancelled, + ReceivedCharacter(char), + Focused(bool), + KeyboardInput { + device_id: DeviceId, + input: KeyboardInput, + is_synthetic: bool, + }, + ModifiersChanged(ModifiersState), + CursorMoved { + device_id: DeviceId, + position: PhysicalPosition, + #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] + modifiers: ModifiersState, + }, + CursorEntered { device_id: DeviceId }, + CursorLeft { device_id: DeviceId }, + MouseWheel { + device_id: DeviceId, + delta: MouseScrollDelta, + phase: TouchPhase, + #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] + modifiers: ModifiersState, + }, + MouseInput { + device_id: DeviceId, + state: ElementState, + button: MouseButton, + #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] + modifiers: ModifiersState, + }, + TouchpadPressure { + device_id: DeviceId, + pressure: f32, + stage: i64, + }, + AxisMotion { + device_id: DeviceId, + axis: AxisId, + value: f64, + }, + Touch(Touch), + ScaleFactorChanged { + scale_factor: f64, + new_inner_size: PhysicalSize, + }, + ThemeChanged(Theme), +} \ No newline at end of file diff --git a/src/physics.rs b/src/physics.rs index 8b85e3a..ec6e48b 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -6,8 +6,10 @@ use rapier3d::pipeline::PhysicsPipeline; use legion::*; use crate::render::{EntityUniforms, Renderer}; -use crate::{Collider, Mesh, RigidBody, Physics, Position}; use cgmath::Quaternion; +use crate::components::{Collider, Physics, Mesh, Position}; +use crate::camera::{CameraController, Camera}; +use std::time::Instant; pub struct PhysicsState { gravity: rapier3d::math::Vector, @@ -79,6 +81,20 @@ pub fn run_physics( ); } +#[system] +#[write_component(Camera)] +pub fn update_camera( + world: &mut SubWorld, + #[resource] camera_controller: &mut CameraController, + #[resource] last_frame: &mut Instant, +) { + let mut query = <(&mut Camera)>::query(); + for (camera) in query.iter_mut(world) { + //camera.update_camera() + } + +} + #[system] #[write_component(Collider)] #[write_component(Physics)] diff --git a/src/render.rs b/src/render.rs index 690c239..91c6918 100644 --- a/src/render.rs +++ b/src/render.rs @@ -3,10 +3,11 @@ use std::{iter, num::NonZeroU32, ops::Range, rc::Rc}; use bytemuck::__core::mem; use bytemuck::{Pod, Zeroable}; -use cgmath::{Point3, Matrix4, Transform, vec3, Vector3}; +use cgmath::{vec3, Decomposed, Deg, Euler, InnerSpace, Matrix4, Point3, Quaternion, Rotation3, Transform, Vector3, Rad}; use futures::executor::LocalPool; use legion::world::SubWorld; use legion::*; +use rapier3d::parry::motion::RigidMotionComposition; use wgpu::util::DeviceExt; use wgpu::{ BindGroup, BindGroupLayout, Buffer, Device, Instance, Queue, Surface, SwapChain, @@ -16,10 +17,19 @@ use winit::dpi::PhysicalSize; use winit::platform::unix::x11::ffi::Time; use winit::window::Window; +use crate::camera::{Camera, CameraController}; +use crate::components::{Color, DirectionalLight, Mesh, Position, RangeCopy}; use crate::geometry::{create_plane, import_mesh, vertex, Vertex}; use crate::light::LightRaw; -use crate::{Color, DirectionalLight, Mesh, Position, RangeCopy, Velocity, OPENGL_TO_WGPU_MATRIX}; -use rapier3d::parry::motion::RigidMotionComposition; + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[allow(unused)] +pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.0, 0.0, 0.5, 1.0, +); #[repr(C)] #[derive(Clone, Copy)] @@ -29,25 +39,30 @@ pub struct ForwardUniforms { } unsafe impl Pod for ForwardUniforms {} - unsafe impl Zeroable for ForwardUniforms {} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct EntityUniforms { model: [[f32; 4]; 4], color: [f32; 4], } unsafe impl Pod for EntityUniforms {} - unsafe impl Zeroable for EntityUniforms {} #[repr(C)] +#[derive(Clone, Copy, Debug)] pub struct ShadowUniforms { proj: [[f32; 4]; 4], } +unsafe impl Pod for ShadowUniforms {} +unsafe impl Zeroable for ShadowUniforms {} + +/// A render pass consists of a pipeline, bindgroup, and uniform buf +/// The uniform buf is just the ShadowUniforms or ForwardUniforms +/// And the bindgroup is just the localbindgroup (the EntityUniforms) and the rest pub struct Pass { pipeline: wgpu::RenderPipeline, bind_group: wgpu::BindGroup, @@ -55,7 +70,6 @@ pub struct Pass { } pub struct Renderer { - swapchain: SwapChain, swapchain_description: SwapChainDescriptor, instance: Arc, @@ -78,32 +92,6 @@ pub struct Renderer { light_uniform_buf: wgpu::Buffer, camera_projection: Matrix4, - -} - -impl Renderer { - const MAX_LIGHTS: usize = 10; - const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d { - width: 512, - height: 512, - depth: Self::MAX_LIGHTS as u32, - }; - const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - - pub(crate) fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4 { - // Specifies the aspect ratio that determines the field of view in the x direction. - // The aspect ratio is the ratio of x (width) to y (height). - let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 20.0); - let mx_view = cgmath::Matrix4::look_at( - cgmath::Point3::new(3.0f32, -9.0, 6.0), - cgmath::Point3::new(0f32, 0.0, 0.0), - cgmath::Vector3::unit_z(), - ); - - let mx_correction = OPENGL_TO_WGPU_MATRIX; - mx_correction * mx_projection * mx_view - } } #[system] @@ -112,7 +100,12 @@ impl Renderer { #[write_component(Mesh)] #[write_component(Color)] #[write_component(DirectionalLight)] -pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { +pub fn render_test( + world: &mut SubWorld, + #[resource] renderer: &mut Renderer, + #[resource] camera_controller: &mut CameraController, +) { + let mut encoder = renderer .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); @@ -167,7 +160,6 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); for (i, (light, pos)) in query.iter_mut(world).enumerate() { - encoder.insert_debug_marker(&format!("shadow pass {} (light at position {:?})", i, pos)); // The light uniform buffer already has the projection, @@ -197,14 +189,11 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]); for mesh in &mesh_stack { - pass.set_bind_group(1, &mesh.bind_group, &[]); pass.set_index_buffer(mesh.index_buffer.slice(..)); pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); - } - } encoder.pop_debug_group(); // forward pass @@ -252,6 +241,77 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { } impl Renderer { + const MAX_LIGHTS: usize = 10; + const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d { + width: 512, + height: 512, + depth: Self::MAX_LIGHTS as u32, + }; + const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + + pub fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4 { + // Specifies the aspect ratio that determines the field of view in the x direction. + // The aspect ratio is the ratio of x (width) to y (height). + let mx_projection = cgmath::perspective(cgmath::Deg(75f32), aspect_ratio, 1.0, 20.0); + let mx_view = cgmath::Matrix4::look_at( + cgmath::Point3::new(1.0f32, 1.0, 4.0), + cgmath::Point3::new(0.0f32, 0.0, 0.0), + cgmath::Vector3::unit_z(), + ); + + let mx_correction = OPENGL_TO_WGPU_MATRIX; + mx_correction * mx_projection * mx_view + } + + pub fn cam_look_delta(&mut self, delta: (f64, f64)) { + + // let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 20.0); + // let mx_view = cgmath::Matrix4::look_at( + // cgmath::Point3::new(3.0f32, -9.0, 6.0), + // cgmath::Point3::new(0f32, 0.0, 0.0), + // cgmath::Vector3::unit_z(), + // ); + // let mx_correction = OPENGL_TO_WGPU_MATRIX; + // let mx_total = mx_correction * mx_projection * mx_view; + // + // let rotation = Quaternion::from(Euler { + // x: Deg(90.0), + // y: Deg(45.0), + // z: Deg(15.0), + // }); + // + // Euler { + // x: (), + // y: (), + // z: () + // }; + // + // let offset = cgmath::vec3(1.0, 1.0, 4.0); + // let transform = Decomposed { + // disp: offset.clone(), + // rot: Quaternion::from_axis_angle(offset.normalize(), Deg(50.0)), + // scale: 1.0, + // }; + // + // let mut q = Quaternion::from(self.camera_direction); + // q.v.z += delta.0 as f32; + // q.v.y += delta.1 as f32; + // //let q2 = Quaternion::from_angle_x(Deg(delta.0 as f32)); + // //let q3 = Quaternion::from_angle_y(Deg(delta.1 as f32)); + // let w = Matrix4::from(q); + // //mx_total = mx_total + w; + // + // self.camera_projection = transform.into(); + // let mut mx_total = self.camera_projection.clone(); + // + // let mx_ref: &[f32; 16] = mx_total.as_ref(); + // self.queue.write_buffer( + // &self.forward_pass.uniform_buf, + // 0, + // bytemuck::cast_slice(mx_ref), + // ); + } pub fn get_current_frame(&mut self) -> SwapChainFrame { // Update the renderers swapchain state @@ -273,7 +333,6 @@ impl Renderer { indices: Vec, vertices: Vec, ) -> (Arc, Arc) { - let vertex_buf = Arc::new( device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("vertex-buffer"), @@ -294,7 +353,11 @@ impl Renderer { } pub fn create_light(&mut self) -> DirectionalLight { - let target = self.shadow_target_views.get(self.views_given as usize).take().unwrap(); + let target = self + .shadow_target_views + .get(self.views_given as usize) + .take() + .unwrap(); self.views_given = self.views_given + 1; DirectionalLight { color: wgpu::Color { @@ -640,7 +703,6 @@ impl Renderer { let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); - let forward_pass = { // Create pipeline layout let bind_group_layout = @@ -833,35 +895,12 @@ impl Renderer { wgpu::Features::DEPTH_CLAMPING } - pub fn cam_look_delta(&mut self, delta: (f64, f64)) { - - // let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 20.0); - // let mx_view = cgmath::Matrix4::look_at( - // cgmath::Point3::new(3.0f32, -9.0, 6.0), - // cgmath::Point3::new(0f32, 0.0, 0.0), - // cgmath::Vector3::unit_z(), - // ); - // let mx_correction = OPENGL_TO_WGPU_MATRIX; - // let mx_total = mx_correction * mx_projection * mx_view; - let mut mx_total = self.camera_projection.clone(); - let q = vec3(delta.0 as f32, delta.1 as f32, 1.0); - mx_total.transform_vector(q); - - let mx_ref: &[f32; 16] = mx_total.as_ref(); - self.queue.write_buffer( - &self.forward_pass.uniform_buf, - 0, - bytemuck::cast_slice(mx_ref), - ); - } - pub fn resize(&mut self, width: u32, height: u32) { - self.swapchain_description.width = width; self.swapchain_description.height = height; - self.swapchain = self.device.create_swap_chain( - &self.surface, &self.swapchain_description.clone() - ); + self.swapchain = self + .device + .create_swap_chain(&self.surface, &self.swapchain_description.clone()); // update view-projection matrix let mx_total = Self::generate_matrix(width as f32 / height as f32); @@ -887,7 +926,5 @@ impl Renderer { }); self.forward_depth = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); self.camera_projection = mx_total; - - } }