diff --git a/Cargo.lock b/Cargo.lock index c166bf4..84ec05e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -349,15 +349,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" -[[package]] -name = "colored" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "combine" version = "4.6.7" @@ -1105,9 +1096,6 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "mars" version = "0.1.0" -dependencies = [ - "colored", -] [[package]] name = "memchr" diff --git a/game.core b/game.core deleted file mode 100644 index e541f3a..0000000 Binary files a/game.core and /dev/null differ diff --git a/src/app.rs b/src/app.rs index 0907c8e..37f3ede 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,345 +1,312 @@ use std::collections::HashMap; // Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu -use crate::render::Renderer; -use crate::world::{SimpleObject, World}; -use glam::{Affine3A, EulerRot, Mat4, Quat, Vec2, Vec3, Vec4}; use std::sync::Arc; +use glam::{Vec2, Affine3A, Vec3, Vec4, Mat4, EulerRot, Quat}; #[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; use winit::dpi::PhysicalPosition; #[cfg(target_arch = "wasm32")] use winit::platform::web::EventLoopExtWebSys; use winit::{ - application::ApplicationHandler, - event::*, - event_loop::{ActiveEventLoop, EventLoop}, - keyboard::{KeyCode, PhysicalKey}, - window::Window, + application::ApplicationHandler, + event::*, + event_loop::{ActiveEventLoop, EventLoop}, + keyboard::{KeyCode, PhysicalKey}, + window::Window, }; +use crate::render; +use crate::render::{Renderer, SimpleTexture}; +use crate::world::{SimpleObject, World}; struct Controller { - buttons: HashMap, - keys: HashMap, - mouse: Vec2, + buttons: HashMap, + keys: HashMap, + mouse: Vec2, } impl Controller { - fn new() -> Controller { - Controller { - buttons: Default::default(), - keys: HashMap::new(), - mouse: Vec2::new(0.0, 0.0), - } + fn new() -> Controller { + Controller { + buttons: Default::default(), + keys: HashMap::new(), + mouse: Vec2::new(0.0,0.0), } + } } pub struct AppState { - world: World, - controller: Controller, - window: Arc, - clients: Vec, + world: World, + controller: Controller, + window: Arc, + clients: Vec, } -const BLOCKS: i32 = 1; +const BLOCKS: i32 = 50; impl AppState { - // We don't need this to be async right now, - // but we will in the next tutorial - pub async fn new(window: Arc) -> Result> { - let mut world = World::new(); - world.add_renderer(Renderer::new(&window).await?); - let mut clients = Vec::new(); - { - let file = world - .renderer - .as_mut() - .unwrap() - .load_from_gltf(include_bytes!("assets/cube.glb")); - let block = file.first_object().unwrap(); - let skybox = world.renderer.as_mut().unwrap().load_texture_from_bytes( - include_bytes!("assets/skybox1.png"), - Some(image::ImageFormat::Png), - ); - world.renderer.as_mut().unwrap().set_skybox(skybox); - //let color = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png")); - //let normal = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png")); - //let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png")); - //let mat = renderer.new_material(color,normal,roughness); - for x in -BLOCKS..BLOCKS { - for y in -BLOCKS..BLOCKS { - let block = block.hard_clone(); - world.add_object(block.clone()); - { - let mut model = block.0.borrow_mut(); - model.model.as_mut().unwrap().instance.transform = Mat4::from_translation( - Vec3::new(-x as f32 * 3.0, -8.0, -y as f32 * 3.0), - ) - * Mat4::from_rotation_z((x * y) as f32 / 1.23); - model.model.as_mut().unwrap().instance.color = Vec4::new( - 0.3, - (x + BLOCKS) as f32 / BLOCKS as f32, - (y + BLOCKS) as f32 / BLOCKS as f32, - 1.0, - ); - } - clients.push(block) - } - } + // We don't need this to be async right now, + // but we will in the next tutorial + pub async fn new(window: Arc) -> Result> { + let size = window.inner_size(); + let mut world = World::new(); + world.add_renderer(Renderer::new(&window).await?); + let mut clients = Vec::new(); + { + let file = world.renderer.as_mut().unwrap().load_from_gltf( include_bytes!("assets/cube.glb")); + let block = file.first_object().unwrap(); + //let color = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png")); + //let normal = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png")); + //let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png")); + //let mat = renderer.new_material(color,normal,roughness); + for x in -BLOCKS..BLOCKS { + for y in -BLOCKS..BLOCKS { + let block = block.hard_clone(); + world.add_object(block.clone()); + { + let mut model = block.0.borrow_mut(); + model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(Vec3::new(-x as f32 * 3.0,0.0,-y as f32 * 3.0)) + * Mat4::from_rotation_z((x * y) as f32 / 1.23); + model.model.as_mut().unwrap().instance.color = Vec4::new(0.3,(x + BLOCKS) as f32 / BLOCKS as f32,(y + BLOCKS) as f32 / BLOCKS as f32,1.0); + } + clients.push(block) } - Ok(Self { - world, - clients, - controller: Controller::new(), - window, - }) + } } + Ok(Self { + world, + clients, + controller: Controller::new(), + window, + }) + } - pub fn bounds(&self) -> (u32, u32) { - let size = self.window.inner_size(); - (size.width, size.height) - } + pub fn bounds(&self) -> (u32,u32) { + let size = self.window.inner_size(); + (size.width,size.height) + } - pub fn resize(&mut self, width: u32, height: u32) { - if width > 0 && height > 0 { - self.world.renderer.as_mut().unwrap().resize(width, height); - } + pub fn resize(&mut self, width: u32, height: u32) { + if width > 0 && height > 0 { + let max = 2048; + self.world.renderer.as_mut().unwrap().resize(width,height); } + } - fn update(&mut self) { - // ... - } + fn update(&mut self) { + // ... + } - fn handle_key(&mut self, event_loop: &ActiveEventLoop, code: KeyCode, is_pressed: bool) { - match (code, is_pressed) { - (KeyCode::Escape, true) => event_loop.exit(), - (KeyCode::Space, true) => {} - (KeyCode::KeyR, true) => { - self.world.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY - } - _ => {} - } - self.controller.keys.insert(code, is_pressed); + fn handle_key(&mut self, event_loop: &ActiveEventLoop, code: KeyCode, is_pressed: bool) { + match (code, is_pressed) { + (KeyCode::Escape, true) => event_loop.exit(), + (KeyCode::Space, true) => {}, + (KeyCode::KeyR, true) => { + self.world.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY + } + _ => {} } + self.controller.keys.insert(code, is_pressed); + } - fn handle_mouse_moved(&mut self, position: PhysicalPosition) { - if let Some(true) = self.controller.buttons.get(&MouseButton::Right) { - self.world.renderer.as_mut().unwrap().eye.rotate( - position.x as f32 - self.controller.mouse.x, - position.y as f32 - self.controller.mouse.y, - ); - } - self.controller.mouse = Vec2::new(position.x as f32, position.y as f32); + fn handle_mouse_moved(&mut self, position: PhysicalPosition) { + if let Some(true) = self.controller.buttons.get(&MouseButton::Right) { + self.world.renderer.as_mut().unwrap().eye.rotate(position.x as f32 - self.controller.mouse.x, position.y as f32 - self.controller.mouse.y); } + self.controller.mouse = Vec2::new(position.x as f32, position.y as f32); + } - fn handle_mouse_button(&mut self, button: MouseButton, state: ElementState) { - self.controller.buttons.insert(button, state.is_pressed()); - } + fn handle_mouse_button(&mut self, button: MouseButton, state: ElementState ) { + self.controller.buttons.insert(button,state.is_pressed()); + } } pub struct App { - #[cfg(target_arch = "wasm32")] - proxy: Option>, - state: Option, + #[cfg(target_arch = "wasm32")] + proxy: Option>, + state: Option, } impl App { - pub fn new(#[cfg(target_arch = "wasm32")] event_loop: &EventLoop) -> Self { - #[cfg(target_arch = "wasm32")] - let proxy = Some(event_loop.create_proxy()); - Self { - state: None, - #[cfg(target_arch = "wasm32")] - proxy, - } + pub fn new(#[cfg(target_arch = "wasm32")] event_loop: &EventLoop) -> Self { + #[cfg(target_arch = "wasm32")] + let proxy = Some(event_loop.create_proxy()); + Self { + state: None, + #[cfg(target_arch = "wasm32")] + proxy, } + } } impl ApplicationHandler for App { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - #[allow(unused_mut)] - let mut window_attributes = Window::default_attributes(); - - #[cfg(target_arch = "wasm32")] - { - use wasm_bindgen::JsCast; - use winit::platform::web::WindowAttributesExtWebSys; - - const CANVAS_ID: &str = "canvas"; - - let window = wgpu::web_sys::window().unwrap_throw(); - let document = window.document().unwrap_throw(); - let canvas = document.get_element_by_id(CANVAS_ID).unwrap_throw(); - let html_canvas_element = canvas.unchecked_into(); - window_attributes = window_attributes.with_canvas(Some(html_canvas_element)); - } - - let window = Arc::new(event_loop.create_window(window_attributes).unwrap()); - - #[cfg(not(target_arch = "wasm32"))] - { - // If we are not on web we can use pollster to - // await the window creation - self.state = Some(pollster::block_on(AppState::new(window)).unwrap()); - } - - #[cfg(target_arch = "wasm32")] - { - // Run the future asynchronously and use the - // proxy to send the results to the event loop - if let Some(proxy) = self.proxy.take() { - wasm_bindgen_futures::spawn_local(async move { - assert!( - proxy - .send_event( - AppState::new(window) - .await - .expect("Unable to create canvas!!!") - ) - .is_ok() - ) - }); - } - } - } - + fn resumed(&mut self, event_loop: &ActiveEventLoop) { #[allow(unused_mut)] - fn user_event(&mut self, _event_loop: &ActiveEventLoop, mut event: AppState) { - // This is where proxy.send_event() ends up - #[cfg(target_arch = "wasm32")] - { - event.window.request_redraw(); - event.resize( - event.window.inner_size().width, - event.window.inner_size().height, - ); - } - self.state = Some(event); + let mut window_attributes = Window::default_attributes(); + + #[cfg(target_arch = "wasm32")] + { + use wasm_bindgen::JsCast; + use winit::platform::web::WindowAttributesExtWebSys; + + const CANVAS_ID: &str = "canvas"; + + let window = wgpu::web_sys::window().unwrap_throw(); + let document = window.document().unwrap_throw(); + let canvas = document.get_element_by_id(CANVAS_ID).unwrap_throw(); + let html_canvas_element = canvas.unchecked_into(); + window_attributes = window_attributes.with_canvas(Some(html_canvas_element)); } - fn window_event( - &mut self, - event_loop: &ActiveEventLoop, - _window_id: winit::window::WindowId, - event: WindowEvent, - ) { - let state = match &mut self.state { - Some(canvas) => canvas, - None => return, + let window = Arc::new(event_loop.create_window(window_attributes).unwrap()); + + #[cfg(not(target_arch = "wasm32"))] + { + // If we are not on web we can use pollster to + // await the window creation + self.state = Some(pollster::block_on(AppState::new(window)).unwrap()); + } + + #[cfg(target_arch = "wasm32")] + { + // Run the future asynchronously and use the + // proxy to send the results to the event loop + if let Some(proxy) = self.proxy.take() { + wasm_bindgen_futures::spawn_local(async move { + assert!( + proxy + .send_event( + AppState::new(window) + .await + .expect("Unable to create canvas!!!") + ) + .is_ok() + ) + }); + } + } + } + + #[allow(unused_mut)] + fn user_event(&mut self, _event_loop: &ActiveEventLoop, mut event: AppState) { + // This is where proxy.send_event() ends up + #[cfg(target_arch = "wasm32")] + { + event.window.request_redraw(); + event.resize( + event.window.inner_size().width, + event.window.inner_size().height, + ); + } + self.state = Some(event); + } + + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + _window_id: winit::window::WindowId, + event: WindowEvent, + ) { + let state = match &mut self.state { + Some(canvas) => canvas, + None => return, + }; + + match event { + WindowEvent::CloseRequested => event_loop.exit(), + WindowEvent::Resized(size) => state.resize(size.width, size.height), + WindowEvent::RedrawRequested => { + state.update(); + let mut movement = Vec3::new(0.0,0.0,0.0); + + let pressed = |keycode: KeyCode| { + if let Some(true) = state.controller.keys.get(&keycode) { + true + } else { + false + } }; - match event { - WindowEvent::CloseRequested => event_loop.exit(), - WindowEvent::Resized(size) => state.resize(size.width, size.height), - WindowEvent::RedrawRequested => { - state.update(); - let mut movement = Vec3::new(0.0, 0.0, 0.0); - - let pressed = |keycode: KeyCode| { - if let Some(true) = state.controller.keys.get(&keycode) { - true - } else { - false - } - }; - - if pressed(KeyCode::KeyA) { - movement.x -= 1.0; - } - if pressed(KeyCode::KeyD) { - movement.x += 1.0; - } - if pressed(KeyCode::KeyW) { - movement.z += 1.0; - } - if pressed(KeyCode::KeyS) { - movement.z -= 1.0; - } - if pressed(KeyCode::KeyE) { - movement.y += 1.0; - } - if pressed(KeyCode::KeyQ) { - movement.y -= 1.0; - } - - state - .world - .renderer - .as_mut() - .unwrap() - .eye - .control(movement * 0.1); - match state.world.renderer.as_mut().unwrap().render(&state.window) { - Ok(_) => {} - Err(e) => { - // Log the error and exit gracefully - log::error!("{e}"); - event_loop.exit(); - } - } - for object in state.clients.iter() { - object - .0 - .borrow_mut() - .model - .as_mut() - .unwrap() - .instance - .transform *= Mat4::from_rotation_translation( - Quat::from_euler(EulerRot::XYZ, 0.001, -0.001, 0.001), - Vec3::new(0.0, 0.0, 0.0), - ); - } - } - WindowEvent::MouseInput { - button, - state: element, - .. - } => state.handle_mouse_button(button, element), - WindowEvent::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos), - WindowEvent::KeyboardInput { - event: - KeyEvent { - physical_key: PhysicalKey::Code(code), - state: key_state, - .. - }, - .. - } => state.handle_key(event_loop, code, key_state.is_pressed()), - _ => {} + if pressed(KeyCode::KeyA) { + movement.x -= 1.0; } + if pressed(KeyCode::KeyD) { + movement.x += 1.0; + } + if pressed(KeyCode::KeyW) { + movement.z += 1.0; + } + if pressed(KeyCode::KeyS) { + movement.z -= 1.0; + } + if pressed(KeyCode::KeyE) { + movement.y += 1.0; + } + if pressed(KeyCode::KeyQ) { + movement.y -= 1.0; + } + + state.world.renderer.as_mut().unwrap().eye.control(movement * 0.1); + match state.world.renderer.as_mut().unwrap().render(&state.window) { + Ok(_) => {} + Err(e) => { + // Log the error and exit gracefully + log::error!("{e}"); + event_loop.exit(); + } + } + for object in state.clients.iter() { + object.0.borrow_mut().model.as_mut().unwrap().instance.transform *= Mat4::from_rotation_translation( + Quat::from_euler(EulerRot::XYZ,0.001,-0.001,0.001), + Vec3::new(0.0,0.0,0.0) + ); + } + } + WindowEvent::MouseInput { button, state: element, .. } => state.handle_mouse_button(button,element), + WindowEvent::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos), + WindowEvent::KeyboardInput { + event: + KeyEvent { + physical_key: PhysicalKey::Code(code), + state: key_state, + .. + }, + .. + } => state.handle_key(event_loop, code, key_state.is_pressed()), + _ => {} } + } } pub fn run() -> anyhow::Result<()> { - #[cfg(not(target_arch = "wasm32"))] - { - env_logger::init(); - } - #[cfg(target_arch = "wasm32")] - { - console_log::init_with_level(log::Level::Info).unwrap_throw(); - } + #[cfg(not(target_arch = "wasm32"))] + { + env_logger::init(); + } + #[cfg(target_arch = "wasm32")] + { + console_log::init_with_level(log::Level::Info).unwrap_throw(); + } - let event_loop = EventLoop::with_user_event().build()?; - #[cfg(not(target_arch = "wasm32"))] - { - let mut app = App::new(); - event_loop.run_app(&mut app)?; - } - #[cfg(target_arch = "wasm32")] - { - let app = App::new(&event_loop); - event_loop.spawn_app(app); - } + let event_loop = EventLoop::with_user_event().build()?; + #[cfg(not(target_arch = "wasm32"))] + { + let mut app = App::new(); + event_loop.run_app(&mut app)?; + } + #[cfg(target_arch = "wasm32")] + { + let app = App::new(&event_loop); + event_loop.spawn_app(app); + } - Ok(()) + Ok(()) } #[cfg(target_arch = "wasm32")] #[wasm_bindgen(start)] pub fn run_web() -> Result<(), wasm_bindgen::JsValue> { - console_error_panic_hook::set_once(); - run().unwrap_throw(); + console_error_panic_hook::set_once(); + run().unwrap_throw(); - Ok(()) + Ok(()) } diff --git a/src/assets/SimpleShader.wgsl b/src/assets/SimpleShader.wgsl index 7a9a592..1f22a81 100644 --- a/src/assets/SimpleShader.wgsl +++ b/src/assets/SimpleShader.wgsl @@ -4,26 +4,16 @@ struct Environment { dir: vec4, } -struct Eye { - // from camera to screen - proj: mat4x4, - // from screen to camera - inv: mat4x4, - // world to camera +struct View { view: mat4x4, - // camera transform frame: mat4x4, } // Vertex shader @group(0) @binding(0) -var eye: Eye; +var view: View; @group(0) @binding(1) var environment: Environment; -@group(0) @binding(2) -var sky_sampler: sampler; -@group(0) @binding(3) -var sky_texture: texture_2d; struct VertexInput { @location(0) position: vec3, @@ -70,7 +60,7 @@ fn vs_main( out.world_normal = model_rot_matrix * model.normal; var world_position: vec4 = model_matrix * vec4(model.position, 1.0); out.world_position = world_position.xyz; - out.clip_position = eye.proj * eye.view * world_position; + out.clip_position = view.view * world_position; return out; } @@ -85,79 +75,23 @@ var t_normal: texture_2d; @group(1) @binding(3) var t_rough: texture_2d; -fn sky_aspect(look: vec3) -> vec4 { - var pi = 3.14159; - let u_angle = atan2(look.x,look.z); - let u = (u_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1 - let v_angle = atan2(-look.y,sqrt(look.x * look.x + look.z * look.z)); - let v = (v_angle/pi) + 0.5;//(v_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1 - let uv = vec2(u,v); // Get UV on skybox - return textureSample(sky_texture, sky_sampler, uv); -} - -fn rotation(mat: mat4x4) -> mat3x3 { - return mat3x3( - mat[0].xyz, - mat[1].xyz, - mat[2].xyz, - ); -} - -fn translation(mat: mat4x4) -> vec4 { - //return vec4(mat[0][3],mat[1][3],mat[2][3],mat[3][3]); - return mat[3]; -} - @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.tex_coords); let object_normal: vec4 = textureSample(t_normal, s_diffuse, in.tex_coords); - let diffuse_color = object_color.xyz; - let specular_color = vec3(0.0,0.0,0.0); - let reflection = sky_aspect(reflect(normalize(in.world_position-translation(eye.frame).xyz),normalize(in.world_normal))); + let tangent_normal = object_normal.xyz * 2.0 - 1.0; + let light_dir = normalize(environment.dir.xyz); + let view_dir = normalize(view.frame[3].xyz - in.world_position); + let half_dir = normalize(view_dir + light_dir); - //let result = (environment.ambient.xyz + diffuse_color + specular_color) * object_color.xyz; + let diffuse_strength = max(dot(tangent_normal, light_dir), 0.0); + let diffuse_color = environment.light.xyz * diffuse_strength; - //let light_dir = normalize(environment.dir.xyz); - //let view_dir = normalize(eye.frame[3].xyz - in.world_position); - //let half_dir = normalize(view_dir + light_dir); - - //let diffuse_strength = max(dot(tangent_normal, light_dir), 0.0); - //let diffuse_color = environment.light.xyz * diffuse_strength; - - //let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0); - //let specular_color = specular_strength * environment.light.xyz; + let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0); + let specular_color = specular_strength * environment.light.xyz; let result = (environment.ambient.xyz + diffuse_color.xyz + specular_color.xyz) * object_color.xyz; - return vec4(reflection.xyz,object_color.a); -} - -struct SkyOutput { - @builtin(position) position: vec4, - @location(0) pos: vec4 // unadulterated by WGSL -} - -const TRI_VERTICES = array( - vec4(-1.0, -1.0, 1.0, 1.0), - vec4(-1.0, 1.0, 1.0, 1.0), - vec4( 1.0, -1.0, 1.0, 1.0), - vec4( 1.0, 1.0, 1.0, 1.0), - vec4(-1.0, 1.0, 1.0, 1.0), - vec4( 1.0, -1.0, 1.0, 1.0), -); - -@vertex -fn vs_sky(@builtin(vertex_index) index: u32) -> SkyOutput { - var out: SkyOutput; - out.position = TRI_VERTICES[index]; - out.pos = out.position; - return out; -} - -@fragment -fn fs_sky(in: SkyOutput) -> @location(0) vec4 { - let look = rotation(eye.frame) * in.pos.xyz; - return sky_aspect(look); -} + return vec4(result.xyz,object_color.a); +} \ No newline at end of file diff --git a/src/assets/cube.glb b/src/assets/cube.glb deleted file mode 100644 index 461ea6c..0000000 Binary files a/src/assets/cube.glb and /dev/null differ diff --git a/src/assets/skybox1.png b/src/assets/skybox1.png deleted file mode 100644 index a526667..0000000 Binary files a/src/assets/skybox1.png and /dev/null differ diff --git a/src/assets/test.png b/src/assets/test.png new file mode 100755 index 0000000..9de6980 Binary files /dev/null and b/src/assets/test.png differ diff --git a/src/render/eye.rs b/src/render/eye.rs index 11b7112..4d03e14 100644 --- a/src/render/eye.rs +++ b/src/render/eye.rs @@ -1,187 +1,131 @@ -use crate::render::{MaterialProperties, SimpleTexture}; use bytemuck::{Pod, Zeroable}; -use glam::camera::lh::proj::directx::perspective; +use env_logger::Env; use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4}; -use wgpu::util::DeviceExt; +use glam::camera::lh::proj::directx::perspective; use wgpu::{Device, Queue}; +use wgpu::util::DeviceExt; pub(crate) struct Eye { - pub(crate) frame: Affine3A, - pub(crate) environment: Environment, - aspect_ratio: f32, - z_near: f32, - z_far: f32, - fov_y: f32, - pub(crate) environment_buffer: wgpu::Buffer, - pub(crate) camera_buffer: wgpu::Buffer, - pub(crate) layout: wgpu::BindGroupLayout, - pub(crate) group: wgpu::BindGroup, + pub(crate) frame: Affine3A, + pub(crate) environment: Environment, + aspect_ratio: f32, + z_near: f32, + z_far: f32, + fov_y: f32, + pub(crate) environment_buffer: wgpu::Buffer, + pub(crate) buffer: wgpu::Buffer, + pub(crate) layout: wgpu::BindGroupLayout, + pub(crate) group: wgpu::BindGroup, } #[repr(C)] #[derive(Pod, Copy, Clone, Zeroable)] -pub struct Environment { - ambient: Vec4, - light: Vec4, - dir: Vec4, +struct Environment { + ambient: Vec4, + light: Vec4, + dir: Vec4, } impl Eye { - pub(crate) fn write(&mut self, queue: &Queue) { - let camera = Mat4::from_mat3_translation( - self.frame.matrix3.into(), - Vec3::from(self.frame.translation), - ); - let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far); - queue.write_buffer( - &self.camera_buffer, - 0, - bytemuck::cast_slice(&[ - projection, - camera * projection.inverse(), - camera.inverse(), - camera, - ]), - ); - queue.write_buffer( - &self.environment_buffer, - 0, - bytemuck::cast_slice(&[self.environment]), - ); - } - pub(crate) fn new(device: &Device, width: u32, height: u32, skybox: SimpleTexture) -> Eye { - let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Camera Buffer"), - contents: bytemuck::cast_slice(&[ - Mat4::from_translation(Vec3::new(0.0, 2.0, -8.0)), - Mat4::IDENTITY, - Mat4::IDENTITY, - Mat4::IDENTITY, - ]), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - }); + pub(crate) fn view(&self) -> Mat4 { + let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far); + projection * self.frame.inverse() + } + pub(crate) fn write(&mut self, queue: &Queue) { + queue.write_buffer(&self.buffer,0,bytemuck::cast_slice(&[ + self.view(), + Mat4::from_mat3_translation(self.frame.matrix3.into(), Vec3::from(self.frame.translation)) + ])); + queue.write_buffer(&self.environment_buffer,0,bytemuck::cast_slice(&[self.environment])); + } + pub(crate) fn new(device: &Device, width: u32, height: u32) -> Eye { + let buffer = device.create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Camera Buffer"), + contents: bytemuck::cast_slice(&[Mat4::from_translation(Vec3::new(0.0,2.0,-8.0)),Mat4::IDENTITY]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + } + ); - let dir = Vec3::new(1.0, 0.5, 1.0).normalize(); - let environment = Environment { - ambient: Vec4::new(0.15, 0.15, 0.15, 0.0), - light: Vec4::new(1.0, 1.0, 1.0, 0.0), - dir: Vec4::new(dir.x, dir.y, dir.z, 0.0), - }; + let dir = Vec3::new(1.0,0.5,1.0).normalize(); + let environment = Environment { + ambient: Vec4::new(0.15,0.15,0.15, 0.0), + light: Vec4::new(1.0,1.0,1.0, 0.0), + dir: Vec4::new(dir.x,dir.y,dir.z,0.0), + }; - let environment_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some(""), - contents: bytemuck::cast_slice(&[environment]), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - }); + let environment_buffer = device.create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some(""), + contents: bytemuck::cast_slice(&[environment]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + } + ); - let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - ], - label: Some("eye_bind_group_layout"), - }); - - let group = Eye::bind_group(&layout, device, &camera_buffer, &environment_buffer, skybox); - - Eye { - aspect_ratio: width as f32 / height as f32, - frame: Affine3A::IDENTITY, - fov_y: 90.0, - z_near: 0.1, - z_far: 1000.0, - camera_buffer, - group, - layout, - environment, - environment_buffer, + let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, } + ], + label: Some("eye_bind_group_layout"), + }); + + let group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: environment_buffer.as_entire_binding(), + } + ], + label: Some("eye_bind_group"), + }); + + Eye { + aspect_ratio: width as f32 / height as f32, + frame: Affine3A::IDENTITY, + fov_y: 90.0, + z_near: 0.1, + z_far: 1000.0, + buffer, + group, + layout, + environment, + environment_buffer, } - fn bind_group( - layout: &wgpu::BindGroupLayout, - device: &wgpu::Device, - camera: &wgpu::Buffer, - environment: &wgpu::Buffer, - skybox: SimpleTexture, - ) -> wgpu::BindGroup { - device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: camera.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: environment.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::Sampler( - &MaterialProperties::default().sampler(device), - ), - }, - wgpu::BindGroupEntry { - binding: 3, - resource: wgpu::BindingResource::TextureView(&skybox.view), - }, - ], - label: Some("eye_bind_group"), - }) - } - pub fn skybox(&mut self, device: &wgpu::Device, texture: SimpleTexture) { - self.group = Eye::bind_group( - &self.layout, - device, - &self.camera_buffer, - &self.environment_buffer, - texture, - ) - } - pub(crate) fn resize(&mut self, width: u32, height: u32) { - self.aspect_ratio = width as f32 / height as f32 - } - pub(crate) fn control(&mut self, delta: Vec3) { - self.frame *= Affine3A::from_translation(delta); - } - pub(crate) fn rotate(&mut self, yaw: f32, pitch: f32) { - let (mut y, mut x, z) = self.frame.matrix3.to_euler(EulerRot::YXZ); - x = (x + pitch * 0.005).clamp(-1.4, 1.4); - y += yaw * 0.005; - self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ, y, x, z); - } -} + } + pub(crate) fn resize(&mut self, width: u32, height: u32) { + self.aspect_ratio = width as f32 / height as f32 + } + pub(crate) fn control(&mut self, delta: Vec3) { + self.frame *= Affine3A::from_translation(delta); + } + pub(crate) fn rotate(&mut self, yaw: f32, pitch: f32) { + let (mut y,mut x,z) = self.frame.matrix3.to_euler(EulerRot::YXZ); + x = (x + pitch * 0.005).clamp(-1.4,1.4); + y += yaw * 0.005; + self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ,y,x,z); + } +} \ No newline at end of file diff --git a/src/render/mod.rs b/src/render/mod.rs index 2687354..b35b4a5 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,1251 +1,1043 @@ pub mod eye; -use crate::render::eye::Eye; -use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData}; -use bytemuck::{Pod, Zeroable}; -use glam::prelude::*; -use gltf::Semantic; -use image::EncodableLayout; use std::cell::RefCell; -use std::collections::HashMap; +use glam::prelude::*; +use std::collections::{HashMap}; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::hash::{BuildHasherDefault, Hash, Hasher}; -use std::ops::Range; +use std::ops::{Range}; use std::rc::Rc; use std::sync::Arc; +use bytemuck::{Pod, Zeroable}; +use gltf::{Gltf, Node, Semantic}; +use image::EncodableLayout; +use wgpu::{Device, Queue}; use wgpu::naga::{FastHashMap, FastHashSet}; use wgpu::util::DeviceExt; -use wgpu::{Device, Queue}; use winit::window::Window; +use crate::render::eye::Eye; +use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData}; -const DEFAULT_VERTICES: [SimpleVertex; 0] = []; +const DEFAULT_VERTICES: [SimpleVertex;0] = []; #[repr(C)] -#[derive(Pod, Zeroable, Copy, Clone)] +#[derive(Pod,Zeroable,Copy,Clone)] pub struct SimpleModelInstance { - pub transform: Mat4, - pub color: Vec4, - pub lights: [u16; 16], - pub point_lights: u32, - pub spot_lights: u32, - pub metal: f32, - pub rough: f32, + pub transform: Mat4, + pub color: Vec4, + pub lights: [u16;16], + pub point_lights: u32, + pub spot_lights: u32, + pub metal: f32, + pub rough: f32, } #[repr(C)] -#[derive(Pod, Copy, Clone, Zeroable)] +#[derive(Pod,Copy,Clone,Zeroable)] pub struct SimpleLightInstance { - pub location: Vec4, - pub rotation: Vec4, - pub color: Vec4, + pub location: Vec4, + pub rotation: Vec4, + pub color: Vec4, } #[derive(Clone)] pub struct SimpleLightData { - pub index: usize, - pub instance: SimpleLightInstance, - pub transform: Affine3, + pub index: usize, + pub instance: SimpleLightInstance, + pub transform: Affine3, } #[derive(Clone)] pub struct SimpleModelData { - pub instance: SimpleModelInstance, - pub material: Id, - pub mesh: Id, + pub instance: SimpleModelInstance, + pub material: Id, + pub mesh: Id, } pub struct SimpleInstances { - light_count: usize, - light_buffer: wgpu::Buffer, - instance_count: usize, - instance_buffer: wgpu::Buffer, - //light_ref_last: usize, - //light_ref_buffer: wgpu::Buffer, - objects: - FastHashMap, FastHashMap, FastHashSet>>, - lights: FastHashMap, + light_count: usize, + light_buffer: wgpu::Buffer, + instance_count: usize, + instance_buffer: wgpu::Buffer, + //light_ref_last: usize, + //light_ref_buffer: wgpu::Buffer, + objects: FastHashMap,FastHashMap,FastHashSet>>, + lights: FastHashMap, } enum SimpleRenderCode { - Material(wgpu::BindGroup), - Mesh((wgpu::Buffer, u32), Option<(wgpu::Buffer, u32)>), - Draw(Range), + Material(wgpu::BindGroup), + Mesh((wgpu::Buffer,u32),Option<(wgpu::Buffer,u32)>), + Draw(Range) } struct SimpleRenderProgram(Vec); impl SimpleRenderProgram { - fn push(&mut self, item: SimpleRenderCode) { - self.0.push(item) - } - fn new() -> SimpleRenderProgram { - SimpleRenderProgram(Vec::new()) - } - fn render(self, pass: &mut wgpu::RenderPass) { - let mut count = 0; - let mut indexed = false; - for code in self.0 { - match code { - SimpleRenderCode::Material(material) => pass.set_bind_group( - Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION, - &material, - &[], - ), - SimpleRenderCode::Mesh(vertices, indices) => { - pass.set_vertex_buffer(0, vertices.0.slice(..)); - if let Some(indices) = indices { - pass.set_index_buffer(indices.0.slice(..), wgpu::IndexFormat::Uint32); - count = indices.1; - indexed = true; - } else { - count = vertices.1; - indexed = false; - } - } - SimpleRenderCode::Draw(instances) => { - if indexed { - pass.draw_indexed(0..count, 0, instances) - } else { - pass.draw(0..count, instances); - } - } - } + fn push(&mut self, item: SimpleRenderCode) { + self.0.push(item) + } + fn new() -> SimpleRenderProgram { + SimpleRenderProgram(Vec::new()) + } + fn render(self, pass: &mut wgpu::RenderPass) { + let mut count = 0; + let mut indexed = false; + for code in self.0 { + match code { + SimpleRenderCode::Material(material) => { + pass.set_bind_group(Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,&material,&[]) } + SimpleRenderCode::Mesh(vertices,indices) => { + pass.set_vertex_buffer(0, vertices.0.slice(..)); + if let Some(indices) = indices { + pass.set_index_buffer(indices.0.slice(..),wgpu::IndexFormat::Uint32); + count = indices.1; + indexed = true; + } else { + count = vertices.1; + indexed = false; + } + } + SimpleRenderCode::Draw(instances) => { + if indexed { + pass.draw_indexed(0..count, 0, instances) + } else { + pass.draw(0..count, instances); + } + } + } } + } } impl SimpleInstances { - const MIN_SIZE: u64 = 64; - pub fn add_object(&mut self, object: SimpleObject) { - if let Some(ref model) = object.0.borrow().model { - self.instance_count += 1; - self.objects - .entry(model.mesh.clone()) - .or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) - .entry(model.material.clone()) - .or_insert(FastHashSet::with_hasher(BuildHasherDefault::new())) - .insert(object.clone()); - } + const MIN_SIZE: u64 = 64; + pub fn add_object(&mut self, object: SimpleObject) { + if let Some(ref model) = object.0.borrow().model { + self.instance_count += 1; + self.objects + .entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) + .entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new())) + .insert(object.clone()); } + } - pub fn remove_object(&mut self, object: SimpleObject) { - if let Some(ref model) = object.0.borrow().model { - self.instance_count -= 1; - self.objects - .entry(model.mesh.clone()) - .or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) - .entry(model.material.clone()) - .or_insert(FastHashSet::with_hasher(BuildHasherDefault::new())) - .remove(&object); - } + pub fn remove_object(&mut self, object: SimpleObject) { + if let Some(ref model) = object.0.borrow().model { + self.instance_count -= 1; + self.objects + .entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) + .entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new())) + .remove(&object); } + } - pub fn add_light(&mut self, light: SimpleLight) { - self.light_count += 1; - self.lights.insert(light, 0); - } + pub fn add_light(&mut self, light: SimpleLight) { + self.light_count += 1; + self.lights.insert(light,0); + } - pub fn remove_light(&mut self, light: &SimpleLight) { - self.light_count -= 1; - self.lights.remove(light); - } + pub fn remove_light(&mut self, light: &SimpleLight) { + self.light_count -= 1; + self.lights.remove(light); + } - pub fn reallocate_buffer( - device: &wgpu::Device, - buffer: &mut wgpu::Buffer, - count: usize, - item_size: usize, - ) { - let size = buffer.size() / item_size as wgpu::BufferAddress; - if count > SimpleInstances::MIN_SIZE as usize { - let mut reallocate: Option = None; - if count < (size / 2) as usize { - reallocate = Some(count / 2); - } else if count > size as usize { - reallocate = Some(count * 2); - } - if let Some(new_size) = reallocate { - *buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Instance Buffer"), - size: (item_size * new_size) as wgpu::BufferAddress, - usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, - mapped_at_creation: false, - }); - } - } - } - pub fn write_lights(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) { - //SimpleInstances::reallocate_buffer(device, queue, &mut self.light_ref_buffer, self.light_ref_last, size_of::()); - /* - let mut light_ref_buffer = queue.write_buffer_with( - &self.light_ref_buffer, - 0 as wgpu::BufferAddress, - wgpu::BufferSize::new(self.instance_buffer.size()).unwrap() - ).unwrap(); - */ - SimpleInstances::reallocate_buffer( - device, - &mut self.light_buffer, - self.light_count, - size_of::(), - ); - let mut buffer = queue - .write_buffer_with( - &self.light_buffer, - 0 as wgpu::BufferAddress, - wgpu::BufferSize::new(self.light_buffer.size()).unwrap(), - ) - .unwrap(); - let stride = size_of::(); - for (new_index, (light, index)) in self.lights.iter_mut().enumerate() { - *index = new_index + 1; - let begin = *index * stride; - buffer - .slice(begin..begin + stride) - .copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance])); - } - } - fn write_instances( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - ) -> SimpleRenderProgram { - let mut program = SimpleRenderProgram::new(); - SimpleInstances::reallocate_buffer( - device, - &mut self.instance_buffer, - self.instance_count, - size_of::(), - ); - let mut buffer = queue - .write_buffer_with( - &self.instance_buffer, - 0 as wgpu::BufferAddress, - wgpu::BufferSize::new(self.instance_buffer.size()).unwrap(), - ) - .unwrap(); - let mut index: u32 = 0; - let stride = size_of::(); - for (mesh, materials) in self.objects.iter() { - program.push(SimpleRenderCode::Mesh( - mesh.it.vertices.clone(), - mesh.it.indices.clone(), - )); - for (material, objects) in materials.iter() { - program.push(SimpleRenderCode::Material(material.it.group.clone())); - let before = index; - for object in objects.iter() { - let begin = index as usize * stride; - buffer - .slice(begin..begin + stride) - .copy_from_slice(bytemuck::cast_slice(&[object - .0 - .borrow() - .model - .as_ref() - .unwrap() - .instance])); - index += 1; - } - program.push(SimpleRenderCode::Draw(Range::from(before..index))); - } - } - program - } - - fn desc() -> wgpu::VertexBufferLayout<'static> { - wgpu::VertexBufferLayout { - array_stride: size_of::() as wgpu::BufferAddress, - step_mode: wgpu::VertexStepMode::Instance, - attributes: &[ - // todo: is this too big? - wgpu::VertexAttribute { - offset: 0, - shader_location: 4, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 4]>() as wgpu::BufferAddress, - shader_location: 5, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 8]>() as wgpu::BufferAddress, - shader_location: 6, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 12]>() as wgpu::BufferAddress, - shader_location: 7, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, - shader_location: 8, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, - shader_location: 9, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, - shader_location: 10, - format: wgpu::VertexFormat::Float32x4, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, - shader_location: 11, - format: wgpu::VertexFormat::Float32x4, - }, - ], - } - } - - pub fn new(device: &wgpu::Device) -> SimpleInstances { - let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Instance Buffer"), - size: (size_of::() * SimpleInstances::MIN_SIZE as usize) - as wgpu::BufferAddress, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, + pub fn reallocate_buffer(device: &wgpu::Device, queue: &wgpu::Queue, buffer: &mut wgpu::Buffer, count: usize, item_size: usize) { + let size = buffer.size() / item_size as wgpu::BufferAddress; + if count > SimpleInstances::MIN_SIZE as usize { + let mut reallocate: Option = None; + if count < (size / 2) as usize { + reallocate = Some(count / 2); + } else if count > size as usize { + reallocate = Some(count * 2); + } + if let Some(new_size) = reallocate { + *buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Instance Buffer"), + size: (item_size * new_size) as wgpu::BufferAddress, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, + mapped_at_creation: false, }); - let light_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Light Buffer"), - size: (size_of::() * SimpleInstances::MIN_SIZE as usize) - as wgpu::BufferAddress, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - /*let light_ref_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Light Ref Buffer"), - size: (size_of::() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - });*/ - SimpleInstances { - light_count: 0, - //light_ref_last: 0, - instance_count: 0, - light_buffer, - instance_buffer, - //light_ref_buffer, - objects: FastHashMap::with_hasher(BuildHasherDefault::new()), - lights: Default::default(), - } + } } + } + pub fn write_lights(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) { + //SimpleInstances::reallocate_buffer(device, queue, &mut self.light_ref_buffer, self.light_ref_last, size_of::()); + /* + let mut light_ref_buffer = queue.write_buffer_with( + &self.light_ref_buffer, + 0 as wgpu::BufferAddress, + wgpu::BufferSize::new(self.instance_buffer.size()).unwrap() + ).unwrap(); + */ + SimpleInstances::reallocate_buffer(device, queue, &mut self.light_buffer, self.light_count, size_of::()); + let mut buffer = queue.write_buffer_with( + &self.light_buffer, + 0 as wgpu::BufferAddress, + wgpu::BufferSize::new(self.light_buffer.size()).unwrap(), + ).unwrap(); + let stride = size_of::(); + for (new_index,(light,index)) in self.lights.iter_mut().enumerate() { + *index = new_index + 1; + let begin = *index * stride; + buffer.slice(begin..begin + stride).copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance])); + } + } + pub fn write_instances(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> SimpleRenderProgram { + let mut program = SimpleRenderProgram::new(); + SimpleInstances::reallocate_buffer(device, queue, &mut self.instance_buffer, self.instance_count, size_of::()); + let mut buffer = queue.write_buffer_with( + &self.instance_buffer, + 0 as wgpu::BufferAddress, + wgpu::BufferSize::new(self.instance_buffer.size()).unwrap() + ).unwrap(); + let mut index: u32 = 0; + let stride = size_of::(); + for (mesh,materials) in self.objects.iter() { + program.push(SimpleRenderCode::Mesh(mesh.it.vertices.clone(), mesh.it.indices.clone())); + for (material, objects) in materials.iter() { + program.push(SimpleRenderCode::Material(material.it.group.clone())); + let before = index; + for object in objects.iter() { + let begin = index as usize * stride; + buffer.slice(begin .. begin + stride).copy_from_slice(bytemuck::cast_slice(&[object.0.borrow().model.as_ref().unwrap().instance])); + index += 1; + } + program.push(SimpleRenderCode::Draw(Range::from(before..index))); + } + }; + program + } + + fn desc() -> wgpu::VertexBufferLayout<'static> { + use std::mem; + wgpu::VertexBufferLayout { + array_stride: size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &[ // todo: is this too big? + wgpu::VertexAttribute { + offset: 0, + shader_location: 4, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 4]>() as wgpu::BufferAddress, + shader_location: 5, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 8]>() as wgpu::BufferAddress, + shader_location: 6, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 12]>() as wgpu::BufferAddress, + shader_location: 7, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, + shader_location: 8, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, + shader_location: 9, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, + shader_location: 10, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 16]>() as wgpu::BufferAddress, + shader_location: 11, + format: wgpu::VertexFormat::Float32x4, + }, + ], + } + } + + pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> SimpleInstances { + let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Instance Buffer"), + size: (size_of::() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let light_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Light Buffer"), + size: (size_of::() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let light_ref_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Light Ref Buffer"), + size: (size_of::() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false + }); + SimpleInstances { + light_count: 0, + //light_ref_last: 0, + instance_count: 0, + light_buffer, + instance_buffer, + //light_ref_buffer, + objects: FastHashMap::with_hasher(BuildHasherDefault::new()), + lights: Default::default(), + } + } } pub struct Renderer { - id_count: u64, - surface: wgpu::Surface<'static>, - config: wgpu::SurfaceConfiguration, - device: wgpu::Device, - queue: wgpu::Queue, - pub(crate) eye: eye::Eye, - material_layout: wgpu::BindGroupLayout, - default_texture: SimpleTexture, - default_material: SimpleMaterial, - sky_pipeline: wgpu::RenderPipeline, - instance_pipeline: wgpu::RenderPipeline, - depth_texture: SimpleTexture, - pub(crate) instances: SimpleInstances, + id_count: u64, + surface: wgpu::Surface<'static>, + config: wgpu::SurfaceConfiguration, + device: wgpu::Device, + queue: wgpu::Queue, + pub(crate) eye: eye::Eye, + material_layout: wgpu::BindGroupLayout, + default_texture: SimpleTexture, + pipeline: wgpu::RenderPipeline, + depth_texture: SimpleTexture, + pub(crate) instances: SimpleInstances, } #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] struct SimpleVertex { - position: [f32; 3], - normal: [f32; 3], - tex_coord: [f32; 2], - tangent: [f32; 3], - bitangent: [f32; 3], + position: [f32; 3], + normal: [f32; 3], + tex_coord: [f32; 2], + tangent: [f32; 3], + bitangent: [f32; 3], } impl SimpleVertex { - fn desc() -> wgpu::VertexBufferLayout<'static> { - wgpu::VertexBufferLayout { - array_stride: size_of::() as wgpu::BufferAddress, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &[ - wgpu::VertexAttribute { - offset: 0, - shader_location: 0, - format: wgpu::VertexFormat::Float32x3, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 3]>() as wgpu::BufferAddress, - shader_location: 1, - format: wgpu::VertexFormat::Float32x3, - }, - wgpu::VertexAttribute { - offset: size_of::<[f32; 6]>() as wgpu::BufferAddress, - shader_location: 2, - format: wgpu::VertexFormat::Float32x2, - }, - ], + fn desc() -> wgpu::VertexBufferLayout<'static> { + wgpu::VertexBufferLayout { + array_stride: size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 3]>() as wgpu::BufferAddress, + shader_location: 1, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 6]>() as wgpu::BufferAddress, + shader_location: 2, + format: wgpu::VertexFormat::Float32x2, } + ] } + } } #[derive(Debug, Clone, PartialEq)] pub struct SimpleMesh { - indices: Option<(wgpu::Buffer, u32)>, - vertices: (wgpu::Buffer, u32), + indices: Option<(wgpu::Buffer,u32)>, + vertices: (wgpu::Buffer, u32), } #[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct SimpleTexture { - texture: wgpu::Texture, - view: wgpu::TextureView, +pub(crate) struct SimpleTexture { + texture: wgpu::Texture, + view: wgpu::TextureView, } -pub struct TextureProperties { - width: u32, - height: u32, +struct TextureProperties { + width: u32, + height: u32, } -// todo: use texture compression! impl SimpleTexture { - pub fn load( - device: &Device, - queue: &Queue, - slice: impl AsRef<[u8]>, - properties: TextureProperties, - ) -> SimpleTexture { - let size = wgpu::Extent3d { - width: properties.width, - height: properties.height, - depth_or_array_layers: 1, - }; - let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor { - size, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - label: Some("texture"), - view_formats: &[], - }); - let diffuse_texture_view = - diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default()); - queue.write_texture( - wgpu::TexelCopyTextureInfo { - texture: &diffuse_texture, - mip_level: 0, - origin: wgpu::Origin3d::ZERO, - aspect: wgpu::TextureAspect::All, - }, - slice.as_ref(), - wgpu::TexelCopyBufferLayout { - offset: 0, - bytes_per_row: Some(4 * size.width), - rows_per_image: Some(size.height), - }, - size, - ); - SimpleTexture { - texture: diffuse_texture, - view: diffuse_texture_view, - } + pub fn load(device: &Device, queue: &Queue, slice: impl AsRef<[u8]>, properties: TextureProperties) -> SimpleTexture { + let size = wgpu::Extent3d { + width: properties.width, + height: properties.height, + depth_or_array_layers: 1, + }; + let diffuse_texture = device.create_texture( + &wgpu::TextureDescriptor { + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + label: Some("texture"), + view_formats: &[], + } + ); + let diffuse_texture_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default()); + queue.write_texture( + wgpu::TexelCopyTextureInfo { + texture: &diffuse_texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + slice.as_ref(), + wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(4 * size.width), + rows_per_image: Some(size.height), + }, + size, + ); + SimpleTexture { + texture: diffuse_texture, + view: diffuse_texture_view, } + } } #[derive(Clone)] pub struct SimpleMaterial { - group: wgpu::BindGroup, + group: wgpu::BindGroup, } #[derive(Clone)] pub struct Id { - id: u64, - it: T, + id: u64, + it: T, } impl Hash for Id { - fn hash(&self, state: &mut H) { - self.id.hash(state) - } + fn hash(&self, state: &mut H) { + self.id.hash(state) + } } impl PartialEq for Id { - fn eq(&self, other: &Self) -> bool { - other.id == self.id - } + fn eq(&self, other: &Self) -> bool { + other.id == self.id + } } impl Eq for Id {} struct MaterialProperties { - edge: wgpu::AddressMode, - filter: wgpu::FilterMode, -} - -impl Default for MaterialProperties { - fn default() -> MaterialProperties { - MaterialProperties { - edge: wgpu::AddressMode::Repeat, - filter: wgpu::FilterMode::Linear, - } - } -} - -impl MaterialProperties { - fn sampler(&self, device: &wgpu::Device) -> wgpu::Sampler { - device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: self.edge, - address_mode_v: self.edge, - address_mode_w: self.edge, - mag_filter: self.filter, - min_filter: self.filter, - mipmap_filter: wgpu::MipmapFilterMode::Nearest, - ..Default::default() - }) - } + edge: wgpu::AddressMode, + filter: wgpu::FilterMode, } impl SimpleMaterial { - fn new( - device: &wgpu::Device, - layout: &wgpu::BindGroupLayout, - base: &SimpleTexture, - normal: &SimpleTexture, - reflect: &SimpleTexture, - config: MaterialProperties, - ) -> SimpleMaterial { - let sampler = config.sampler(&device); - let group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Sampler(&sampler), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::TextureView(&base.view), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::TextureView(&normal.view), - }, - wgpu::BindGroupEntry { - binding: 3, - resource: wgpu::BindingResource::TextureView(&reflect.view), - }, - ], - label: Some("diffuse_bind_group"), - }); - SimpleMaterial { group } + fn new(renderer: &Renderer, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture, config: MaterialProperties) -> SimpleMaterial { + let sampler = renderer.device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: config.edge, + address_mode_v: config.edge, + address_mode_w: config.edge, + mag_filter: config.filter, + min_filter: config.filter, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, + ..Default::default() + }); + let group = renderer.device.create_bind_group( + &wgpu::BindGroupDescriptor { + layout: &renderer.material_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&base.view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::TextureView(&normal.view), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: wgpu::BindingResource::TextureView(&reflect.view), + }, + ], + label: Some("diffuse_bind_group"), + } + ); + SimpleMaterial { + group, } + } } #[derive(Debug)] struct PoolError(String); impl Display for PoolError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f,"{}",self.0) + } } impl Error for PoolError {} pub struct SimpleTreeNode { - object: Option, - children: Vec, - name: String, + object: Option, + children: Vec, + name: String, } impl SimpleTreeNode { - pub fn first_object(&self) -> Option { - if let Some(object) = self.object.clone() { - Some(object) - } else { - for child in self.children.iter() { - if let Some(object) = child.first_object() { - return Some(object); - } - } - None + pub fn first_object(&self) -> Option { + if let Some(object) = self.object.clone() { + Some(object) + } else { + for child in self.children.iter() { + if let Some(object) = child.first_object() { + return Some(object) } + } + None } + } } -type GltfVertexBufferKey = (Option, Option, Option, Option); +type GltfVertexBufferKey = (Option,Option,Option,Option); impl Renderer { - const SIMPLE_RENDER_EYE_GROUP_POSITION: u32 = 0; - const SIMPLE_RENDER_TEXTURE_GROUP_POSITION: u32 = 1; - const SIMPLE_RENDER_MODEL_GROUP_POSITION: u32 = 2; - pub fn new_id(&mut self, value: T) -> Id { - self.id_count += 1; - Id { - it: value, - id: self.id_count, - } + const SIMPLE_RENDER_EYE_GROUP_POSITION: u32 = 0; + const SIMPLE_RENDER_TEXTURE_GROUP_POSITION: u32 = 1; + const SIMPLE_RENDER_MODEL_GROUP_POSITION: u32 = 2; + pub fn new_id(&mut self, value: T) -> Id { + self.id_count += 1; + Id { + it: value, + id: self.id_count, } - pub fn load_texture_from_bytes( - &mut self, - slice: impl AsRef<[u8]>, - format: Option, - ) -> SimpleTexture { - let image = if let Some(format) = format { - image::load_from_memory_with_format(slice.as_ref(), format) - } else { - image::load_from_memory(slice.as_ref()) - }; - if let Ok(data) = image { - let data = data.into_rgba8(); - SimpleTexture::load( - &self.device, - &self.queue, - data.as_bytes(), - TextureProperties { - width: data.width(), - height: data.height(), - }, - ) - } else { - println!("failed to load texture! error: {:?}", image.unwrap_err()); - self.default_texture.clone() - } + } + pub fn load_texture_from_bytes(&mut self, slice: impl AsRef<[u8]>) -> SimpleTexture { + let image = image::load_from_memory(slice.as_ref()); + if let Ok(data) = image { + let data = data.into_rgba8(); + SimpleTexture::load(&self.device, &self.queue, data.as_bytes(), TextureProperties { + width: data.width(), + height: data.height(), + }) + } else { + self.default_texture.clone() } - pub fn new_material( - &mut self, - base: &SimpleTexture, - normal: &SimpleTexture, - reflect: &SimpleTexture, - ) -> Id { - self.new_id(SimpleMaterial::new( - &self.device, - &self.material_layout, - base, - normal, - reflect, - MaterialProperties { - edge: wgpu::AddressMode::Repeat, - filter: wgpu::FilterMode::Linear, + } + pub fn new_material(&mut self, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture) -> Id { + self.new_id(SimpleMaterial::new(self, base, normal, reflect, MaterialProperties { + edge: wgpu::AddressMode::Repeat, + filter: wgpu::FilterMode::Linear, + })) + } + pub fn new_texture_from_gltf(&mut self, info: &gltf::texture::Texture, images: &Vec) -> SimpleTexture { + if let Some(image) = images.get(info.source().index()) { + let mut new_pixels = Vec::new(); + let pixels: &Vec; + match image.format { + gltf::image::Format::R8G8B8 => { + for pixel in image.pixels.chunks(3) { + new_pixels.push(pixel[0]); + new_pixels.push(pixel[0]); + new_pixels.push(pixel[0]); + new_pixels.push(255); + } + pixels = &new_pixels; + } + gltf::image::Format::R8G8B8A8 => { + pixels = &image.pixels + } + _ => return self.default_texture.clone() + } + SimpleTexture::load(&self.device, &self.queue, pixels.as_slice(), TextureProperties { + width: image.width, + height: image.height, + }) + } else { + self.default_texture.clone() + } + } + pub fn new_mesh_from_gltf( + &mut self, + primitive: gltf::Primitive, + meshes: &mut HashMap, + buffers: &[gltf::buffer::Data] + ) -> Id { + let position_index = primitive.get(&Semantic::Positions).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); + let normals_index = primitive.get(&Semantic::Normals).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); + let tex_coords_index = primitive.get(&Semantic::TexCoords(0)).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); + let indices_index = primitive.indices().and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); + let tangent_index = primitive.get(&Semantic::Tangents).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); + let key = (position_index,normals_index,tex_coords_index,indices_index); + self.new_id(meshes.entry(key).or_insert_with(|| { + let mut tangents = false; + let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()])); + let mut vertex_data: Vec; + if let Some(positions) = reader.read_positions() { + vertex_data = Vec::with_capacity(positions.len()); + let mut normal = reader.read_normals().map(|it| it.into_iter()); + let mut tex_coord = reader.read_tex_coords(0).map(|it| it.into_f32().into_iter()); + let mut tangent = reader.read_tangents().map(|it| it.into_iter()); + tangents = tangent.is_some(); + for position in positions { + vertex_data.push(SimpleVertex { + position, + normal: if let Some(ref mut normals) = normal { + if let Some(normal) = normals.next() { + normal + } else { + [0.0;3] + } + } else { + [0.0;3] }, - )) - } - pub fn new_texture_from_gltf( - &mut self, - info: &gltf::texture::Texture, - images: &Vec, - ) -> SimpleTexture { - if let Some(image) = images.get(info.source().index()) { - let mut new_pixels = Vec::new(); - let pixels: &Vec; - match image.format { - gltf::image::Format::R8G8B8 => { - for pixel in image.pixels.chunks(3) { - new_pixels.push(pixel[0]); - new_pixels.push(pixel[0]); - new_pixels.push(pixel[0]); - new_pixels.push(255); - } - pixels = &new_pixels; - } - gltf::image::Format::R8G8B8A8 => pixels = &image.pixels, - _ => return self.default_texture.clone(), - } - SimpleTexture::load( - &self.device, - &self.queue, - pixels.as_slice(), - TextureProperties { - width: image.width, - height: image.height, - }, - ) - } else { - self.default_texture.clone() + tex_coord: if let Some(ref mut tex_coords) = tex_coord { + tex_coords.next() + } else { + None + }.unwrap_or([0.0;2]), + tangent: [0.0;3], // todo: tangent from model + bitangent: [0.0;3], + }) } - } - pub fn new_mesh_from_gltf( - &mut self, - primitive: gltf::Primitive, - meshes: &mut HashMap, - buffers: &[gltf::buffer::Data], - ) -> Id { - let position_index = primitive - .get(&Semantic::Positions) - .and_then(|it| it.view()) - .and_then(|it| Some(it.buffer().index())); - let normals_index = primitive - .get(&Semantic::Normals) - .and_then(|it| it.view()) - .and_then(|it| Some(it.buffer().index())); - let tex_coords_index = primitive - .get(&Semantic::TexCoords(0)) - .and_then(|it| it.view()) - .and_then(|it| Some(it.buffer().index())); - let indices_index = primitive - .indices() - .and_then(|it| it.view()) - .and_then(|it| Some(it.buffer().index())); - let tangent_index = primitive - .get(&Semantic::Tangents) - .and_then(|it| it.view()) - .and_then(|it| Some(it.buffer().index())); - let key = ( - position_index, - normals_index, - tex_coords_index, - indices_index, - ); - self.new_id( - meshes - .entry(key) - .or_insert_with(|| { - let mut tangents = false; - let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()])); - let mut vertex_data: Vec; - if let Some(positions) = reader.read_positions() { - vertex_data = Vec::with_capacity(positions.len()); - let mut normal = reader.read_normals().map(|it| it.into_iter()); - let mut tex_coord = reader - .read_tex_coords(0) - .map(|it| it.into_f32().into_iter()); - let mut tangent = reader.read_tangents().map(|it| it.into_iter()); - tangents = tangent.is_some(); - for position in positions { - vertex_data.push(SimpleVertex { - position, - normal: if let Some(ref mut normals) = normal { - if let Some(normal) = normals.next() { - normal - } else { - [0.0; 3] - } - } else { - [0.0; 3] - }, - tex_coord: if let Some(ref mut tex_coords) = tex_coord { - tex_coords.next() - } else { - None - } - .unwrap_or([0.0; 2]), - tangent: [0.0; 3], // todo: tangent from model - bitangent: [0.0; 3], - }) - } - } else { - vertex_data = Vec::new(); - } - let vertex_buffer = - self.device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Vertex Buffer"), - contents: bytemuck::cast_slice(vertex_data.as_slice()), - usage: wgpu::BufferUsages::VERTEX, - }); - let vertices_result = (vertex_buffer, vertex_data.len() as u32); - let indices_result = if let Some(indices) = reader.read_indices() { - let index_data: Vec = indices.into_u32().collect(); - Some(( - self.device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Index Buffer"), - contents: bytemuck::cast_slice(index_data.as_slice()), - usage: wgpu::BufferUsages::INDEX, - }), - index_data.len() as u32, - )) - } else { - None - }; - SimpleMesh { - indices: indices_result, - vertices: vertices_result, - } - }) - .clone(), - ) - } - pub fn load_node_from_gltf( - &mut self, - node: gltf::Node, - meshes: &mut HashMap, - textures: &mut HashMap, - images: &Vec, - buffers: &Vec, - ) -> SimpleTreeNode { - let mut tree_node = SimpleTreeNode { - object: None, + } else { + vertex_data = Vec::new(); + } + let vertex_buffer = self.device.create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Vertex Buffer"), + contents: bytemuck::cast_slice(vertex_data.as_slice()), + usage: wgpu::BufferUsages::VERTEX, + } + ); + let vertices_result = (vertex_buffer,vertex_data.len() as u32); + let indices_result = if let Some(indices) = reader.read_indices() { + let index_data: Vec = indices.into_u32().collect(); + Some((self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Index Buffer"), + contents: bytemuck::cast_slice(index_data.as_slice()), + usage: wgpu::BufferUsages::INDEX, + }), index_data.len() as u32)) + } else { + None + }; + SimpleMesh { + indices: indices_result, + vertices: vertices_result + } + }).clone()) + } + pub fn load_node_from_gltf( + &mut self, + node: gltf::Node, + meshes: &mut HashMap, + textures: &mut HashMap, + images: &Vec, + buffers: &Vec, + ) -> SimpleTreeNode { + let mut tree_node = SimpleTreeNode { + object: None, + children: Vec::new(), + name: node.name().unwrap_or("Node").to_string() + }; + if let Some(mesh) = node.mesh() { + let len = mesh.primitives().len(); + for primitive in mesh.primitives() { + let pbr = primitive.material().pbr_metallic_roughness(); + let material = primitive.material(); + let color = pbr.base_color_factor(); + let metal = pbr.metallic_factor(); + let rough = pbr.roughness_factor(); + let light = primitive.material().emissive_factor(); + let base = match pbr.base_color_texture() { + Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(), + None => self.default_texture.clone() + }; + let reflect = match pbr.metallic_roughness_texture() { + Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(), + None => self.default_texture.clone() + }; + let normal = match material.normal_texture() { + Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(), + None => self.default_texture.clone() + }; + let material = self.new_material(&base, &normal, &reflect); + let mesh = self.new_mesh_from_gltf(primitive,meshes,buffers); + let object = SimpleObject(Rc::new(RefCell::new(SimpleObjectData { + model: Some(SimpleModelData { + instance: SimpleModelInstance { + transform: Mat4::default(), + color: Vec4::from_array(color), + lights: [0;16], + point_lights: 0, + spot_lights: 0, + metal, + rough, + }, + material, + mesh, + }), + collider: SimpleColliderData { + transform: Mat4::default(), + shape: Shape::None, + radius: 0.0, + }, + }))); + if len == 1 { + tree_node.object = Some(object); + } else { + tree_node.children.push(SimpleTreeNode { + object: Some(object), children: Vec::new(), - name: node.name().unwrap_or("Node").to_string(), - }; - if let Some(mesh) = node.mesh() { - let len = mesh.primitives().len(); - for primitive in mesh.primitives() { - let pbr = primitive.material().pbr_metallic_roughness(); - let material = primitive.material(); - let color = pbr.base_color_factor(); - let metal = pbr.metallic_factor(); - let rough = pbr.roughness_factor(); - let light = primitive.material().emissive_factor(); - let base = match pbr.base_color_texture() { - Some(info) => textures - .entry(info.texture().source().index()) - .or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)) - .clone(), - None => self.default_texture.clone(), - }; - let reflect = match pbr.metallic_roughness_texture() { - Some(info) => textures - .entry(info.texture().source().index()) - .or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)) - .clone(), - None => self.default_texture.clone(), - }; - let normal = match material.normal_texture() { - Some(info) => textures - .entry(info.texture().source().index()) - .or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)) - .clone(), - None => self.default_texture.clone(), - }; - let material = self.new_material(&base, &normal, &reflect); - let mesh = self.new_mesh_from_gltf(primitive, meshes, buffers); - let object = SimpleObject(Rc::new(RefCell::new(SimpleObjectData { - model: Some(SimpleModelData { - instance: SimpleModelInstance { - transform: Mat4::default(), - color: Vec4::from_array(color), - lights: [0; 16], - point_lights: 0, - spot_lights: 0, - metal, - rough, - }, - material, - mesh, - }), - collider: SimpleColliderData { - transform: Mat4::default(), - shape: Shape::None, - radius: 0.0, - }, - }))); - if len == 1 { - tree_node.object = Some(object); - } else { - tree_node.children.push(SimpleTreeNode { - object: Some(object), - children: Vec::new(), - name: "Primitive".to_string(), - }) - } - } + name: "Primitive".to_string() + }) } - for node in node.children() { - tree_node - .children - .push(self.load_node_from_gltf(node, meshes, textures, images, buffers)); + } + } + for node in node.children() { + tree_node.children.push(self.load_node_from_gltf(node,meshes,textures,images,buffers)); + } + tree_node + } + pub fn load_from_gltf(&mut self, slice: impl AsRef<[u8]>) -> SimpleTreeNode { + let mut root = SimpleTreeNode { + object: None, + children: Vec::new(), + name: "Root".to_string(), + }; + if let Ok((document, buffers, images)) = gltf::import_slice(slice) { + let mut meshes: HashMap = HashMap::new(); + let mut textures: HashMap = HashMap::new(); + for scene in document.scenes() { + let mut scene_node = SimpleTreeNode { + object: None, + children: Vec::new(), + name: scene.name().unwrap_or("Scene").to_string(), + }; + for node in scene.nodes() { + scene_node.children.push(self.load_node_from_gltf(node, &mut meshes, &mut textures, &images, &buffers)); } - tree_node + root.children.push(scene_node) + } } - pub fn load_from_gltf(&mut self, slice: impl AsRef<[u8]>) -> SimpleTreeNode { - let mut root = SimpleTreeNode { - object: None, - children: Vec::new(), - name: "Root".to_string(), - }; - if let Ok((document, buffers, images)) = gltf::import_slice(slice) { - let mut meshes: HashMap = HashMap::new(); - let mut textures: HashMap = HashMap::new(); - for scene in document.scenes() { - let mut scene_node = SimpleTreeNode { - object: None, - children: Vec::new(), - name: scene.name().unwrap_or("Scene").to_string(), - }; - for node in scene.nodes() { - scene_node.children.push(self.load_node_from_gltf( - node, - &mut meshes, - &mut textures, - &images, - &buffers, - )); - } - root.children.push(scene_node) - } + root + } + pub fn resize(&mut self, width: u32, height: u32) { + self.surface.configure(&self.device, &self.config); + self.eye.resize(width, height); + } + pub async fn new(window: &Arc) -> anyhow::Result { + let bounds = window.inner_size(); + let width = bounds.width; + let height = bounds.height; + // The instance is a handle to our GPU + // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + #[cfg(not(target_arch = "wasm32"))] + backends: wgpu::Backends::PRIMARY, + #[cfg(target_arch = "wasm32")] + backends: wgpu::Backends::GL, + flags: Default::default(), + memory_budget_thresholds: Default::default(), + backend_options: Default::default(), + display: None, + }); + + let surface = instance.create_surface(window.clone())?; + + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + compatible_surface: Some(&surface), + force_fallback_adapter: false, + }) + .await?; + + let (device, queue) = adapter + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + experimental_features: wgpu::ExperimentalFeatures::disabled(), + // WebGL doesn't support all of wgpu's features, so if + // we're building for the web we'll have to disable some. + required_limits: if cfg!(target_arch = "wasm32") { + wgpu::Limits::downlevel_webgl2_defaults() + } else { + wgpu::Limits::default() + }, + memory_hints: Default::default(), + trace: wgpu::Trace::Off, + }) + .await?; + + let surface_caps = surface.get_capabilities(&adapter); + // Shader code in this tutorial assumes an sRGB surface texture. Using a different + // one will result in all the colors coming out darker. If you want to support non + // sRGB surfaces, you'll need to account for that when drawing to the frame. + let surface_format = surface_caps + .formats + .iter() + .find(|f| f.is_srgb()) + .copied() + .unwrap_or(surface_caps.formats[0]); + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width, + height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + desired_maximum_frame_latency: 2, + }; + + let eye = Eye::new(&device, width, height); + + let shader = device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl")); + + let texture = SimpleTexture::load(&device, &queue, [255,255,255,255], TextureProperties { + width: 1, + height: 1, + }); + + let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + }, + count: None, } - root - } - pub fn resize(&mut self, width: u32, height: u32) { - self.surface.configure(&self.device, &self.config); - self.eye.resize(width, height); - } - pub fn set_skybox(&mut self, skybox: SimpleTexture) { - self.eye.skybox(&self.device, skybox); - } - pub async fn new(window: &Arc) -> anyhow::Result { - let bounds = window.inner_size(); - let width = bounds.width; - let height = bounds.height; - // The instance is a handle to our GPU - // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - #[cfg(not(target_arch = "wasm32"))] - backends: wgpu::Backends::PRIMARY, - #[cfg(target_arch = "wasm32")] - backends: wgpu::Backends::GL, - flags: Default::default(), - memory_budget_thresholds: Default::default(), - backend_options: Default::default(), - display: None, - }); + ], + label: Some("texture_bind_group_layout"), + }); - let surface = instance.create_surface(window.clone())?; + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + bind_group_layouts: &[ + Some(&eye.layout), + Some(&texture_bind_group_layout), + ], + immediate_size: 0, + }); - let adapter = instance - .request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::default(), - compatible_surface: Some(&surface), - force_fallback_adapter: false, - }) - .await?; + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: Some("vs_main"), + buffers: &[ + SimpleVertex::desc(),SimpleInstances::desc(), + ], + compilation_options: wgpu::PipelineCompilationOptions::default(), + }, + fragment: Some(wgpu::FragmentState { + // 3. + module: &shader, + entry_point: Some("fs_main"), + targets: &[Some(wgpu::ColorTargetState { + // 4. + format: config.format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + compilation_options: wgpu::PipelineCompilationOptions::default(), + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: Some(true), + depth_compare: Some(wgpu::CompareFunction::Less), + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview_mask: None, + cache: None, + }); - let (device, queue) = adapter - .request_device(&wgpu::DeviceDescriptor { - label: None, - required_features: wgpu::Features::empty(), - experimental_features: wgpu::ExperimentalFeatures::disabled(), - // WebGL doesn't support all of wgpu's features, so if - // we're building for the web we'll have to disable some. - required_limits: if cfg!(target_arch = "wasm32") { - wgpu::Limits::downlevel_webgl2_defaults() - } else { - wgpu::Limits::default() - }, - memory_hints: Default::default(), - trace: wgpu::Trace::Off, - }) - .await?; - - let surface_caps = surface.get_capabilities(&adapter); - // Shader code in this tutorial assumes an sRGB surface texture. Using a different - // one will result in all the colors coming out darker. If you want to support non - // sRGB surfaces, you'll need to account for that when drawing to the frame. - let surface_format = surface_caps - .formats - .iter() - .find(|f| f.is_srgb()) - .copied() - .unwrap_or(surface_caps.formats[0]); - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width, - height, - present_mode: surface_caps.present_modes[0], - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - desired_maximum_frame_latency: 2, - }; - - let shader = - device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl")); - - let default_texture = SimpleTexture::load( - &device, - &queue, - [0, 0, 255, 255], - TextureProperties { - width: 1, - height: 1, - }, - ); - - let eye = Eye::new(&device, width, height, default_texture.clone()); - let texture_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - ], - label: Some("texture_bind_group_layout"), - }); - - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Render Pipeline Layout"), - bind_group_layouts: &[Some(&eye.layout), Some(&texture_bind_group_layout)], - immediate_size: 0, - }); - - let instance_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Render Pipeline"), - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: Some("vs_main"), - buffers: &[SimpleVertex::desc(), SimpleInstances::desc()], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }, - fragment: Some(wgpu::FragmentState { - // 3. - module: &shader, - entry_point: Some("fs_main"), - targets: &[Some(wgpu::ColorTargetState { - // 4. - format: config.format, - blend: Some(wgpu::BlendState::REPLACE), - write_mask: wgpu::ColorWrites::ALL, - })], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }), - primitive: Default::default(), /*wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }*/ - depth_stencil: Some(wgpu::DepthStencilState { - stencil: wgpu::StencilState::default(), - format: wgpu::TextureFormat::Depth32Float, - depth_write_enabled: Some(true), - depth_compare: Some(wgpu::CompareFunction::Less), - bias: wgpu::DepthBiasState::default(), - }), - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview_mask: None, - cache: None, - }); - - //todo: use a pipeline cache! - let sky_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Sky Pipeline"), - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: Some("vs_sky"), - compilation_options: Default::default(), - buffers: &[], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: Some("fs_sky"), - compilation_options: Default::default(), - targets: &[Some(wgpu::ColorTargetState { - // 4. - format: config.format, - blend: Some(wgpu::BlendState::REPLACE), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - primitive: wgpu::PrimitiveState { - front_face: wgpu::FrontFace::Cw, - ..Default::default() - }, - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Depth32Float, - depth_write_enabled: Some(false), - depth_compare: Some(wgpu::CompareFunction::LessEqual), - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), - multisample: wgpu::MultisampleState::default(), - multiview_mask: None, - cache: None, - }); - - let size = wgpu::Extent3d { - // 2. - width: config.width.max(1), - height: config.height.max(1), - depth_or_array_layers: 1, - }; - let desc = wgpu::TextureDescriptor { - label: Some("depth texture"), - size, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Depth32Float, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3. + let size = wgpu::Extent3d { // 2. + width: config.width.max(1), + height: config.height.max(1), + depth_or_array_layers: 1, + }; + let desc = wgpu::TextureDescriptor { + label: Some("depth texture"), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth32Float, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3. | wgpu::TextureUsages::TEXTURE_BINDING, - view_formats: &[], - }; - let depth_texture = device.create_texture(&desc); - let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); - let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor { - // 4. - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::MipmapFilterMode::Nearest, - compare: Some(wgpu::CompareFunction::LessEqual), // 5. - lod_min_clamp: 0.0, - lod_max_clamp: 100.0, - ..Default::default() - }); + view_formats: &[], + }; + let depth_texture = device.create_texture(&desc); + let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); + let depth_sampler = device.create_sampler( + &wgpu::SamplerDescriptor { // 4. + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), // 5. + lod_min_clamp: 0.0, + lod_max_clamp: 100.0, + ..Default::default() + } + ); - let instances = SimpleInstances::new(&device); + let instances = SimpleInstances::new(&device,&queue); - let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Vertex Buffer"), - contents: bytemuck::cast_slice(&DEFAULT_VERTICES), - usage: wgpu::BufferUsages::VERTEX, - }); + let staging_belt = wgpu::util::StagingBelt::new(device.clone(), 0x1024); - let default_material = SimpleMaterial::new( - &device, - &texture_bind_group_layout, - &default_texture, - &default_texture, - &default_texture, - MaterialProperties::default(), - ); + let buffer = device.create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Vertex Buffer"), + contents: bytemuck::cast_slice(&DEFAULT_VERTICES), + usage: wgpu::BufferUsages::VERTEX, + } + ); - Ok(Renderer { - id_count: 0, - material_layout: texture_bind_group_layout, - default_texture, - default_material, - depth_texture: SimpleTexture { - texture: depth_texture, - view: depth_view, - }, - instances, - sky_pipeline, - instance_pipeline, - surface, - config, - device, - queue, - eye, - }) + Ok(Renderer { + id_count: 0, + material_layout: texture_bind_group_layout, + default_texture: texture, + depth_texture: SimpleTexture { + texture: depth_texture, + view: depth_view, + }, + instances, + pipeline, + surface, + config, + device, + queue, + eye, + }) + } + pub(crate) fn render(&mut self, window: &Arc) -> anyhow::Result<()> { + window.request_redraw(); + + let output = match self.surface.get_current_texture() { + wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture, + wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => { + self.surface.configure(&self.device, &self.config); + surface_texture + } + wgpu::CurrentSurfaceTexture::Timeout + | wgpu::CurrentSurfaceTexture::Occluded + | wgpu::CurrentSurfaceTexture::Validation => { + // Skip this frame + return Ok(()); + } + wgpu::CurrentSurfaceTexture::Outdated => { + self.surface.configure(&self.device, &self.config); + return Ok(()); + } + wgpu::CurrentSurfaceTexture::Lost => { + // You could recreate the devices and all resources + // created with it here, but we'll just bail + anyhow::bail!("Lost device"); + } + }; + let view = output + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + let program = self.instances.write_instances(&self.device,&self.queue); + + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); + + { + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + depth_slice: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(Default::default()), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + occlusion_query_set: None, + timestamp_writes: None, + multiview_mask: None, + }); + + pass.set_pipeline(&self.pipeline); + pass.set_bind_group(0, &self.eye.group, &[]); + pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..)); + program.render(&mut pass); } - pub(crate) fn render(&mut self, window: &Arc) -> anyhow::Result<()> { - window.request_redraw(); - let output = match self.surface.get_current_texture() { - wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture, - wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => { - self.surface.configure(&self.device, &self.config); - surface_texture - } - wgpu::CurrentSurfaceTexture::Timeout - | wgpu::CurrentSurfaceTexture::Occluded - | wgpu::CurrentSurfaceTexture::Validation => { - // Skip this frame - return Ok(()); - } - wgpu::CurrentSurfaceTexture::Outdated => { - self.surface.configure(&self.device, &self.config); - return Ok(()); - } - wgpu::CurrentSurfaceTexture::Lost => { - // You could recreate the devices and all resources - // created with it here, but we'll just bail - anyhow::bail!("Lost device"); - } - }; - let view = output - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - let program = self.instances.write_instances(&self.device, &self.queue); + self.queue.submit(Some(encoder.finish())); - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Render Encoder"), - }); + self.eye.write(&self.queue); - { - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - depth_slice: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.5, - g: 0.6, - b: 0.8, - a: 1.0, - }), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture.view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: wgpu::StoreOp::Store, - }), - stencil_ops: None, - }), - occlusion_query_set: None, - timestamp_writes: None, - multiview_mask: None, - }); + output.present(); - pass.set_pipeline(&self.instance_pipeline); - pass.set_bind_group(0, &self.eye.group, &[]); - pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..)); - program.render(&mut pass); - - pass.set_bind_group(1, &self.default_material.group, &[]); - - pass.set_pipeline(&self.sky_pipeline); - pass.draw(0..6, 0..1); - } - - self.queue.submit(Some(encoder.finish())); - - self.eye.write(&self.queue); - - output.present(); - - Ok(()) - } -} + Ok(()) + } +} \ No newline at end of file diff --git a/src/world/mod.rs b/src/world/mod.rs index 3802219..94875fa 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -1,228 +1,223 @@ -use crate::render::{Renderer, SimpleLightData, SimpleModelData}; -use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles}; use std::cell::RefCell; use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::ops::{Div, Mul}; use std::rc::Rc; +use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles}; use wgpu::naga::{FastHashMap, FastHashSet}; +use crate::render::{SimpleModelData, SimpleLightData, Renderer}; #[derive(Clone)] pub enum Shape { - Block(Vec3), - Sphere(f32), - None, + Block(Vec3), + Sphere(f32), + None, } #[derive(Clone)] pub struct SimpleColliderData { - pub transform: Mat4, - pub shape: Shape, - pub radius: f32, + pub transform: Mat4, + pub shape: Shape, + pub radius: f32, } #[derive(Clone)] pub struct SimpleObjectData { - pub model: Option, - pub collider: SimpleColliderData, + pub model: Option, + pub collider: SimpleColliderData, } #[derive(Clone)] pub struct SimpleLight(pub Rc>); impl PartialEq for SimpleLight { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.0, &other.0) - } + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.0, &other.0) + } } impl Eq for SimpleLight {} impl Hash for SimpleLight { - fn hash(&self, state: &mut H) { - (self.0.as_ptr() as *const RefCell).hash(state) - } + fn hash(&self, state: &mut H) { + (self.0.as_ptr() as *const RefCell).hash(state) + } } #[derive(Clone)] pub struct SimpleObject(pub Rc>); impl SimpleObject { - pub(crate) fn hard_clone(&self) -> SimpleObject { - SimpleObject { - 0: Rc::new(RefCell::new(SimpleObjectData { - model: self.0.borrow().model.clone(), - collider: self.0.borrow().collider.clone(), - })), - } + pub(crate) fn hard_clone(&self) -> SimpleObject { + SimpleObject { + 0: Rc::new(RefCell::new(SimpleObjectData { + model: self.0.borrow().model.clone(), + collider: self.0.borrow().collider.clone(), + })), } + } } impl PartialEq for SimpleObject { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.0, &other.0) - } + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.0,&other.0) + } } impl Eq for SimpleObject {} impl Hash for SimpleObject { - fn hash(&self, state: &mut H) { - (self.0.as_ptr() as *const RefCell).hash(state); - } + fn hash(&self, state: &mut H) { + (self.0.as_ptr() as *const RefCell).hash(state); + } } #[derive(Eq, Hash, PartialEq, Clone)] enum Interest { - Light(SimpleLight), - Object(SimpleObject), + Light(SimpleLight), + Object(SimpleObject), } struct Block { - debug: Option, - volume: u8, - velocity: Vec3, - material: u8, - interests: FastHashSet, - blocks: [Option>; 64], + debug: Option, + volume: u8, + velocity: Vec3, + material: u8, + interests: FastHashSet, + blocks: [Option>;64], } const TREE_ATTACK: usize = 4; const TREE_FLOOR: usize = 4; impl Block { - fn new() -> Block { - Block { - debug: None, - volume: 0, - velocity: Vec3::ZERO, - material: 0, - interests: FastHashSet::with_hasher(BuildHasherDefault::default()), - blocks: [const { None }; const { TREE_ATTACK * TREE_ATTACK * TREE_ATTACK }], - } + fn new() -> Block { + Block { + debug: None, + volume: 0, + velocity: Vec3::ZERO, + material: 0, + interests: FastHashSet::with_hasher(BuildHasherDefault::default()), + blocks: [const { None }; const { TREE_ATTACK * TREE_ATTACK * TREE_ATTACK }], } - fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32, block_size: f32) { - let cs = block_size / const { TREE_ATTACK as f32 }; - if rad < cs || block_size >= TREE_FLOOR as f32 { - let rel = ((pos + block_size / 2.0) / cs).round().as_uvec3(); - let new_pos = pos - (rel.as_vec3() + cs / 2.0); - let index = (rel.x + rel.y * 4 + rel.z * 16) as usize; - match self.blocks[index] { - Some(ref mut block) => { - block.place_pos(interest, new_pos, rad, cs); - } - None => { - let mut block = Box::new(Block::new()); - block.place_pos(interest, new_pos, rad, cs); - self.blocks[index] = Some(block); - } - } + } + fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32, block_size: f32) { + let cs = block_size / const { TREE_ATTACK as f32 }; + if rad < cs || block_size >= TREE_FLOOR as f32 { + let rel = ((pos + block_size / 2.0) / cs).round().as_uvec3(); + let new_pos = pos - (rel.as_vec3() + cs / 2.0); + let index = (rel.x + rel.y * 4 + rel.z * 16) as usize; + match self.blocks[index] { + Some(ref mut block) => { + block.place_pos(interest,new_pos,rad,cs); + }, + None => { + let mut block = Box::new(Block::new()); + block.place_pos(interest,new_pos,rad,cs); + self.blocks[index] = Some(block); + } + } + } else { + self.interests.insert(interest); + } + } + fn debug_step(&mut self, value: bool) { + match self.debug { + Some(ref mut debug) => { + if value { + } else { - self.interests.insert(interest); - } - } - fn debug_step(&mut self, value: bool) { - match self.debug { - Some(ref mut debug) => { - if value { - } else { - } - } - None => { - if value { - } else { - } - } - } - for maybe_block in self.blocks.iter_mut() { - if let Some(block) = maybe_block { - block.debug_step(value) - } + } + }, + None => { + if value { + + } else { + + } + } } + } } pub struct World { - chunk_size: u32, - map: FastHashMap, - pub renderer: Option, - debug_world_map: bool, - debug_world_map_object: Option, + chunk_size: u32, + map: FastHashMap, + pub renderer: Option, + debug_world_map: bool, + debug_world_map_object: Option, } impl World { - pub fn new() -> World { - World { - chunk_size: 512, - map: FastHashMap::with_hasher(BuildHasherDefault::default()), - renderer: None, - debug_world_map: false, - debug_world_map_object: None, + pub fn new() -> World { + World { + chunk_size: 512, + map: FastHashMap::with_hasher(BuildHasherDefault::default()), + renderer: None, + debug_world_map: false, + debug_world_map_object: None, + } + } + pub fn add_renderer(&mut self, renderer: Renderer) { + self.renderer = Some(renderer); + self.debug_world_map_object = self.renderer.as_mut().unwrap().load_from_gltf(include_bytes!("../assets/debug.glb")).first_object() + } + pub fn add_object(&mut self, object: SimpleObject) { + self.place(Interest::Object(object.clone())); + if let Some(ref mut renderer) = self.renderer { + renderer.instances.add_object(object) + } + } + pub fn set_debug(&mut self, value: bool) { + self.debug_world_map = value; + } + pub fn light_step(&mut self) { + + } + pub fn object_step(&mut self) { + + } + pub fn debug_step(&mut self) { + self.light_step(); + self.object_step(); + for (index, item) in self.map.iter_mut() { + item.debug_step(self.debug_world_map); + } + } + fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32) { + let cs = self.chunk_size as f32; + let c_rad = ((cs / 2.0) * (cs / 2.0)) * 3.0; + for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 { + for y in (pos.y - rad).div(cs) as i32..=(pos.y + rad).div(cs).ceil() as i32 { + for z in (pos.z - rad).div(cs) as i32..=(pos.z + rad).div(cs).ceil() as i32 { + let block_pos = IVec3::new(x,y,z); + let block_pos_f32 = block_pos.as_vec3(); + if block_pos_f32.distance_squared(pos) < rad + c_rad { + self.map.entry(block_pos).or_insert_with(|| { + let mut block = Block::new(); + block.place_pos( + interest.clone(), + pos - block_pos_f32, + rad, + self.chunk_size as f32, + ); + block + }); + } } + } } - pub fn add_renderer(&mut self, renderer: Renderer) { - self.renderer = Some(renderer); - self.debug_world_map_object = self - .renderer - .as_mut() - .unwrap() - .load_from_gltf(include_bytes!("../assets/cube.glb")) - .first_object() - } - pub fn add_object(&mut self, object: SimpleObject) { - self.place(Interest::Object(object.clone())); - if let Some(ref mut renderer) = self.renderer { - renderer.instances.add_object(object) - } - } - pub fn set_debug(&mut self, value: bool) { - self.debug_world_map = value; - } - pub fn light_step(&mut self) {} - pub fn object_step(&mut self) {} - pub fn debug_step(&mut self) { - self.light_step(); - self.object_step(); - for (index, item) in self.map.iter_mut() { - item.debug_step(self.debug_world_map); - } - } - fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32) { - let cs = self.chunk_size as f32; - let c_rad = ((cs / 2.0) * (cs / 2.0)) * 3.0; - for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 { - for y in (pos.y - rad).div(cs) as i32..=(pos.y + rad).div(cs).ceil() as i32 { - for z in (pos.z - rad).div(cs) as i32..=(pos.z + rad).div(cs).ceil() as i32 { - let block_pos = IVec3::new(x, y, z); - let block_pos_f32 = block_pos.as_vec3(); - if block_pos_f32.distance_squared(pos) < rad + c_rad { - self.map.entry(block_pos).or_insert_with(|| { - let mut block = Block::new(); - block.place_pos( - interest.clone(), - pos - block_pos_f32, - rad, - self.chunk_size as f32, - ); - block - }); - } - } - } - } - } - fn place(&mut self, interest: Interest) { - let (pos, rad) = match &interest { - Interest::Light(light) => { - let light = light.0.borrow(); - (light.instance.location.xyz(), light.instance.color.length()) - } - Interest::Object(object) => { - let collider = &object.0.borrow().collider; - ( - collider.transform.to_scale_rotation_translation().2, - collider.radius, - ) - } - }; - self.place_pos(interest, pos, rad); - } -} + } + fn place(&mut self, interest: Interest) { + let (pos,rad) = match &interest { + Interest::Light(light) => { + let light = light.0.borrow(); + (light.instance.location.xyz(),light.instance.color.length()) + }, + Interest::Object(object) => { + let collider = &object.0.borrow().collider; + (collider.transform.to_scale_rotation_translation().2,collider.radius) + }, + }; + self.place_pos(interest,pos,rad); + } +} \ No newline at end of file