lots of skeleton stuff. lots of hacking. mostly hacking

master
mitchellhansen 4 years ago
parent 9f4c8a856c
commit 189805dd13

@ -30,3 +30,4 @@ tobj = "2.0.3"
legion = "0.3.1" legion = "0.3.1"
nalgebra = "0.24.1" nalgebra = "0.24.1"
rapier3d = { version = "0.5.0", features = [ "simd-nightly", "parallel" ] } rapier3d = { version = "0.5.0", features = [ "simd-nightly", "parallel" ] }
gilrs = "0.8.0"

@ -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<f32>,
pub yaw: Rad<f32>,
pub pitch: Rad<f32>,
}
impl Camera {
pub fn new<
V: Into<Point3<f32>>,
Y: Into<Rad<f32>>,
P: Into<Rad<f32>>,
>(
position: V,
yaw: Y,
pitch: P,
) -> Self {
Self {
position: position.into(),
yaw: yaw.into(),
pitch: pitch.into(),
}
}
pub fn calc_matrix(&self) -> Matrix4<f32> {
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);
}
}
}

@ -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<f32>,
}
#[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<Idx> {
pub start: Idx,
pub end: Idx,
}
#[derive(Clone, Debug)]
pub struct DirectionalLight {
pub color: wgpu::Color,
pub fov: f32,
pub depth: RangeCopy<f32>,
pub target_view: Arc<TextureView>,
}
#[derive(Clone, Debug)]
pub struct Mesh {
pub index_buffer: Arc<Buffer>,
pub index_count: usize,
pub vertex_buffer: Arc<Buffer>,
pub uniform_buffer: Arc<Buffer>,
pub bind_group: Arc<BindGroup>,
}
#[derive(Clone, Debug)]
pub struct Physics {
pub rigid_body: RigidBody,
pub rigid_body_handle: Option<RigidBodyHandle>,
}
#[derive(Clone)]
pub struct Collider {
pub collider: r3dCollider,
pub collider_handle: Option<ColliderHandle>,
}

@ -1,7 +1,8 @@
use bytemuck::__core::ops::Range; use bytemuck::__core::ops::Range;
use bytemuck::{Zeroable, Pod}; use bytemuck::{Zeroable, Pod};
use crate::{OPENGL_TO_WGPU_MATRIX, DirectionalLight, Position};
use cgmath::Point3; use cgmath::Point3;
use crate::render::OPENGL_TO_WGPU_MATRIX;
use crate::components::DirectionalLight;
#[repr(C)] #[repr(C)]

