lots of skeleton stuff. lots of hacking. mostly hacking
This commit is contained in:
@@ -30,3 +30,4 @@ tobj = "2.0.3"
|
||||
legion = "0.3.1"
|
||||
nalgebra = "0.24.1"
|
||||
rapier3d = { version = "0.5.0", features = [ "simd-nightly", "parallel" ] }
|
||||
gilrs = "0.8.0"
|
||||
173
src/camera.rs
Normal file
173
src/camera.rs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
64
src/components.rs
Normal file
64
src/components.rs
Normal file
@@ -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::{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)]
|
||||
|
||||
193
src/main.rs
193
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<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!("");
|
||||
|
||||
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::<TrEventExtension>::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<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| {
|
||||
// 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::<Instant>().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::<Instant>().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,
|
||||
|
||||
213
src/owned_event.rs
Normal file
213
src/owned_event.rs
Normal file
@@ -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 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<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]
|
||||
#[write_component(Collider)]
|
||||
#[write_component(Physics)]
|
||||
|
||||
175
src/render.rs
175
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<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)]
|
||||
#[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<Instance>,
|
||||
@@ -78,32 +92,6 @@ pub struct Renderer {
|
||||
light_uniform_buf: wgpu::Buffer,
|
||||
|
||||
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]
|
||||
@@ -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<f32>)>::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<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 {
|
||||
// Update the renderers swapchain state
|
||||
@@ -273,7 +333,6 @@ impl Renderer {
|
||||
indices: Vec<u32>,
|
||||
vertices: Vec<Vertex>,
|
||||
) -> (Arc<Buffer>, Arc<Buffer>) {
|
||||
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user