diff --git a/src/hud/hotbar_hud.rs b/src/hud/hotbar_hud.rs index 172aedb..85028f4 100644 --- a/src/hud/hotbar_hud.rs +++ b/src/hud/hotbar_hud.rs @@ -25,7 +25,7 @@ impl HotbarHud { Some(BlockType::Sand), None, Some(BlockType::Grass), - None, + Some(BlockType::Cobblestone), None, None, None, diff --git a/src/hud/mod.rs b/src/hud/mod.rs index 94576ac..a0b0d0a 100644 --- a/src/hud/mod.rs +++ b/src/hud/mod.rs @@ -4,6 +4,7 @@ use crate::{ render_context::RenderContext, state::PRIMITIVE_STATE, vertex::{HudVertex, Vertex}, + world::block::BlockType, }; use self::{debug_hud::DebugHud, hotbar_hud::HotbarHud, widgets_hud::WidgetsHud}; @@ -138,4 +139,9 @@ impl Hud { + self.debug_hud.render(&mut render_pass) + self.hotbar_hud.render(render_context, &mut render_pass) } + + pub fn selected_block(&self) -> Option { + // TODO The hotbar widget should be rendered by HotbarHud + self.hotbar_hud.blocks[self.widgets_hud.hotbar_cursor_position] + } } diff --git a/src/hud/widgets_hud.rs b/src/hud/widgets_hud.rs index 0296b60..8c4e720 100644 --- a/src/hud/widgets_hud.rs +++ b/src/hud/widgets_hud.rs @@ -12,7 +12,7 @@ use crate::{ pub struct WidgetsHud { texture_bind_group: BindGroup, geometry_buffers: GeometryBuffers, - hotbar_cursor_position: usize, + pub hotbar_cursor_position: usize, } impl WidgetsHud { diff --git a/src/main.rs b/src/main.rs index f472438..5103f55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ mod aabb; mod camera; mod geometry; mod hud; -mod npc; mod player; mod render_context; mod state; @@ -148,7 +147,7 @@ fn main() { println!( "{:>8} tris | {:>5} chunks", triangle_count, - state.world_state.world.chunks.len() + state.world.chunks.len() ); elapsed = Duration::from_secs(0); diff --git a/src/state/mod.rs b/src/state.rs similarity index 58% rename from src/state/mod.rs rename to src/state.rs index 467cccd..66967a8 100644 --- a/src/state/mod.rs +++ b/src/state.rs @@ -1,16 +1,20 @@ -pub mod world_state; - use std::time::{Duration, Instant}; use winit::{ dpi::PhysicalSize, - event::{DeviceEvent, ElementState, MouseScrollDelta, VirtualKeyCode, WindowEvent}, + event::{ + DeviceEvent, ElementState, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent, + }, window::Window, }; -use world_state::WorldState; - -use crate::{hud::Hud, render_context::RenderContext, texture::TextureManager}; +use crate::{ + hud::Hud, + player::Player, + render_context::RenderContext, + texture::{Texture, TextureManager}, + world::World, +}; pub const PRIMITIVE_STATE: wgpu::PrimitiveState = wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, @@ -25,11 +29,13 @@ pub const PRIMITIVE_STATE: wgpu::PrimitiveState = wgpu::PrimitiveState { pub struct State { pub window_size: PhysicalSize, render_context: RenderContext, - pub world_state: WorldState, pub mouse_grabbed: bool, pub hud: Hud, + + pub world: World, + pub player: Player, } impl State { @@ -85,8 +91,6 @@ impl State { } pub async fn new(window: &Window) -> State { - let window_size = window.inner_size(); - let (render_surface, render_adapter, render_device, render_queue) = Self::create_render_device(window).await; @@ -107,29 +111,31 @@ impl State { texture_manager.load_all(&render_context).unwrap(); render_context.texture_manager = Some(texture_manager); - let world_state = WorldState::new(&render_context); - let hud = Hud::new(&render_context); + let player = Player::new(&render_context); + let world = World::new(&render_context, &player.view); Self { - window_size, + window_size: window.inner_size(), render_context, - world_state, - mouse_grabbed: false, hud, + player, + world, } } - pub fn resize(&mut self, new_size: PhysicalSize) { - println!("resizing to {:?}", new_size); - self.window_size = new_size; - self.render_context.swap_chain_descriptor.width = new_size.width; - self.render_context.swap_chain_descriptor.height = new_size.height; + pub fn resize(&mut self, size: PhysicalSize) { + println!("resizing to {:?}", size); + self.window_size = size; + self.render_context.swap_chain_descriptor.width = size.width; + self.render_context.swap_chain_descriptor.height = size.height; - self.world_state.resize(&self.render_context, new_size); + self.player.view.projection.resize(size.width, size.height); + self.world.depth_texture = + Texture::create_depth_texture(&self.render_context, "depth_texture"); self.render_context.swap_chain = self.render_context.device.create_swap_chain( &self.render_context.surface, @@ -144,27 +150,53 @@ impl State { } fn input_keyboard(&mut self, key_code: VirtualKeyCode, state: ElementState) { - if state == ElementState::Pressed { - match key_code { - VirtualKeyCode::Key1 => self.set_hotbar_cursor(0), - VirtualKeyCode::Key2 => self.set_hotbar_cursor(1), - VirtualKeyCode::Key3 => self.set_hotbar_cursor(2), - VirtualKeyCode::Key4 => self.set_hotbar_cursor(3), - VirtualKeyCode::Key5 => self.set_hotbar_cursor(4), - VirtualKeyCode::Key6 => self.set_hotbar_cursor(5), - VirtualKeyCode::Key7 => self.set_hotbar_cursor(6), - VirtualKeyCode::Key8 => self.set_hotbar_cursor(7), - VirtualKeyCode::Key9 => self.set_hotbar_cursor(8), - _ => self.world_state.input_keyboard(key_code, state), + let pressed = state == ElementState::Pressed; + + match key_code { + VirtualKeyCode::F2 if pressed => self.player.creative ^= true, + + // Hotbar + VirtualKeyCode::Key1 if pressed => self.set_hotbar_cursor(0), + VirtualKeyCode::Key2 if pressed => self.set_hotbar_cursor(1), + VirtualKeyCode::Key3 if pressed => self.set_hotbar_cursor(2), + VirtualKeyCode::Key4 if pressed => self.set_hotbar_cursor(3), + VirtualKeyCode::Key5 if pressed => self.set_hotbar_cursor(4), + VirtualKeyCode::Key6 if pressed => self.set_hotbar_cursor(5), + VirtualKeyCode::Key7 if pressed => self.set_hotbar_cursor(6), + VirtualKeyCode::Key8 if pressed => self.set_hotbar_cursor(7), + VirtualKeyCode::Key9 if pressed => self.set_hotbar_cursor(8), + + // Movement + VirtualKeyCode::W => self.player.forward_pressed = pressed, + VirtualKeyCode::S => self.player.backward_pressed = pressed, + VirtualKeyCode::A => self.player.left_pressed = pressed, + VirtualKeyCode::D => self.player.right_pressed = pressed, + VirtualKeyCode::Space => { + self.player.up_speed = match (pressed, self.player.creative) { + // Creative + (true, true) => 1.0, + (false, true) => 0.0, + + // Not creative + (true, false) => { + // TODO Don't allow player to jump in mid-air + 0.6 + } + (false, false) => self.player.up_speed, + }; } - } else { - self.world_state.input_keyboard(key_code, state) + VirtualKeyCode::LShift if self.player.creative => { + self.player.up_speed = if pressed { -1.0 } else { 0.0 } + } + VirtualKeyCode::LControl => self.player.sprinting = pressed, + + _ => (), } } fn input_mouse(&mut self, dx: f64, dy: f64) { if self.mouse_grabbed { - self.world_state.player.update_camera(dx, dy); + self.player.update_camera(dx, dy); } } @@ -178,11 +210,20 @@ impl State { button, state: ElementState::Pressed, .. - } if self.mouse_grabbed => self.world_state.input_mouse_button( - button, - &self.render_context, - None, // TODO - ), + } if self.mouse_grabbed => { + if button == &MouseButton::Left { + self.world + .break_at_crosshair(&self.render_context, &self.player.view.camera); + } else if button == &MouseButton::Right { + if let Some(selected) = self.hud.selected_block() { + self.world.place_at_crosshair( + &self.render_context, + &self.player.view.camera, + selected, + ); + } + } + } WindowEvent::MouseWheel { delta: MouseScrollDelta::LineDelta(_, delta), @@ -203,11 +244,14 @@ impl State { } pub fn update(&mut self, dt: Duration, render_time: Duration) { - self.world_state - .update(dt, render_time, &self.render_context); + self.player.update_position(dt, &self.world); - self.hud - .update(&self.render_context, &self.world_state.player.view.camera) + let view = &mut self.player.view; + view.update_view_projection(&self.render_context); + + self.world + .update(&self.render_context, dt, render_time, &view.camera); + self.hud.update(&self.render_context, &view.camera); } pub fn render(&mut self) -> anyhow::Result<(usize, Duration)> { @@ -221,9 +265,13 @@ impl State { .create_command_encoder(&Default::default()); let mut triangle_count = 0; - triangle_count += - self.world_state - .render(&self.render_context, &frame, &mut render_encoder); + + triangle_count += self.world.render( + &self.render_context, + &mut render_encoder, + &frame, + &self.player.view, + ); triangle_count += self .hud diff --git a/src/state/world_state.rs b/src/state/world_state.rs deleted file mode 100644 index 652d535..0000000 --- a/src/state/world_state.rs +++ /dev/null @@ -1,282 +0,0 @@ -use std::time::Duration; - -use wgpu::{ - util::{BufferInitDescriptor, DeviceExt}, - CommandEncoder, SwapChainTexture, -}; -use winit::{ - dpi::PhysicalSize, - event::{ElementState, MouseButton, VirtualKeyCode}, -}; - -use crate::{ - player::Player, - render_context::RenderContext, - texture::Texture, - time::Time, - vertex::{BlockVertex, Vertex}, - world::{block::BlockType, World}, -}; - -pub struct WorldState { - pub render_pipeline: wgpu::RenderPipeline, - pub depth_texture: Texture, - - time: Time, - time_buffer: wgpu::Buffer, - pub time_bind_group: wgpu::BindGroup, - - pub world: World, - pub player: Player, -} - -impl WorldState { - fn create_time( - render_context: &RenderContext, - ) -> (Time, wgpu::Buffer, wgpu::BindGroupLayout, wgpu::BindGroup) { - let time = Time::new(); - - let buffer = render_context - .device - .create_buffer_init(&BufferInitDescriptor { - label: Some("time_buffer"), - contents: bytemuck::cast_slice(&[time]), - usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - }); - - let bind_group_layout = - render_context - .device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: Some("time_bind_group_layout"), - }); - - let bind_group = render_context - .device - .create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: buffer.as_entire_binding(), - }], - label: Some("time_bind_group"), - }); - - (time, buffer, bind_group_layout, bind_group) - } - - fn create_render_pipeline( - render_context: &RenderContext, - shader: &wgpu::ShaderModule, - pipeline_layout: &wgpu::PipelineLayout, - ) -> wgpu::RenderPipeline { - render_context - .device - .create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Render Pipeline"), - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "main", - buffers: &[BlockVertex::descriptor()], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "main", - targets: &[wgpu::ColorTargetState { - format: render_context.swap_chain_descriptor.format, - blend: Some(wgpu::BlendState { - alpha: wgpu::BlendComponent::REPLACE, - color: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrite::ALL, - }], - }), - primitive: wgpu::PrimitiveState { - cull_mode: Some(wgpu::Face::Back), - polygon_mode: wgpu::PolygonMode::Fill, - ..Default::default() - }, - depth_stencil: Some(wgpu::DepthStencilState { - format: Texture::DEPTH_FORMAT, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::Less, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), - multisample: wgpu::MultisampleState::default(), - }) - } - - pub fn new(render_context: &RenderContext) -> WorldState { - let (time, time_buffer, time_layout, time_bind_group) = Self::create_time(render_context); - let player = Player::new(render_context); - - let world = World::new(render_context); - - let shader = render_context.device.create_shader_module( - &(wgpu::ShaderModuleDescriptor { - label: Some("shader"), - flags: wgpu::ShaderFlags::all(), - source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/world.wgsl").into()), - }), - ); - - let texture_manager = render_context.texture_manager.as_ref().unwrap(); - let render_pipeline_layout = - render_context - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("render_pipeline_layout"), - push_constant_ranges: &[], - bind_group_layouts: &[ - &texture_manager.bind_group_layout, - &player.view.bind_group_layout, - &time_layout, - ], - }); - let render_pipeline = - Self::create_render_pipeline(render_context, &shader, &render_pipeline_layout); - let depth_texture = Texture::create_depth_texture(render_context, "depth_texture"); - - Self { - render_pipeline, - depth_texture, - - time, - time_buffer, - time_bind_group, - - world, - player, - } - } - - pub fn render( - &self, - render_context: &RenderContext, - frame: &SwapChainTexture, - render_encoder: &mut CommandEncoder, - ) -> usize { - let mut triangle_count = 0; - - let mut render_pass = render_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("render_pass"), - color_attachments: &[wgpu::RenderPassColorAttachment { - view: &frame.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.502, - g: 0.663, - b: 0.965, - a: 1.0, - }), - store: true, - }, - }], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture.view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: None, - }), - }); - render_pass.set_pipeline(&self.render_pipeline); - - let texture_manager = render_context.texture_manager.as_ref().unwrap(); - render_pass.set_bind_group(0, texture_manager.bind_group.as_ref().unwrap(), &[]); - render_pass.set_bind_group(1, &self.player.view.bind_group, &[]); - render_pass.set_bind_group(2, &self.time_bind_group, &[]); - - triangle_count += self.world.render(&mut render_pass, &self.player.view); - - triangle_count - } - - pub fn input_mouse_button( - &mut self, - button: &MouseButton, - render_context: &RenderContext, - selected: Option, - ) { - if button == &MouseButton::Left { - self.world - .break_at_crosshair(render_context, &self.player.view.camera); - } else if button == &MouseButton::Right { - if let Some(selected) = selected { - self.world - .place_at_crosshair(render_context, &self.player.view.camera, selected); - } - } - } - - #[allow(clippy::collapsible_else_if)] - pub fn input_keyboard(&mut self, key_code: VirtualKeyCode, state: ElementState) { - let pressed = state == ElementState::Pressed; - match key_code { - VirtualKeyCode::W => self.player.forward_pressed = pressed, - VirtualKeyCode::S => self.player.backward_pressed = pressed, - VirtualKeyCode::A => self.player.left_pressed = pressed, - VirtualKeyCode::D => self.player.right_pressed = pressed, - VirtualKeyCode::F2 if pressed => self.player.creative ^= true, - VirtualKeyCode::Space => { - self.player.up_speed = match (pressed, self.player.creative) { - // Creative - (true, true) => 1.0, - (false, true) => 0.0, - - // Not creative - (true, false) => { - // TODO Don't allow player to jump in mid-air - 0.6 - } - (false, false) => self.player.up_speed, - }; - } - VirtualKeyCode::LShift if self.player.creative => { - self.player.up_speed = if pressed { -1.0 } else { 0.0 } - } - VirtualKeyCode::LControl => self.player.sprinting = pressed, - _ => (), - } - } - - pub fn update(&mut self, dt: Duration, render_time: Duration, render_context: &RenderContext) { - self.player.update_position(dt, &self.world); - - self.world - .update(render_context, dt, render_time, &self.player.view.camera); - - self.player.view.update_view_projection(render_context); - - self.time.time += dt.as_secs_f32(); - render_context.queue.write_buffer( - &self.time_buffer, - 0, - &bytemuck::cast_slice(&[self.time]), - ); - } - - pub fn resize(&mut self, render_context: &RenderContext, new_size: PhysicalSize) { - // TODO Move this to View - self.player - .view - .projection - .resize(new_size.width, new_size.height); - - self.depth_texture = Texture::create_depth_texture(render_context, "depth_texture"); - } -} diff --git a/src/world/chunk.rs b/src/world/chunk.rs index 4a0adad..2608bc4 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -21,7 +21,7 @@ use serde::{ ser::SerializeSeq, Deserialize, Serialize, Serializer, }; -use wgpu::BufferUsage; +use wgpu::{BufferUsage, RenderPass}; pub const CHUNK_SIZE: usize = 32; pub const CHUNK_ISIZE: isize = CHUNK_SIZE as isize; @@ -93,6 +93,25 @@ impl<'de> Deserialize<'de> for Chunk { } impl Chunk { + pub fn render<'a>( + &'a self, + render_pass: &mut RenderPass<'a>, + position: &Point3, + view: &View, + ) -> usize { + if !self.is_visible(position * CHUNK_ISIZE, &view) { + // Frustrum culling + 0 + } else if let Some(buffers) = &self.buffers { + buffers.apply_buffers(render_pass); + buffers.draw_indexed(render_pass) + } else { + // Not loaded + println!("Trying to render non-loaded chunk {:?}", position); + 0 + } + } + pub fn generate(&mut self, chunk_x: isize, chunk_y: isize, chunk_z: isize) { let fbm = noise::Fbm::new(); diff --git a/src/world/mod.rs b/src/world/mod.rs index ed84f31..621df7e 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -1,6 +1,7 @@ pub mod block; pub mod chunk; pub mod face_flags; +pub mod npc; pub mod quad; use std::{ @@ -10,19 +11,32 @@ use std::{ use crate::{ camera::Camera, - npc::Npc, render_context::RenderContext, + texture::Texture, + time::Time, + vertex::{BlockVertex, Vertex}, view::View, world::{ block::{Block, BlockType}, chunk::{Chunk, CHUNK_ISIZE}, + npc::Npc, }, }; use ahash::AHashMap; use cgmath::{EuclideanSpace, InnerSpace, Point3, Vector3}; -use wgpu::RenderPass; +use wgpu::{ + util::{BufferInitDescriptor, DeviceExt}, + BindGroup, Buffer, CommandEncoder, RenderPipeline, SwapChainTexture, +}; pub struct World { + pub render_pipeline: RenderPipeline, + pub depth_texture: Texture, + + pub time: Time, + pub time_buffer: Buffer, + pub time_bind_group: BindGroup, + pub npc: Npc, pub chunks: AHashMap, Chunk>, @@ -50,6 +64,13 @@ impl World { render_time: Duration, camera: &Camera, ) { + self.time.time += dt.as_secs_f32(); + render_context.queue.write_buffer( + &self.time_buffer, + 0, + &bytemuck::cast_slice(&[self.time]), + ); + self.update_highlight(render_context, camera); // Queue up new chunks for loading, if necessary @@ -147,33 +168,58 @@ impl World { } } - pub fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>, view: &View) -> usize { + pub fn render<'a>( + &'a self, + render_context: &RenderContext, + render_encoder: &mut CommandEncoder, + frame: &SwapChainTexture, + view: &View, + ) -> usize { + let mut render_pass = render_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("render_pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: &frame.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.502, + g: 0.663, + b: 0.965, + a: 1.0, + }), + store: true, + }, + }], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }), + }); + render_pass.set_pipeline(&self.render_pipeline); + + let texture_manager = render_context.texture_manager.as_ref().unwrap(); + render_pass.set_bind_group(0, texture_manager.bind_group.as_ref().unwrap(), &[]); + render_pass.set_bind_group(1, &view.bind_group, &[]); + render_pass.set_bind_group(2, &self.time_bind_group, &[]); + let mut triangle_count = 0; for (position, chunk) in &self.chunks { - // TODO Reimplement frustrum culling - if !chunk.is_visible(position * CHUNK_ISIZE, &view) { - continue; - } - - if let Some(buffers) = chunk.buffers.as_ref() { - buffers.apply_buffers(render_pass); - triangle_count += buffers.draw_indexed(render_pass); - } + triangle_count += chunk.render(&mut render_pass, position, view); } - let buffers = self.npc.geometry_buffers.as_ref().unwrap(); - buffers.apply_buffers(render_pass); - triangle_count += buffers.draw_indexed(render_pass); + triangle_count += self.npc.render(&mut render_pass); triangle_count } -} -impl World { - pub fn new(render_context: &RenderContext) -> Self { + pub fn new(render_context: &RenderContext, view: &View) -> Self { let chunks = AHashMap::new(); - let mut npc = Npc::load(); + let mut npc = Npc::new(); npc.load_geometry(render_context); let chunk_database = sled::Config::new() @@ -183,10 +229,118 @@ impl World { .open() .unwrap(); + let time = Time::new(); + + let time_buffer = render_context + .device + .create_buffer_init(&BufferInitDescriptor { + label: Some("time_buffer"), + contents: bytemuck::cast_slice(&[time]), + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + let time_bind_group_layout = + render_context + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: Some("time_bind_group_layout"), + }); + + let time_bind_group = render_context + .device + .create_bind_group(&wgpu::BindGroupDescriptor { + layout: &time_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: time_buffer.as_entire_binding(), + }], + label: Some("time_bind_group"), + }); + + let texture_manager = render_context.texture_manager.as_ref().unwrap(); + let render_pipeline_layout = + render_context + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("render_pipeline_layout"), + push_constant_ranges: &[], + bind_group_layouts: &[ + &texture_manager.bind_group_layout, + &view.bind_group_layout, + &time_bind_group_layout, + ], + }); + + let shader = render_context.device.create_shader_module( + &(wgpu::ShaderModuleDescriptor { + label: Some("shader"), + flags: wgpu::ShaderFlags::all(), + source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/world.wgsl").into()), + }), + ); + + let render_pipeline = + render_context + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "main", + buffers: &[BlockVertex::descriptor()], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "main", + targets: &[wgpu::ColorTargetState { + format: render_context.swap_chain_descriptor.format, + blend: Some(wgpu::BlendState { + alpha: wgpu::BlendComponent::REPLACE, + color: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrite::ALL, + }], + }), + primitive: wgpu::PrimitiveState { + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + ..Default::default() + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: Texture::DEPTH_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState::default(), + }); + + let depth_texture = Texture::create_depth_texture(render_context, "depth_texture"); + Self { - chunks, + render_pipeline, + + time, + time_buffer, + time_bind_group, + + depth_texture, + npc, + chunks, chunk_database, chunk_load_queue: VecDeque::new(), chunk_save_queue: VecDeque::new(), diff --git a/src/npc.rs b/src/world/npc.rs similarity index 88% rename from src/npc.rs rename to src/world/npc.rs index 1e24243..2c38543 100644 --- a/src/npc.rs +++ b/src/world/npc.rs @@ -2,7 +2,7 @@ extern crate gltf; extern crate wgpu; use cgmath::Vector3; -use wgpu::BufferUsage; +use wgpu::{BufferUsage, RenderPass}; use crate::{ geometry::{Geometry, GeometryBuffers}, @@ -19,7 +19,7 @@ pub struct Npc { } impl Npc { - pub fn load() -> Self { + pub fn new() -> Self { let position: Vector3 = Vector3::new(0.0, 0.0, 0.0); let scale: Vector3 = Vector3::new(0.0, 0.0, 0.0); let rotation: Vector3 = Vector3::new(0.0, 0.0, 0.0); @@ -71,4 +71,10 @@ impl Npc { BufferUsage::empty(), )); } + + pub fn render<'a>(&'a self, render_pass: &mut RenderPass<'a>) -> usize { + let buffers = self.geometry_buffers.as_ref().unwrap(); + buffers.apply_buffers(render_pass); + buffers.draw_indexed(render_pass) + } }