@ -8,13 +8,12 @@ use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use bytemuck::__core::ops::Range; 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 futures::task::LocalSpawn;
use legion::*; use legion::*;
use rapier3d::dynamics::{ use rapier3d::dynamics::{
IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet,
}; };
use rapier3d::geometry::Collider as r3dCollider;
use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderHandle, ColliderSet, NarrowPhase}; use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderHandle, ColliderSet, NarrowPhase};
use rapier3d::math; use rapier3d::math;
use rapier3d::na::{Isometry, Isometry3, Vector, Vector3}; use rapier3d::na::{Isometry, Isometry3, Vector, Vector3};
@ -28,13 +27,23 @@ use winit::{
event_loop::{ControlFlow, EventLoop}, 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::physics::PhysicsState;
use crate::render::Renderer; use crate::render::Renderer;
use crate::owned_event::TrEventExtension;
use gilrs::{Gamepad, Gilrs};
use rapier3d::counters::Timer;
mod camera;
mod components;
mod geometry; mod geometry;
mod light; mod light;
mod physics; mod physics;
mod render; mod render;
mod owned_event;
/* /*
@ -58,81 +67,13 @@ mvp:
ECS ECS
animation animation
render 3d render 3d (good!)
input/io input/io
collision / physics collision / physics (yep!)
entities & behaviours entities & behaviours (got the entities!)
*/ */
#[cfg_attr(rustfmt, rustfmt_skip)]
#[allow(unused)]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = 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<f32>,
//mx: cgmath::Matrix4<f32>,
}
#[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<Idx> {
pub start: Idx,
pub end: Idx,
}
#[derive(Clone, Debug)]
pub struct DirectionalLight {
color: wgpu::Color,
fov: f32,
depth: RangeCopy<f32>,
target_view: Arc<TextureView>,
}
#[derive(Clone, Debug)]
pub struct Mesh {
index_buffer: Arc<Buffer>,
index_count: usize,
vertex_buffer: Arc<Buffer>,
uniform_buffer: Arc<Buffer>,
bind_group: Arc<BindGroup>,
}
#[derive(Clone, Debug)]
pub struct Physics {
rigid_body: RigidBody,
rigid_body_handle: Option<RigidBodyHandle>,
}
#[derive(Clone)]
pub struct Collider {
collider: r3dCollider,
collider_handle: Option<ColliderHandle>,
}
//log::info!(""); //log::info!("");
fn main() { fn main() {
@ -151,12 +92,13 @@ fn main() {
// TODO schedule for the update system and others // TODO schedule for the update system and others
let mut update_schedule = Schedule::builder() let mut update_schedule = Schedule::builder()
.add_system(physics::update_camera_system())
.add_system(physics::run_physics_system()) .add_system(physics::run_physics_system())
.add_system(physics::update_models_system()) .add_system(physics::update_models_system())
// next system here, gamelogic update system? // next system here, gamelogic update system?
.build(); .build();
let event_loop = EventLoop::new(); let event_loop = EventLoop::<TrEventExtension>::with_user_event();
let mut builder = winit::window::WindowBuilder::new(); let mut builder = winit::window::WindowBuilder::new();
builder = builder.with_title("MVGE"); builder = builder.with_title("MVGE");
@ -169,8 +111,6 @@ fn main() {
let window = builder.build(&event_loop).unwrap(); let window = builder.build(&event_loop).unwrap();
let mut last_update_inst = Instant::now();
// Load up the renderer (and the resources) // Load up the renderer (and the resources)
let mut renderer = { let mut renderer = {
let mut renderer = render::Renderer::init(&window); let mut renderer = render::Renderer::init(&window);
@ -186,20 +126,94 @@ fn main() {
resources.insert(physics_state); resources.insert(physics_state);
resources.insert(physics_pipeline); 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<Gamepad> = 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::<Instant>().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| { event_loop.run(move |event, _, control_flow| {
// Artificially slows the loop rate to 10 millis // Artificially slows the loop rate to 10 millis
// This is called after redraw events cleared // 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 { match event {
event::Event::MainEventsCleared => { event::Event::MainEventsCleared => {
// ask for a redraw every 20 millis
if last_update_inst.elapsed() > Duration::from_millis(20) { elapsed_time = { // deltatime since last frame
window.request_redraw(); let last_frame = resources.get::<Instant>().unwrap();
last_update_inst = Instant::now(); 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::<Instant>().unwrap();
last_frame.elapsed()
};
update_schedule.execute(&mut world, &mut resources); 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::Event::DeviceEvent {
event: MouseMotion { delta }, event: MouseMotion { delta },
@ -257,7 +271,20 @@ fn main() {
pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { pub fn entity_loading(world: &mut World, renderer: &mut Renderer) {
let monkey_mesh = renderer.load_mesh_to_buffer("./resources/monkey.obj"); 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(( let light_entity: Entity = world.push((
cgmath::Point3 { cgmath::Point3 {
x: 7.0 as f32, x: 7.0 as f32,

@ -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<T> {
UIEvent(T)
}
#[derive(Clone)]
pub enum TrEventExtension {
/// Custom events here
MouseHeldEvent {},
KeyHeldEvent {},
GamepadEvent {
gil_event: GilEvent,
},
}
#[derive(Clone, Debug)]
pub enum TrEvent<T> {
/// 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<T> From<Event<'_, T>> for TrEvent<T> {
fn from(event: Event<T>) -> 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<u32>),
Moved(PhysicalPosition<i32>),
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<f64>,
#[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<u32>,
},
ThemeChanged(Theme),
}

@ -6,8 +6,10 @@ use rapier3d::pipeline::PhysicsPipeline;
use legion::*; use legion::*;
use crate::render::{EntityUniforms, Renderer}; use crate::render::{EntityUniforms, Renderer};
use crate::{Collider, Mesh, RigidBody, Physics, Position};
use cgmath::Quaternion; use cgmath::Quaternion;
use crate::components::{Collider, Physics, Mesh, Position};
use crate::camera::{CameraController, Camera};
use std::time::Instant;
pub struct PhysicsState { pub struct PhysicsState {
gravity: rapier3d::math::Vector<f32>, gravity: rapier3d::math::Vector<f32>,
@ -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] #[system]
#[write_component(Collider)] #[write_component(Collider)]
#[write_component(Physics)] #[write_component(Physics)]

@ -3,10 +3,11 @@ use std::{iter, num::NonZeroU32, ops::Range, rc::Rc};
use bytemuck::__core::mem; use bytemuck::__core::mem;
use bytemuck::{Pod, Zeroable}; 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 futures::executor::LocalPool;
use legion::world::SubWorld; use legion::world::SubWorld;
use legion::*; use legion::*;
use rapier3d::parry::motion::RigidMotionComposition;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use wgpu::{ use wgpu::{
BindGroup, BindGroupLayout, Buffer, Device, Instance, Queue, Surface, SwapChain, 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::platform::unix::x11::ffi::Time;
use winit::window::Window; 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::geometry::{create_plane, import_mesh, vertex, Vertex};
use crate::light::LightRaw; 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<f32> = 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)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -29,25 +39,30 @@ pub struct ForwardUniforms {
} }
unsafe impl Pod for ForwardUniforms {} unsafe impl Pod for ForwardUniforms {}
unsafe impl Zeroable for ForwardUniforms {} unsafe impl Zeroable for ForwardUniforms {}
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy, Debug)]
pub struct EntityUniforms { pub struct EntityUniforms {
model: [[f32; 4]; 4], model: [[f32; 4]; 4],
color: [f32; 4], color: [f32; 4],
} }
unsafe impl Pod for EntityUniforms {} unsafe impl Pod for EntityUniforms {}
unsafe impl Zeroable for EntityUniforms {} unsafe impl Zeroable for EntityUniforms {}
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct ShadowUniforms { pub struct ShadowUniforms {
proj: [[f32; 4]; 4], 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 { pub struct Pass {
pipeline: wgpu::RenderPipeline, pipeline: wgpu::RenderPipeline,
bind_group: wgpu::BindGroup, bind_group: wgpu::BindGroup,
@ -55,7 +70,6 @@ pub struct Pass {
} }
pub struct Renderer { pub struct Renderer {
swapchain: SwapChain, swapchain: SwapChain,
swapchain_description: SwapChainDescriptor, swapchain_description: SwapChainDescriptor,
instance: Arc<Instance>, instance: Arc<Instance>,
@ -78,32 +92,6 @@ pub struct Renderer {
light_uniform_buf: wgpu::Buffer, light_uniform_buf: wgpu::Buffer,
camera_projection: Matrix4<f32>, camera_projection: Matrix4<f32>,
}
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<f32> {
// 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] #[system]
@ -112,7 +100,12 @@ impl Renderer {
#[write_component(Mesh)] #[write_component(Mesh)]
#[write_component(Color)] #[write_component(Color)]
#[write_component(DirectionalLight)] #[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 let mut encoder = renderer
.device .device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); .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<f32>)>::query(); let mut query = <(&mut DirectionalLight, &mut Point3<f32>)>::query();
for (i, (light, pos)) in query.iter_mut(world).enumerate() { for (i, (light, pos)) in query.iter_mut(world).enumerate() {
encoder.insert_debug_marker(&format!("shadow pass {} (light at position {:?})", i, pos)); encoder.insert_debug_marker(&format!("shadow pass {} (light at position {:?})", i, pos));
// The light uniform buffer already has the projection, // 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, &[]); pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]);
for mesh in &mesh_stack { for mesh in &mesh_stack {
pass.set_bind_group(1, &mesh.bind_group, &[]); pass.set_bind_group(1, &mesh.bind_group, &[]);
pass.set_index_buffer(mesh.index_buffer.slice(..)); pass.set_index_buffer(mesh.index_buffer.slice(..));
pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1);
} }
} }
encoder.pop_debug_group(); encoder.pop_debug_group();
// forward pass // forward pass
@ -252,6 +241,77 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) {
} }
impl 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<f32> {
// 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 { pub fn get_current_frame(&mut self) -> SwapChainFrame {
// Update the renderers swapchain state // Update the renderers swapchain state
@ -273,7 +333,6 @@ impl Renderer {
indices: Vec<u32>, indices: Vec<u32>,
vertices: Vec<Vertex>, vertices: Vec<Vertex>,
) -> (Arc<Buffer>, Arc<Buffer>) { ) -> (Arc<Buffer>, Arc<Buffer>) {
let vertex_buf = Arc::new( let vertex_buf = Arc::new(
device.create_buffer_init(&wgpu::util::BufferInitDescriptor { device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("vertex-buffer"), label: Some("vertex-buffer"),
@ -294,7 +353,11 @@ impl Renderer {
} }
pub fn create_light(&mut self) -> DirectionalLight { 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; self.views_given = self.views_given + 1;
DirectionalLight { DirectionalLight {
color: wgpu::Color { 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 mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
let forward_pass = { let forward_pass = {
// Create pipeline layout // Create pipeline layout
let bind_group_layout = let bind_group_layout =
@ -833,35 +895,12 @@ impl Renderer {
wgpu::Features::DEPTH_CLAMPING 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) { pub fn resize(&mut self, width: u32, height: u32) {
self.swapchain_description.width = width; self.swapchain_description.width = width;
self.swapchain_description.height = height; self.swapchain_description.height = height;
self.swapchain = self.device.create_swap_chain( self.swapchain = self
&self.surface, &self.swapchain_description.clone() .device
); .create_swap_chain(&self.surface, &self.swapchain_description.clone());
// update view-projection matrix // update view-projection matrix
let mx_total = Self::generate_matrix(width as f32 / height as f32); 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.forward_depth = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
self.camera_projection = mx_total; self.camera_projection = mx_total;
} }
} }

Loading…
Cancel
Save