From 22da1cf7321d8d14866561d3cb66c3405450daa4 Mon Sep 17 00:00:00 2001 From: Thomas Jowett Date: Thu, 22 Feb 2024 23:20:02 +0000 Subject: [PATCH] Implemented the render function --- src/lib.rs | 353 ++++++++++++++++++++++++++++++---------------------- src/main.rs | 2 +- 2 files changed, 208 insertions(+), 147 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3897a14..56d8562 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,165 +1,226 @@ -pub mod halvar { - use winit::{ - event::*, - event_loop::{ControlFlow, EventLoop}, - window::{Window, WindowBuilder}, - }; +use winit::{ + event::*, + event_loop::{ControlFlow, EventLoop}, + window::{Window, WindowBuilder}, +}; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::*; + +struct State { + surface: wgpu::Surface, + device: wgpu::Device, + queue: wgpu::Queue, + config: wgpu::SurfaceConfiguration, + size: winit::dpi::PhysicalSize, + window: Window, +} - #[cfg(target_arch = "wasm32")] - use wasm_bindgen::prelude::*; - - struct State { - surface: wgpu::Surface, - device: wgpu::Device, - queue: wgpu::Queue, - config: wgpu::SurfaceConfiguration, - size: winit::dpi::PhysicalSize, - window: Window, - } +impl State { + async fn new(window: Window) -> Self { + let size = window.inner_size(); - impl State { - async fn new(window: Window) -> Self { - let size = window.inner_size(); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::all(), + ..Default::default() + }); - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::Backends::all(), - ..Default::default() - }); + let surface = unsafe { instance.create_surface(&window) }.unwrap(); - let surface = unsafe { instance.create_surface(&window) }.unwrap(); - - let adapter = instance - .request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::default(), - compatible_surface: Some(&surface), - force_fallback_adapter: false, - }) - .await - .unwrap(); - - let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - features: wgpu::Features::empty(), - limits: if cfg!(target_arch = "wasm32") { - wgpu::Limits::downlevel_webgl2_defaults() - } else { - wgpu::Limits::default() - }, - label: None, + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + compatible_surface: Some(&surface), + force_fallback_adapter: false, + }) + .await + .unwrap(); + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: if cfg!(target_arch = "wasm32") { + wgpu::Limits::downlevel_webgl2_defaults() + } else { + wgpu::Limits::default() }, - None, //trace_path - ) - .await - .unwrap(); - - let surface_caps = surface.get_capabilities(&adapter); - - let surface_format = surface_caps - .formats - .iter() - .copied() - .find(|f| f.is_srgb()) - .unwrap_or(surface_caps.formats[0]); - - let modes = &surface_caps.present_modes; - - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::AutoVsync, - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - }; - surface.configure(&device, &config); - - Self { - surface, - device, - queue, - config, - size, - window, - } - } + label: None, + }, + None, //trace_path + ) + .await + .unwrap(); - pub fn window(&self) -> &Window { - &self.window + let surface_caps = surface.get_capabilities(&adapter); + + let surface_format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.is_srgb()) + .unwrap_or(surface_caps.formats[0]); + + let _modes = &surface_caps.present_modes; //TODO: Select which mode is needed based on settings + + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::AutoVsync, + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + }; + surface.configure(&device, &config); + + Self { + surface, + device, + queue, + config, + size, + window, } + } - fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { - todo!() - } + pub fn window(&self) -> &Window { + &self.window + } - fn input(&mut self, event: &WindowEvent) -> bool { - todo!() + 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); } + } - fn update(&mut self) { - todo!() - } + fn input(&mut self, _event: &WindowEvent) -> bool { + false + } - fn render(&mut self) -> Result<(), wgpu::SurfaceError> { - todo!() - } + fn update(&mut self) { + //TODO: implement update } - #[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))] - pub async fn run() { - cfg_if::cfg_if! { - if #[cfg(target_arch = "wasm32")] { - std::panic::set_hook(Box::new(console_error_panic_hook::hook)); - console_log::init_with_level(log::Level::Warn).expect("couldn't initialize logger"); - } else { - env_logger::init(); - } - } - let event_loop = EventLoop::new(); - let title = env!("CARGO_PKG_NAME"); - let window = WindowBuilder::new() - .with_title(title) - .build(&event_loop) - .unwrap(); + fn render(&mut self) -> Result<(), wgpu::SurfaceError> { + let output = self.surface.get_current_texture()?; - #[cfg(target_arch = "wasm32")] - { - use winit::dpi::PhysicalSize; - window.set_inner_size(PhysicalSize::new(450, 400)); - - use winit::platform::web::WindowExtWebSys; - web_sys::window() - .and_then(|win| win.document()) - .and_then(|doc| { - let dst = doc.get_element_by_id("wasm-halvar")?; - let canvas = web_sys::Element::from(window.canvas()); - dst.append_child(&canvas).ok()?; - Some(()) - }) - .expect("Couldn't append canvas to document body"); - } + let view = output + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); - let mut state = State::new(window).await; - - event_loop.run(move |event, _, control_flow| match event { - Event::WindowEvent { - ref event, - window_id, - } if window_id == state.window.id() => match event { - WindowEvent::CloseRequested - | WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(VirtualKeyCode::Escape), - .. - }, - .. - } => *control_flow = ControlFlow::Exit, - _ => {} - }, - _ => {} + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); + + let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + timestamp_writes: None, }); + + drop(_render_pass); + + self.queue.submit(std::iter::once(encoder.finish())); + output.present(); + Ok(()) + } +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))] +pub async fn run() { + cfg_if::cfg_if! { + if #[cfg(target_arch = "wasm32")] { + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + console_log::init_with_level(log::Level::Warn).expect("couldn't initialize logger"); + } else { + env_logger::init(); + } } + let event_loop = EventLoop::new(); + let title = env!("CARGO_PKG_NAME"); + let window = WindowBuilder::new() + .with_title(title) + .build(&event_loop) + .unwrap(); + + #[cfg(target_arch = "wasm32")] + { + use winit::dpi::PhysicalSize; + window.set_inner_size(PhysicalSize::new(450, 400)); + + use winit::platform::web::WindowExtWebSys; + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| { + let dst = doc.get_element_by_id("wasm-halvar")?; + let canvas = web_sys::Element::from(window.canvas()); + dst.append_child(&canvas).ok()?; + Some(()) + }) + .expect("Couldn't append canvas to document body"); + } + + let mut state = State::new(window).await; + + event_loop.run(move |event, _, control_flow| match event { + Event::WindowEvent { + ref event, + window_id, + } if window_id == state.window.id() => { + if !state.input(event) { + match event { + WindowEvent::CloseRequested + | WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(VirtualKeyCode::Escape), + .. + }, + .. + } => *control_flow = ControlFlow::Exit, + WindowEvent::Resized(physical_size) => { + state.resize(*physical_size); + } + WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + state.resize(**new_inner_size) + } + _ => {} + } + } + } + Event::RedrawRequested(window_id) if window_id == state.window().id() => { + state.update(); + match state.render() { + Ok(_) => {} + Err(wgpu::SurfaceError::Lost) => state.resize(state.size), + Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit, + Err(e) => eprintln!("{:?}", e), + } + } + Event::MainEventsCleared => { + state.window().request_redraw(); + } + _ => {} + }); } diff --git a/src/main.rs b/src/main.rs index a19f506..7f8a5a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use halvar::halvar::run; +use halvar::run; fn main() { pollster::block_on(run());