use wgpu::util::DeviceExt; use winit::{ event::*, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, }; mod camera; use camera::*; struct Renderer { pub device: wgpu::Device, pub mesh_pool: MeshPool, pub size: winit::dpi::PhysicalSize, surface: wgpu::Surface, queue: wgpu::Queue, config: wgpu::SurfaceConfiguration, } impl Renderer { pub async fn new(window: &winit::window::Window) -> Self { let size = window.inner_size(); let instance = wgpu::Instance::new(wgpu::Backends::all()); let surface = unsafe { instance.create_surface(window) }; let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface), force_fallback_adapter: false, }) .await .unwrap(); let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { features: wgpu::Features::empty(), limits: wgpu::Limits::default(), label: None, }, None, ) .await .unwrap(); let config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: surface.get_preferred_format(&adapter).unwrap(), width: size.width, height: size.height, present_mode: wgpu::PresentMode::Fifo, }; surface.configure(&device, &config); let mesh_pool = MeshPool::default(); Self { size, surface, device, queue, config, mesh_pool, } } pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; self.config.width = new_size.width; self.config.height = new_size.height; self.surface.configure(&self.device, &self.config); } } pub fn render( &mut self, camera: &impl Camera, meshes: &MeshCommands, ) -> Result<(), wgpu::SurfaceError> { Ok(()) } } struct MeshGroup { vertices: wgpu::Buffer, vertex_capacity: usize, indices: wgpu::Buffer, index_capacity: usize, } impl MeshGroup { pub fn new(device: &wgpu::Device, data: &MeshData) -> Self { let vertex_capacity = data.vertices.len(); let vertices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Vertex Buffer"), contents: bytemuck::cast_slice(&data.vertices), usage: wgpu::BufferUsages::VERTEX, }); let index_capacity = data.indices.len(); let indices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Index Buffer"), contents: bytemuck::cast_slice(&data.indices), usage: wgpu::BufferUsages::VERTEX, }); Self { vertex_capacity, vertices, index_capacity, indices, } } } #[derive(Default)] struct MeshPool { groups: slab::Slab, } impl MeshPool { pub fn allocate(&mut self, device: &wgpu::Device, data: &MeshData) -> MeshHandle { let group = MeshGroup::new(device, data); let group_id = self.groups.insert(group); let sub_id = 0; MeshHandle { group_id, sub_id } } } #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] struct CameraUniform { vp: [[f32; 4]; 4], } #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] struct Vertex { position: [f32; 3], } type Index = u32; struct MeshData { vertices: Vec, indices: Vec, } #[repr(C)] #[derive(Copy, Clone, Eq, Hash, PartialEq)] struct MeshHandle { group_id: usize, // unused for now, since each group contains only one mesh sub_id: usize, } #[derive(Copy, Clone, PartialEq)] struct MeshInstance { pub handle: MeshHandle, pub transform: glam::Mat4, } type MeshCommands = Vec; fn main() { let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); let mut camera = Flycam::new(10.0, 0.002); let mut is_grabbed = false; let mut ren = pollster::block_on(Renderer::new(&window)); let commands = MeshCommands::new(); event_loop.run(move |event, _, control_flow| match event { Event::RedrawRequested(_) => match ren.render(&camera, &commands) { Ok(_) => {} Err(wgpu::SurfaceError::Lost) => ren.resize(ren.size), Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit, Err(e) => println!("error: {:?}", e), }, Event::MainEventsCleared => { camera.update(); window.request_redraw(); } Event::DeviceEvent { ref event, .. } => match event { DeviceEvent::MouseMotion { delta } => { if is_grabbed { camera.process_mouse(delta.0, delta.1); } } _ => {} }, Event::WindowEvent { ref event, window_id, } if window_id == window.id() => match event { WindowEvent::KeyboardInput { input: KeyboardInput { virtual_keycode: Some(key), state, .. }, .. } => { if *state == ElementState::Pressed && *key == VirtualKeyCode::Escape { if is_grabbed { window.set_cursor_grab(false).unwrap(); window.set_cursor_visible(true); is_grabbed = false; } } else { camera.process_keyboard(*key, *state); } } WindowEvent::MouseInput { button: MouseButton::Left, state: ElementState::Pressed, .. } => { if !is_grabbed { window.set_cursor_grab(true).unwrap(); window.set_cursor_visible(false); is_grabbed = true; } } WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::Resized(physical_size) => { ren.resize(*physical_size); camera.resize(physical_size.width, physical_size.height); } WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { ren.resize(**new_inner_size); camera.resize(new_inner_size.width, new_inner_size.height); } _ => {} }, _ => {} }); }