code is working again

0.19
Benjamin Hansen 3 months ago
parent 3f0caa6904
commit 12f115dfa1

@ -1,7 +1,8 @@
use winit::{ use winit::{
event::*, event::*,
event_loop::EventLoop, event_loop::EventLoop,
window::WindowBuilder, keyboard::{KeyCode, PhysicalKey}, keyboard::{KeyCode, PhysicalKey},
window::WindowBuilder,
}; };
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -40,23 +41,25 @@ pub fn run() {
.expect("Couldn't append canvas to document body."); .expect("Couldn't append canvas to document body.");
} }
event_loop.run(move |event, control_flow| match event { event_loop
Event::WindowEvent { .run(move |event, control_flow| match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == window.id() => match event { window_id,
WindowEvent::CloseRequested } if window_id == window.id() => match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
event: | WindowEvent::KeyboardInput {
KeyEvent { event:
state: ElementState::Pressed, KeyEvent {
physical_key: PhysicalKey::Code(KeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => control_flow.exit(), ..
} => control_flow.exit(),
_ => {}
},
_ => {} _ => {}
}, })
_ => {} .unwrap();
}).unwrap();
} }

@ -84,6 +84,7 @@ impl<'a> State<'a> {
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
desired_maximum_frame_latency: 2, desired_maximum_frame_latency: 2,
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -180,50 +181,54 @@ async fn run() {
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(&window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
event: | WindowEvent::KeyboardInput {
KeyEvent { event:
state: ElementState::Pressed, KeyEvent {
physical_key: PhysicalKey::Code(KeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => control_flow.exit(), ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
} state.resize(*physical_size);
WindowEvent::RedrawRequested => { }
state.window().request_redraw(); WindowEvent::RedrawRequested => {
state.update(); state.window().request_redraw();
match state.render() { state.update();
Ok(_) => {} match state.render() {
// Reconfigure the surface if it's lost or outdated Ok(_) => {}
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => { // Reconfigure the surface if it's lost or outdated
state.resize(state.size) Err(
} wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
// The system is out of memory, we should probably quit ) => state.resize(state.size),
Err(wgpu::SurfaceError::OutOfMemory) => { // The system is out of memory, we should probably quit
log::error!("OutOfMemory"); Err(wgpu::SurfaceError::OutOfMemory) => {
control_flow.exit(); log::error!("OutOfMemory");
control_flow.exit();
}
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
} }
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
_ => {}
} }
} }
_ => {}
} }
_ => {} })
} .unwrap();
}).unwrap();
} }

@ -3,7 +3,8 @@ use std::iter;
use winit::{ use winit::{
event::*, event::*,
event_loop::EventLoop, event_loop::EventLoop,
window::{Window, WindowBuilder}, keyboard::{PhysicalKey, KeyCode}, keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder},
}; };
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -81,6 +82,7 @@ impl<'a> State<'a> {
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
desired_maximum_frame_latency: 2, desired_maximum_frame_latency: 2,
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -191,53 +193,57 @@ pub async fn run() {
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(&window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
// UPDATED! if !state.input(event) {
match event { // UPDATED!
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
event: | WindowEvent::KeyboardInput {
KeyEvent { event:
state: ElementState::Pressed, KeyEvent {
physical_key: PhysicalKey::Code(KeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => control_flow.exit(), ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
} state.resize(*physical_size);
WindowEvent::RedrawRequested => { }
// This tells winit that we want another frame after this one WindowEvent::RedrawRequested => {
state.window().request_redraw(); // This tells winit that we want another frame after this one
state.update(); state.window().request_redraw();
match state.render() { state.update();
Ok(_) => {} match state.render() {
// Reconfigure the surface if it's lost or outdated Ok(_) => {}
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => { // Reconfigure the surface if it's lost or outdated
state.resize(state.size) Err(
} wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
// The system is out of memory, we should probably quit ) => state.resize(state.size),
Err(wgpu::SurfaceError::OutOfMemory) => { // The system is out of memory, we should probably quit
log::error!("OutOfMemory"); Err(wgpu::SurfaceError::OutOfMemory) => {
control_flow.exit(); log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
} }
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
_ => {}
} }
} }
_ => {}
} }
_ => {} })
} .unwrap();
}).unwrap();
} }

@ -3,11 +3,12 @@ use std::iter;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -15,11 +16,11 @@ struct State {
render_pipeline: wgpu::RenderPipeline, render_pipeline: wgpu::RenderPipeline,
challenge_render_pipeline: wgpu::RenderPipeline, challenge_render_pipeline: wgpu::RenderPipeline,
use_color: bool, use_color: bool,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -29,11 +30,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -48,10 +45,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -80,6 +77,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -213,10 +211,10 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(VirtualKeyCode::Space), physical_key: PhysicalKey::Code(KeyCode::Space),
.. ..
}, },
.. ..
@ -284,61 +282,62 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
} state.resize(*physical_size);
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { }
// new_inner_size is &mut so w have to dereference it twice WindowEvent::RedrawRequested => {
state.resize(**new_inner_size); // This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -2,26 +2,27 @@ use std::iter;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
size: winit::dpi::PhysicalSize<u32>, size: winit::dpi::PhysicalSize<u32>,
// NEW! // NEW!
render_pipeline: wgpu::RenderPipeline, render_pipeline: wgpu::RenderPipeline,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -31,11 +32,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -50,10 +47,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -82,6 +79,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -227,7 +225,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -250,57 +248,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
} state.resize(*physical_size);
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { }
// new_inner_size is &mut so w have to dereference it twice WindowEvent::RedrawRequested => {
state.resize(**new_inner_size); // This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
_ => {}
} }
} }
_ => {}
} }
Event::RedrawRequested(window_id) if window_id == state.window().id() => { })
state.update(); .unwrap();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
}
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
}
Event::MainEventsCleared => {
// RedrawRequested will only trigger once, unless we manually
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -4,6 +4,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -60,8 +61,8 @@ const VERTICES: &[Vertex] = &[
const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4]; const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -78,11 +79,11 @@ struct State {
use_complex: bool, use_complex: bool,
size: winit::dpi::PhysicalSize<u32>, size: winit::dpi::PhysicalSize<u32>,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -96,7 +97,7 @@ impl State {
// //
// The surface needs to live as long as the window that created it. // The surface needs to live as long as the window that created it.
// State owns the window so this should be safe. // State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap(); let surface = instance.create_surface(window).unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -111,10 +112,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -143,6 +144,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -281,10 +283,10 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(VirtualKeyCode::Space), physical_key: PhysicalKey::Code(KeyCode::Space),
.. ..
}, },
.. ..
@ -361,61 +363,62 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -3,7 +3,8 @@ use std::iter;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -63,8 +64,8 @@ const VERTICES: &[Vertex] = &[
const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4, /* padding */ 0]; const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4, /* padding */ 0];
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -74,11 +75,11 @@ struct State {
vertex_buffer: wgpu::Buffer, vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer,
num_indices: u32, num_indices: u32,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -92,7 +93,7 @@ impl State {
// //
// The surface needs to live as long as the window that created it. // The surface needs to live as long as the window that created it.
// State owns the window so this should be safe. // State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap(); let surface = instance.create_surface(window).unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -107,10 +108,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -139,6 +140,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -301,7 +303,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -324,57 +326,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -4,6 +4,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -63,8 +64,8 @@ const VERTICES: &[Vertex] = &[
const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4]; const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -80,11 +81,11 @@ struct State {
cartoon_texture: texture::Texture, cartoon_texture: texture::Texture,
cartoon_bind_group: wgpu::BindGroup, cartoon_bind_group: wgpu::BindGroup,
is_space_pressed: bool, is_space_pressed: bool,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -98,7 +99,7 @@ impl State {
// //
// The surface needs to live as long as the window that created it. // The surface needs to live as long as the window that created it.
// State owns the window so this should be safe. // State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap(); let surface = instance.create_surface(window).unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -112,10 +113,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -144,6 +145,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -312,10 +314,10 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(VirtualKeyCode::Space), physical_key: PhysicalKey::Code(KeyCode::Space),
.. ..
}, },
.. ..
@ -388,61 +390,61 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so we have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -3,7 +3,8 @@ use std::iter;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -66,8 +67,8 @@ const VERTICES: &[Vertex] = &[
const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4, /* padding */ 0]; const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4, /* padding */ 0];
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -80,11 +81,11 @@ struct State {
#[allow(dead_code)] #[allow(dead_code)]
diffuse_texture: texture::Texture, diffuse_texture: texture::Texture,
diffuse_bind_group: wgpu::BindGroup, diffuse_bind_group: wgpu::BindGroup,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -94,11 +95,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -112,10 +109,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -144,6 +141,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -351,7 +349,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -374,57 +372,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -3,7 +3,8 @@ use std::iter;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -146,29 +147,29 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -212,8 +213,8 @@ impl CameraController {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -230,11 +231,11 @@ struct State {
camera_buffer: wgpu::Buffer, camera_buffer: wgpu::Buffer,
camera_bind_group: wgpu::BindGroup, camera_bind_group: wgpu::BindGroup,
size: winit::dpi::PhysicalSize<u32>, size: winit::dpi::PhysicalSize<u32>,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -244,11 +245,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -262,10 +259,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -294,6 +291,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -559,61 +557,62 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -3,7 +3,8 @@ use std::iter;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -137,37 +138,37 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::Space => { KeyCode::Space => {
self.is_up_pressed = is_pressed; self.is_up_pressed = is_pressed;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.is_down_pressed = is_pressed; self.is_down_pressed = is_pressed;
true true
} }
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -211,8 +212,8 @@ impl CameraController {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -230,11 +231,11 @@ struct State {
camera_uniform: CameraUniform, camera_uniform: CameraUniform,
camera_buffer: wgpu::Buffer, camera_buffer: wgpu::Buffer,
camera_bind_group: wgpu::BindGroup, camera_bind_group: wgpu::BindGroup,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -244,11 +245,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -262,10 +259,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -294,6 +291,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -560,7 +558,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -583,57 +581,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -4,7 +4,8 @@ use cgmath::prelude::*;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -137,29 +138,29 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -264,8 +265,8 @@ impl InstanceRaw {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -284,11 +285,11 @@ struct State {
size: winit::dpi::PhysicalSize<u32>, size: winit::dpi::PhysicalSize<u32>,
instances: Vec<Instance>, instances: Vec<Instance>,
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -298,11 +299,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -316,10 +313,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -348,6 +345,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -660,61 +658,62 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -5,6 +5,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -144,37 +145,37 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::Space => { KeyCode::Space => {
self.is_up_pressed = is_pressed; self.is_up_pressed = is_pressed;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.is_down_pressed = is_pressed; self.is_down_pressed = is_pressed;
true true
} }
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -269,8 +270,8 @@ impl InstanceRaw {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -291,11 +292,11 @@ struct State {
instances: Vec<Instance>, instances: Vec<Instance>,
#[allow(dead_code)] #[allow(dead_code)]
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -305,11 +306,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -323,10 +320,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -355,6 +352,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -658,7 +656,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -681,57 +679,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -6,6 +6,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -159,29 +160,29 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -461,8 +462,8 @@ impl DepthPass {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -483,11 +484,11 @@ struct State {
#[allow(dead_code)] #[allow(dead_code)]
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
depth_pass: DepthPass, depth_pass: DepthPass,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -497,11 +498,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -515,10 +512,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -547,6 +544,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -867,61 +865,62 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -5,6 +5,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -144,37 +145,37 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::Space => { KeyCode::Space => {
self.is_up_pressed = is_pressed; self.is_up_pressed = is_pressed;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.is_down_pressed = is_pressed; self.is_down_pressed = is_pressed;
true true
} }
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -278,8 +279,8 @@ impl InstanceRaw {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -301,11 +302,11 @@ struct State {
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
// NEW! // NEW!
depth_texture: texture::Texture, depth_texture: texture::Texture,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -315,11 +316,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -333,10 +330,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -365,6 +362,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -685,7 +683,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -708,57 +706,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
match event { .run(move |event, control_flow| {
Event::WindowEvent { match event {
ref event, Event::WindowEvent {
window_id, ref event,
} if window_id == state.window().id() => { window_id,
if !state.input(event) { } if window_id == state.window().id() => {
match event { if !state.input(event) {
WindowEvent::CloseRequested match event {
| WindowEvent::KeyboardInput { WindowEvent::CloseRequested
input: | WindowEvent::KeyboardInput {
KeyboardInput { event:
state: ElementState::Pressed, KeyEvent {
virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed,
.. physical_key: PhysicalKey::Code(KeyCode::Escape),
}, ..
.. },
} => *control_flow = ControlFlow::Exit, ..
WindowEvent::Resized(physical_size) => { } => control_flow.exit(),
state.resize(*physical_size); WindowEvent::Resized(physical_size) => {
state.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// new_inner_size is &mut so w have to dereference it twice
state.resize(**new_inner_size);
}
_ => {}
}
}
}
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
Event::MainEventsCleared => { })
// RedrawRequested will only trigger once, unless we manually .unwrap();
// request it.
state.window().request_redraw();
}
_ => {}
}
});
} }

@ -5,6 +5,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -89,37 +90,37 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::Space => { KeyCode::Space => {
self.is_up_pressed = is_pressed; self.is_up_pressed = is_pressed;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.is_down_pressed = is_pressed; self.is_down_pressed = is_pressed;
true true
} }
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -223,8 +224,8 @@ impl InstanceRaw {
} }
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -240,11 +241,11 @@ struct State {
#[allow(dead_code)] #[allow(dead_code)]
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
depth_texture: texture::Texture, depth_texture: texture::Texture,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -255,11 +256,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -274,10 +271,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -308,6 +305,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -596,7 +594,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -623,53 +621,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
*control_flow = ControlFlow::Poll; .run(move |event, control_flow| {
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent {
Event::WindowEvent { ref event,
ref event, window_id,
window_id, } if window_id == state.window().id() => {
} if window_id == state.window().id() => { if !state.input(event) {
if !state.input(event) { match event {
match event { WindowEvent::CloseRequested
WindowEvent::CloseRequested | WindowEvent::KeyboardInput {
| WindowEvent::KeyboardInput { event:
input: KeyEvent {
KeyboardInput { state: ElementState::Pressed,
state: ElementState::Pressed, physical_key: PhysicalKey::Code(KeyCode::Escape),
virtual_keycode: Some(VirtualKeyCode::Escape), ..
.. },
}, ..
.. } => control_flow.exit(),
} => *control_flow = ControlFlow::Exit, WindowEvent::Resized(physical_size) => {
WindowEvent::Resized(physical_size) => { state.resize(*physical_size);
state.resize(*physical_size); }
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
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(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
_ => {} })
} .unwrap();
});
} }

@ -5,6 +5,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -93,37 +94,37 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::Space => { KeyCode::Space => {
self.is_up_pressed = is_pressed; self.is_up_pressed = is_pressed;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.is_down_pressed = is_pressed; self.is_down_pressed = is_pressed;
true true
} }
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -255,9 +256,9 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
window: Window, window: &'a Window,
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -339,8 +340,8 @@ fn create_render_pipeline(
}) })
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -350,11 +351,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -368,10 +365,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -400,6 +397,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -733,7 +731,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -763,53 +761,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
*control_flow = ControlFlow::Poll; .run(move |event, control_flow| {
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent {
Event::WindowEvent { ref event,
ref event, window_id,
window_id, } if window_id == state.window().id() => {
} if window_id == state.window().id() => { if !state.input(event) {
if !state.input(event) { match event {
match event { WindowEvent::CloseRequested
WindowEvent::CloseRequested | WindowEvent::KeyboardInput {
| WindowEvent::KeyboardInput { event:
input: KeyEvent {
KeyboardInput { state: ElementState::Pressed,
state: ElementState::Pressed, physical_key: PhysicalKey::Code(KeyCode::Escape),
virtual_keycode: Some(VirtualKeyCode::Escape), ..
.. },
}, ..
.. } => control_flow.exit(),
} => *control_flow = ControlFlow::Exit, WindowEvent::Resized(physical_size) => {
WindowEvent::Resized(physical_size) => { state.resize(*physical_size);
state.resize(*physical_size); }
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
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(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
_ => {} })
} .unwrap();
});
} }

@ -5,6 +5,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -92,37 +93,37 @@ impl CameraController {
fn process_events(&mut self, event: &WindowEvent) -> bool { fn process_events(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state, state,
virtual_keycode: Some(keycode), physical_key: PhysicalKey::Code(keycode),
.. ..
}, },
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {
VirtualKeyCode::Space => { KeyCode::Space => {
self.is_up_pressed = is_pressed; self.is_up_pressed = is_pressed;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.is_down_pressed = is_pressed; self.is_down_pressed = is_pressed;
true true
} }
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -253,9 +254,9 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
window: Window, window: &'a Window,
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -339,8 +340,8 @@ fn create_render_pipeline(
}) })
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -350,11 +351,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -368,10 +365,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -400,6 +397,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -784,7 +782,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -811,53 +809,58 @@ pub async fn run() {
} }
// State::new uses async code, so we're going to wait for it to finish // State::new uses async code, so we're going to wait for it to finish
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop
*control_flow = ControlFlow::Poll; .run(move |event, control_flow| {
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent {
Event::WindowEvent { ref event,
ref event, window_id,
window_id, } if window_id == state.window().id() => {
} if window_id == state.window().id() => { if !state.input(event) {
if !state.input(event) { match event {
match event { WindowEvent::CloseRequested
WindowEvent::CloseRequested | WindowEvent::KeyboardInput {
| WindowEvent::KeyboardInput { event:
input: KeyEvent {
KeyboardInput { state: ElementState::Pressed,
state: ElementState::Pressed, physical_key: PhysicalKey::Code(KeyCode::Escape),
virtual_keycode: Some(VirtualKeyCode::Escape), ..
.. },
}, ..
.. } => control_flow.exit(),
} => *control_flow = ControlFlow::Exit, WindowEvent::Resized(physical_size) => {
WindowEvent::Resized(physical_size) => { state.resize(*physical_size);
state.resize(*physical_size); }
WindowEvent::RedrawRequested => {
// This tells winit that we want another frame after this one
state.window().request_redraw();
state.update();
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(
wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("OutOfMemory");
control_flow.exit();
}
// This happens when the a frame takes too long to present
Err(wgpu::SurfaceError::Timeout) => {
log::warn!("Surface timeout")
}
}
}
_ => {}
} }
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(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
state.resize(state.size)
} }
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
} }
_ => {}
} }
_ => {} })
} .unwrap();
});
} }

@ -3,6 +3,7 @@ use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
@ -104,34 +105,34 @@ impl CameraController {
} }
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool {
let amount = if state == ElementState::Pressed { let amount = if state == ElementState::Pressed {
1.0 1.0
} else { } else {
0.0 0.0
}; };
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.amount_forward = amount; self.amount_forward = amount;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.amount_backward = amount; self.amount_backward = amount;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.amount_left = amount; self.amount_left = amount;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.amount_right = amount; self.amount_right = amount;
true true
} }
VirtualKeyCode::Space => { KeyCode::Space => {
self.amount_up = amount; self.amount_up = amount;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.amount_down = amount; self.amount_down = amount;
true true
} }

@ -1,10 +1,11 @@
use std::iter; use std::{f32::consts::PI, iter};
use cgmath::prelude::*; use cgmath::prelude::*;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -130,9 +131,9 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
window: Window, window: &'a Window,
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -219,8 +220,8 @@ fn create_render_pipeline(
}) })
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -230,11 +231,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -248,10 +245,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -280,6 +277,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -564,9 +562,9 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
virtual_keycode: Some(key), physical_key: PhysicalKey::Code(key),
state, state,
.. ..
}, },
@ -601,10 +599,11 @@ impl State {
// Update the light // Update the light
let old_position: cgmath::Vector3<_> = self.light_uniform.position.into(); let old_position: cgmath::Vector3<_> = self.light_uniform.position.into();
self.light_uniform.position = self.light_uniform.position = (cgmath::Quaternion::from_axis_angle(
(cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0)) (0.0, 1.0, 0.0).into(),
* old_position) cgmath::Deg(PI * dt.as_secs_f32()),
.into(); ) * old_position)
.into();
self.queue.write_buffer( self.queue.write_buffer(
&self.light_buffer, &self.light_buffer,
0, 0,
@ -686,7 +685,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -712,12 +711,10 @@ pub async fn run() {
.expect("Couldn't append canvas to document body."); .expect("Couldn't append canvas to document body.");
} }
let mut state = State::new(window).await; // NEW! let mut state = State::new(&window).await; // NEW!
let mut last_render_time = instant::Instant::now(); let mut last_render_time = instant::Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = ControlFlow::Poll;
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(),
// NEW! // NEW!
Event::DeviceEvent { Event::DeviceEvent {
event: DeviceEvent::MouseMotion{ delta, }, event: DeviceEvent::MouseMotion{ delta, },
@ -734,40 +731,38 @@ pub async fn run() {
#[cfg(not(target_arch="wasm32"))] #[cfg(not(target_arch="wasm32"))]
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), physical_key: PhysicalKey::Code(KeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => control_flow.exit(),
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
state.resize(*physical_size); state.resize(*physical_size);
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { // UPDATED!
state.resize(**new_inner_size); WindowEvent::RedrawRequested => {
state.window().request_redraw();
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => control_flow.exit(),
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
} }
_ => {} _ => {}
} }
} }
// UPDATED!
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
}
_ => {} _ => {}
} }
}); }).unwrap();
} }

@ -3,6 +3,7 @@ use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
const SAFE_FRAC_PI_2: f32 = FRAC_PI_2 - 0.0001; const SAFE_FRAC_PI_2: f32 = FRAC_PI_2 - 0.0001;
@ -97,34 +98,34 @@ impl CameraController {
} }
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool {
let amount = if state == ElementState::Pressed { let amount = if state == ElementState::Pressed {
1.0 1.0
} else { } else {
0.0 0.0
}; };
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.amount_forward = amount; self.amount_forward = amount;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.amount_backward = amount; self.amount_backward = amount;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.amount_left = amount; self.amount_left = amount;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.amount_right = amount; self.amount_right = amount;
true true
} }
VirtualKeyCode::Space => { KeyCode::Space => {
self.amount_up = amount; self.amount_up = amount;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.amount_down = amount; self.amount_down = amount;
true true
} }

@ -1,10 +1,11 @@
use std::iter; use std::{f32::consts::PI, iter};
use cgmath::prelude::*; use cgmath::prelude::*;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::EventLoop,
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -146,9 +147,9 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
window: Window, window: &'a Window,
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -238,26 +239,22 @@ fn create_render_pipeline(
}) })
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> anyhow::Result<Self> { async fn new(window: &'a Window) -> anyhow::Result<State<'a>> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
// BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
// UPDATED // UPDATED
#[cfg(target_arch="wasm32")] #[cfg(target_arch = "wasm32")]
backends: wgpu::Backends::BROWSER_WEBGPU, backends: wgpu::Backends::BROWSER_WEBGPU,
#[cfg(not(target_arch="wasm32"))] #[cfg(not(target_arch = "wasm32"))]
backends: wgpu::Backends::all(), backends: wgpu::Backends::all(),
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -272,9 +269,9 @@ impl State {
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
// UPDATED! // UPDATED!
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// UPDATED! // UPDATED!
limits: wgpu::Limits::downlevel_defaults(), required_limits: wgpu::Limits::downlevel_defaults(),
}, },
None, // Trace path None, // Trace path
) )
@ -299,6 +296,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -665,9 +663,9 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
virtual_keycode: Some(key), physical_key: PhysicalKey::Code(key),
state, state,
.. ..
}, },
@ -701,10 +699,11 @@ impl State {
// Update the light // Update the light
let old_position: cgmath::Vector3<_> = self.light_uniform.position.into(); let old_position: cgmath::Vector3<_> = self.light_uniform.position.into();
self.light_uniform.position = self.light_uniform.position = (cgmath::Quaternion::from_axis_angle(
(cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0)) (0.0, 1.0, 0.0).into(),
* old_position) cgmath::Deg(PI * dt.as_secs_f32()),
.into(); ) * old_position)
.into();
self.queue.write_buffer( self.queue.write_buffer(
&self.light_buffer, &self.light_buffer,
0, 0,
@ -816,7 +815,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -842,12 +841,10 @@ pub async fn run() {
.expect("Couldn't append canvas to document body."); .expect("Couldn't append canvas to document body.");
} }
let mut state = State::new(window).await.unwrap(); // NEW! let mut state = State::new(&window).await.unwrap();
let mut last_render_time = instant::Instant::now(); let mut last_render_time = instant::Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = ControlFlow::Poll;
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(),
Event::DeviceEvent { Event::DeviceEvent {
event: DeviceEvent::MouseMotion{ delta, }, event: DeviceEvent::MouseMotion{ delta, },
.. // We're not using device_id currently .. // We're not using device_id currently
@ -863,40 +860,38 @@ pub async fn run() {
#[cfg(not(target_arch="wasm32"))] #[cfg(not(target_arch="wasm32"))]
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), physical_key: PhysicalKey::Code(KeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => control_flow.exit(),
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
state.resize(*physical_size); state.resize(*physical_size);
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { // UPDATED!
state.resize(**new_inner_size); WindowEvent::RedrawRequested => {
state.window().request_redraw();
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => control_flow.exit(),
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
} }
_ => {} _ => {}
} }
} }
// UPDATED!
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
}
_ => {} _ => {}
} }
}); }).unwrap();
} }

@ -327,8 +327,7 @@ impl HdrLoader {
dst_size, dst_size,
self.texture_format, self.texture_format,
1, 1,
wgpu::TextureUsages::STORAGE_BINDING wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
| wgpu::TextureUsages::TEXTURE_BINDING,
wgpu::FilterMode::Nearest, wgpu::FilterMode::Nearest,
label, label,
); );
@ -356,7 +355,10 @@ impl HdrLoader {
}); });
let mut encoder = device.create_command_encoder(&Default::default()); let mut encoder = device.create_command_encoder(&Default::default());
let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label, timestamp_writes: None }); let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label,
timestamp_writes: None,
});
let num_workgroups = (dst_size + 15) / 16; let num_workgroups = (dst_size + 15) / 16;
pass.set_pipeline(&self.equirect_to_cubemap); pass.set_pipeline(&self.equirect_to_cubemap);

@ -239,10 +239,15 @@ impl CubeTexture {
} }
} }
pub fn texture(&self) -> &wgpu::Texture { &self.texture } pub fn texture(&self) -> &wgpu::Texture {
&self.texture
pub fn view(&self) -> &wgpu::TextureView { &self.view } }
pub fn sampler(&self) -> &wgpu::Sampler { &self.sampler } pub fn view(&self) -> &wgpu::TextureView {
&self.view
}
pub fn sampler(&self) -> &wgpu::Sampler {
&self.sampler
}
} }

@ -2,7 +2,7 @@ use std::marker::PhantomData;
pub struct Binder<B> { pub struct Binder<B> {
layout: wgpu::BindGroupLayout, layout: wgpu::BindGroupLayout,
_marker: PhantomData<B> _marker: PhantomData<B>,
} }
// pub trait Uniform // pub trait Uniform

@ -3,6 +3,7 @@ use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
@ -104,34 +105,34 @@ impl CameraController {
} }
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool {
let amount = if state == ElementState::Pressed { let amount = if state == ElementState::Pressed {
1.0 1.0
} else { } else {
0.0 0.0
}; };
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.amount_forward = amount; self.amount_forward = amount;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.amount_backward = amount; self.amount_backward = amount;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.amount_left = amount; self.amount_left = amount;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.amount_right = amount; self.amount_right = amount;
true true
} }
VirtualKeyCode::Space => { KeyCode::Space => {
self.amount_up = amount; self.amount_up = amount;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.amount_down = amount; self.amount_down = amount;
true true
} }

@ -5,18 +5,19 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
mod bindgroups;
mod camera; mod camera;
mod model; mod model;
mod resources; mod resources;
mod terrain; mod terrain;
mod texture; mod texture; // NEW!
mod bindgroups; // NEW!
use model::{DrawLight, DrawModel, Vertex}; use model::{DrawLight, DrawModel, Vertex};
@ -132,9 +133,9 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
window: Window, window: &'a Window,
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -220,8 +221,8 @@ fn create_render_pipeline(
}) })
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -231,11 +232,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -249,10 +246,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -281,6 +278,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -606,9 +604,9 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
virtual_keycode: Some(key), physical_key: PhysicalKey::Code(key),
state, state,
.. ..
}, },
@ -736,7 +734,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -763,13 +761,11 @@ pub async fn run() {
.expect("Couldn't append canvas to document body."); .expect("Couldn't append canvas to document body.");
} }
let mut state = State::new(window).await; // NEW! let mut state = State::new(&window).await; // NEW!
state.window().set_visible(true); state.window().set_visible(true);
let mut last_render_time = instant::Instant::now(); let mut last_render_time = instant::Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = ControlFlow::Poll;
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(),
// NEW! // NEW!
Event::DeviceEvent { Event::DeviceEvent {
event: DeviceEvent::MouseMotion{ delta, }, event: DeviceEvent::MouseMotion{ delta, },
@ -786,40 +782,37 @@ pub async fn run() {
#[cfg(not(target_arch="wasm32"))] #[cfg(not(target_arch="wasm32"))]
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), physical_key: PhysicalKey::Code(KeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => control_flow.exit(),
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
state.resize(*physical_size); state.resize(*physical_size);
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { // UPDATED!
state.resize(**new_inner_size); WindowEvent::RedrawRequested => {
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => control_flow.exit(),
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
} }
_ => {} _ => {}
} }
} }
// UPDATED!
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
}
_ => {} _ => {}
} }
}); }).unwrap();
} }

@ -241,8 +241,7 @@ impl GenerateChunk for TerrainPipeline {
let gen_buffer = device.create_buffer(&wgpu::BufferDescriptor { let gen_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("TerrainPipeline: ChunkData"), label: Some("TerrainPipeline: ChunkData"),
size: size_of_val(&data) as _, size: size_of_val(&data) as _,
usage: wgpu::BufferUsages::UNIFORM usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
| wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
queue.write_buffer(&gen_buffer, 0, bytemuck::bytes_of(&data)); queue.write_buffer(&gen_buffer, 0, bytemuck::bytes_of(&data));

@ -63,7 +63,14 @@ impl Texture {
address_mode: AddressMode, // NEW! address_mode: AddressMode, // NEW!
) -> Result<Self> { ) -> Result<Self> {
let img = image::load_from_memory(bytes)?; let img = image::load_from_memory(bytes)?;
Self::from_image(device, queue, &img, Some(label), is_normal_map, address_mode) // UPDATED! Self::from_image(
device,
queue,
&img,
Some(label),
is_normal_map,
address_mode,
) // UPDATED!
} }
pub fn from_image( pub fn from_image(
@ -117,7 +124,7 @@ impl Texture {
let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor { let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
// UPDATED! // UPDATED!
address_mode_u: address_mode, address_mode_u: address_mode,
address_mode_v: address_mode, address_mode_v: address_mode,
address_mode_w: address_mode, address_mode_w: address_mode,
mag_filter: wgpu::FilterMode::Linear, mag_filter: wgpu::FilterMode::Linear,

@ -3,6 +3,7 @@ use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
@ -104,34 +105,34 @@ impl CameraController {
} }
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool {
let amount = if state == ElementState::Pressed { let amount = if state == ElementState::Pressed {
1.0 1.0
} else { } else {
0.0 0.0
}; };
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.amount_forward = amount; self.amount_forward = amount;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.amount_backward = amount; self.amount_backward = amount;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.amount_left = amount; self.amount_left = amount;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.amount_right = amount; self.amount_right = amount;
true true
} }
VirtualKeyCode::Space => { KeyCode::Space => {
self.amount_up = amount; self.amount_up = amount;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.amount_down = amount; self.amount_down = amount;
true true
} }

@ -6,6 +6,7 @@ use winit::{
dpi::PhysicalPosition, dpi::PhysicalPosition,
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -129,8 +130,8 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -155,11 +156,11 @@ struct State {
debug_material: model::Material, debug_material: model::Material,
last_mouse_pos: PhysicalPosition<f64>, last_mouse_pos: PhysicalPosition<f64>,
mouse_pressed: bool, mouse_pressed: bool,
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -169,11 +170,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -187,10 +184,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -219,6 +216,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -506,9 +504,9 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
virtual_keycode: Some(key), physical_key: PhysicalKey::Code(key),
state, state,
.. ..
}, },
@ -636,18 +634,16 @@ fn main() {
async fn run() { async fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
.build(&event_loop) .build(&event_loop)
.unwrap(); .unwrap();
let mut state = State::new(window).await; // NEW! let mut state = State::new(&window).await; // NEW!
let mut last_render_time = std::time::Instant::now(); let mut last_render_time = std::time::Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop
*control_flow = ControlFlow::Poll; .run(move |event, control_flow| match event {
match event {
Event::MainEventsCleared => state.window().request_redraw(),
Event::WindowEvent { Event::WindowEvent {
ref event, ref event,
window_id, window_id,
@ -656,32 +652,30 @@ async fn run() {
match event { match event {
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), physical_key: PhysicalKey::Code(KeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => control_flow.exit(),
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
state.resize(*physical_size); state.resize(*physical_size);
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { WindowEvent::RedrawRequested => {
state.resize(**new_inner_size); state.window.request_redraw();
let now = std::time::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
state.render();
} }
_ => {} _ => {}
} }
} }
} }
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
let now = std::time::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
state.render();
}
_ => {} _ => {}
} })
}); .unwrap();
} }

@ -298,7 +298,10 @@ impl ModelLoader {
m.mesh.positions[i * 3 + 2], m.mesh.positions[i * 3 + 2],
], ],
// tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1], 0.0] // tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1], 0.0]
tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], tex_coords: [
m.mesh.texcoords[i * 2],
1.0 - m.mesh.texcoords[i * 2 + 1],
],
normal: [ normal: [
m.mesh.normals[i * 3], m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1], m.mesh.normals[i * 3 + 1],

@ -3,6 +3,7 @@ use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
@ -104,34 +105,34 @@ impl CameraController {
} }
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool {
let amount = if state == ElementState::Pressed { let amount = if state == ElementState::Pressed {
1.0 1.0
} else { } else {
0.0 0.0
}; };
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.amount_forward = amount; self.amount_forward = amount;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.amount_backward = amount; self.amount_backward = amount;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.amount_left = amount; self.amount_left = amount;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.amount_right = amount; self.amount_right = amount;
true true
} }
VirtualKeyCode::Space => { KeyCode::Space => {
self.amount_up = amount; self.amount_up = amount;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.amount_down = amount; self.amount_down = amount;
true true
} }

@ -21,24 +21,25 @@ use std::time::{Duration, Instant};
use wgpu::util::{BufferInitDescriptor, DeviceExt}; use wgpu::util::{BufferInitDescriptor, DeviceExt};
use winit::event::*; use winit::event::*;
use winit::event_loop::{ControlFlow, EventLoop}; use winit::event_loop::{ControlFlow, EventLoop};
use winit::keyboard::{KeyCode, PhysicalKey};
use winit::window::{Window, WindowBuilder}; use winit::window::{Window, WindowBuilder};
pub struct Display { pub struct Display<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
pub window: Window, pub window: &'a Window,
pub config: wgpu::SurfaceConfiguration, pub config: wgpu::SurfaceConfiguration,
pub device: wgpu::Device, pub device: wgpu::Device,
pub queue: wgpu::Queue, pub queue: wgpu::Queue,
} }
impl Display { impl<'a> Display<'a> {
pub async fn new(window: Window) -> Result<Self, Error> { pub async fn new(window: &'a Window) -> Result<Display<'a>, Error> {
let size = window.inner_size(); let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(), backends: wgpu::Backends::all(),
..Default::default() ..Default::default()
}); });
let surface = unsafe { instance.create_surface(&window) }.unwrap(); let surface = instance.create_surface(window).unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(), power_preference: wgpu::PowerPreference::default(),
@ -51,10 +52,10 @@ impl Display {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -82,6 +83,7 @@ impl Display {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -214,7 +216,7 @@ impl UniformBinding {
pub trait Demo: 'static + Sized { pub trait Demo: 'static + Sized {
fn init(display: &Display) -> Result<Self, Error>; fn init(display: &Display) -> Result<Self, Error>;
fn process_mouse(&mut self, dx: f64, dy: f64); fn process_mouse(&mut self, dx: f64, dy: f64);
fn process_keyboard(&mut self, key: VirtualKeyCode, pressed: bool); fn process_keyboard(&mut self, key: KeyCode, pressed: bool);
fn resize(&mut self, display: &Display); fn resize(&mut self, display: &Display);
fn update(&mut self, display: &Display, dt: Duration); fn update(&mut self, display: &Display, dt: Duration);
fn render(&mut self, display: &mut Display); fn render(&mut self, display: &mut Display);
@ -223,74 +225,71 @@ pub trait Demo: 'static + Sized {
pub async fn run<D: Demo>() -> Result<(), Error> { pub async fn run<D: Demo>() -> Result<(), Error> {
wgpu_subscriber::initialize_default_subscriber(None); wgpu_subscriber::initialize_default_subscriber(None);
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new() let window = WindowBuilder::new()
.with_title(env!("CARGO_PKG_NAME")) .with_title(env!("CARGO_PKG_NAME"))
.build(&event_loop)?; .build(&event_loop)?;
let mut display = Display::new(window).await?; let mut display = Display::new(&window).await?;
let mut demo = D::init(&display)?; let mut demo = D::init(&display)?;
let mut last_update = Instant::now(); let mut last_update = Instant::now();
let mut is_resumed = true; let mut is_resumed = true;
let mut is_focused = true; let mut is_focused = true;
let mut is_redraw_requested = true; let mut is_redraw_requested = true;
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = if is_resumed && is_focused { if is_resumed && is_focused {
ControlFlow::Poll control_flow.set_control_flow(ControlFlow::Poll)
} else { } else {
ControlFlow::Wait control_flow.set_control_flow(ControlFlow::Wait)
}; };
match event { match event {
Event::Resumed => is_resumed = true, Event::Resumed => is_resumed = true,
Event::Suspended => is_resumed = false, Event::Suspended => is_resumed = false,
Event::RedrawRequested(wid) => {
if wid == display.window().id() {
let now = Instant::now();
let dt = now - last_update;
last_update = now;
demo.update(&display, dt);
demo.render(&mut display);
is_redraw_requested = false;
}
}
Event::MainEventsCleared => {
if is_focused && is_resumed && !is_redraw_requested {
display.window().request_redraw();
is_redraw_requested = true;
} else {
// Freeze time while the demo is not in the foreground
last_update = Instant::now();
}
}
Event::WindowEvent { Event::WindowEvent {
event, window_id, .. event, window_id, ..
} => { } => {
if window_id == display.window().id() { if window_id == display.window().id() {
match event { match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::CloseRequested => control_flow.exit(),
WindowEvent::Focused(f) => is_focused = f, WindowEvent::Focused(f) => is_focused = f,
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
display.resize(new_inner_size.width, new_inner_size.height);
demo.resize(&display);
}
WindowEvent::Resized(new_inner_size) => { WindowEvent::Resized(new_inner_size) => {
display.resize(new_inner_size.width, new_inner_size.height); display.resize(new_inner_size.width, new_inner_size.height);
demo.resize(&display); demo.resize(&display);
} }
WindowEvent::KeyboardInput { input: KeyboardInput { WindowEvent::KeyboardInput {
virtual_keycode: Some(key), event:
state, KeyEvent {
physical_key: PhysicalKey::Code(key),
state,
..
},
.. ..
}, .. } => { } => {
demo.process_keyboard(key, state == ElementState::Pressed); demo.process_keyboard(key, state == ElementState::Pressed);
} }
WindowEvent::RedrawRequested => {
let now = Instant::now();
let dt = now - last_update;
last_update = now;
demo.update(&display, dt);
demo.render(&mut display);
if is_focused && is_resumed {
display.window().request_redraw();
} else {
// Freeze time while the demo is not in the foreground
last_update = Instant::now();
}
}
_ => {} _ => {}
} }
} }
} }
_ => {} _ => {}
} }
}); })?;
Ok(())
} }

@ -1,7 +1,7 @@
use anyhow::*; use anyhow::*;
use image::GenericImageView; use image::GenericImageView;
use std::path::Path;
use std::mem; use std::mem;
use std::path::Path;
use crate::buffer; use crate::buffer;

@ -16,10 +16,10 @@ async fn run() {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: Some("Device"), label: Some("Device"),
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()

@ -7,7 +7,7 @@ use winit::{
}; };
async fn run() -> anyhow::Result<()> { async fn run() -> anyhow::Result<()> {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let mut window = Some( let mut window = Some(
WindowBuilder::new() WindowBuilder::new()
.with_visible(false) .with_visible(false)
@ -31,7 +31,7 @@ async fn run() -> anyhow::Result<()> {
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: Default::default(), features: Default::default(),
limits: Default::default(), required_limits: Default::default(),
}, },
None, None,
) )

@ -3,6 +3,7 @@ use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
@ -104,34 +105,34 @@ impl CameraController {
} }
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { pub fn process_keyboard(&mut self, key: KeyCode, state: ElementState) -> bool {
let amount = if state == ElementState::Pressed { let amount = if state == ElementState::Pressed {
1.0 1.0
} else { } else {
0.0 0.0
}; };
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { KeyCode::KeyW | KeyCode::ArrowUp => {
self.amount_forward = amount; self.amount_forward = amount;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.amount_backward = amount; self.amount_backward = amount;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.amount_left = amount; self.amount_left = amount;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.amount_right = amount; self.amount_right = amount;
true true
} }
VirtualKeyCode::Space => { KeyCode::Space => {
self.amount_up = amount; self.amount_up = amount;
true true
} }
VirtualKeyCode::LShift => { KeyCode::ShiftLeft => {
self.amount_down = amount; self.amount_down = amount;
true true
} }

@ -6,6 +6,7 @@ use wgpu::util::DeviceExt;
use winit::{ use winit::{
event::*, event::*,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
@ -131,9 +132,9 @@ struct LightUniform {
_padding2: u32, _padding2: u32,
} }
struct State { struct State<'a> {
window: Window, window: &'a Window,
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -224,8 +225,8 @@ fn create_render_pipeline(
}) })
} }
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -235,11 +236,7 @@ impl State {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -253,10 +250,10 @@ impl State {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web we'll have to disable some. // we're building for the web we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -285,6 +282,7 @@ impl State {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
@ -577,9 +575,9 @@ impl State {
fn input(&mut self, event: &WindowEvent) -> bool { fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
virtual_keycode: Some(key), physical_key: PhysicalKey::Code(key),
state, state,
.. ..
}, },
@ -733,7 +731,7 @@ pub async fn run() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let title = env!("CARGO_PKG_NAME"); let title = env!("CARGO_PKG_NAME");
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title(title) .with_title(title)
@ -759,12 +757,10 @@ pub async fn run() {
.expect("Couldn't append canvas to document body."); .expect("Couldn't append canvas to document body.");
} }
let mut state = State::new(window).await; // NEW! let mut state = State::new(&window).await; // NEW!
let mut last_render_time = instant::Instant::now(); let mut last_render_time = instant::Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = ControlFlow::Poll;
match event { match event {
Event::MainEventsCleared => state.window().request_redraw(),
// NEW! // NEW!
Event::DeviceEvent { Event::DeviceEvent {
event: DeviceEvent::MouseMotion{ delta, }, event: DeviceEvent::MouseMotion{ delta, },
@ -781,40 +777,38 @@ pub async fn run() {
#[cfg(not(target_arch="wasm32"))] #[cfg(not(target_arch="wasm32"))]
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), physical_key: PhysicalKey::Code(KeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => control_flow.exit(),
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
state.resize(*physical_size); state.resize(*physical_size);
} }
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { // UPDATED!
state.resize(**new_inner_size); WindowEvent::RedrawRequested => {
state.window.request_redraw();
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => control_flow.exit(),
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
} }
_ => {} _ => {}
} }
} }
// UPDATED!
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
let now = instant::Instant::now();
let dt = now - last_render_time;
last_render_time = now;
state.update(dt);
match state.render() {
Ok(_) => {}
// Reconfigure the surface if it's lost or outdated
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => state.resize(state.size),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// We're ignoring timeouts
Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
}
}
_ => {} _ => {}
} }
}); }).unwrap();
} }

@ -27,7 +27,7 @@ pub fn start() {
} }
} }
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let monitor = event_loop.primary_monitor().unwrap(); let monitor = event_loop.primary_monitor().unwrap();
let video_mode = monitor.video_modes().next(); let video_mode = monitor.video_modes().next();
let size = video_mode let size = video_mode
@ -159,7 +159,7 @@ pub fn start() {
log::info!("Event Loop..."); log::info!("Event Loop...");
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = if state.game_state == state::GameState::Quiting { *control_flow = if state.game_state == state::GameState::Quiting {
ControlFlow::Exit ControlFlow::Exit
} else { } else {

@ -45,11 +45,7 @@ impl Render {
..Default::default() ..Default::default()
}); });
// # Safety let surface = instance.create_surface(window).unwrap();
//
// The surface needs to live as long as the window that created it.
// State owns the window so this should be safe.
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
@ -63,8 +59,8 @@ impl Render {
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
limits: wgpu::Limits::downlevel_webgl2_defaults(), required_limits: wgpu::Limits::downlevel_webgl2_defaults(),
}, },
None, // Trace path None, // Trace path
) )
@ -89,6 +85,7 @@ impl Render {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);

@ -1,6 +1,9 @@
use std::{time::Duration, f32::consts::FRAC_PI_2}; use std::{f32::consts::FRAC_PI_2, time::Duration};
use winit::{event::{VirtualKeyCode, MouseScrollDelta}, dpi::PhysicalPosition}; use winit::{
dpi::PhysicalPosition,
event::{MouseScrollDelta, VirtualKeyCode},
};
const SAFE_FRAC_PI_2: f32 = FRAC_PI_2 - 0.0001; const SAFE_FRAC_PI_2: f32 = FRAC_PI_2 - 0.0001;
@ -12,11 +15,7 @@ pub struct Camera {
} }
impl Camera { impl Camera {
pub fn new<V: Into<glam::Vec3>>( pub fn new<V: Into<glam::Vec3>>(position: V, yaw: f32, pitch: f32) -> Self {
position: V,
yaw: f32,
pitch: f32,
) -> Self {
Self { Self {
position: position.into(), position: position.into(),
yaw, yaw,
@ -95,11 +94,7 @@ impl CameraController {
} }
pub fn process_keyboard(&mut self, key: VirtualKeyCode, pressed: bool) -> bool { pub fn process_keyboard(&mut self, key: VirtualKeyCode, pressed: bool) -> bool {
let amount = if pressed { let amount = if pressed { 1.0 } else { 0.0 };
1.0
} else {
0.0
};
match key { match key {
VirtualKeyCode::W | VirtualKeyCode::Up => { VirtualKeyCode::W | VirtualKeyCode::Up => {
self.amount_forward = amount; self.amount_forward = amount;
@ -183,4 +178,4 @@ impl CameraController {
camera.pitch = SAFE_FRAC_PI_2; camera.pitch = SAFE_FRAC_PI_2;
} }
} }
} }

@ -2,7 +2,7 @@ mod camera;
use std::f32::consts::PI; use std::f32::consts::PI;
use camera::{Camera, Projection, CameraController}; use camera::{Camera, CameraController, Projection};
use wgpu::util::{BufferInitDescriptor, DeviceExt}; use wgpu::util::{BufferInitDescriptor, DeviceExt};
const MAX_PARTICLES: u32 = 1000; const MAX_PARTICLES: u32 = 1000;
@ -181,21 +181,25 @@ impl framework::Demo for Snow {
entries: &[wgpu::BindGroupLayoutEntry { entries: &[wgpu::BindGroupLayoutEntry {
binding: 0, binding: 0,
visibility: wgpu::ShaderStages::VERTEX, visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None }, ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None, count: None,
}], }],
}); });
let uniforms_bind_group = display.device.create_bind_group(&wgpu::BindGroupDescriptor { let uniforms_bind_group = display
label: Some("uniforms_bind_group"), .device
layout: &uniforms_bind_group_layout, .create_bind_group(&wgpu::BindGroupDescriptor {
entries: &[ label: Some("uniforms_bind_group"),
wgpu::BindGroupEntry { layout: &uniforms_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0, binding: 0,
resource: uniform_buffer.as_entire_binding(), resource: uniform_buffer.as_entire_binding(),
} }],
], });
});
let draw_particles_layout = let draw_particles_layout =
display display
@ -260,14 +264,15 @@ impl framework::Demo for Snow {
self.camera_controller.process_mouse(dx, dy); self.camera_controller.process_mouse(dx, dy);
self.uniforms_dirty = true; self.uniforms_dirty = true;
} }
fn process_keyboard(&mut self, key: winit::event::VirtualKeyCode, pressed: bool) { fn process_keyboard(&mut self, key: winit::event::VirtualKeyCode, pressed: bool) {
self.camera_controller.process_keyboard(key, pressed); self.camera_controller.process_keyboard(key, pressed);
self.uniforms_dirty = true; self.uniforms_dirty = true;
} }
fn resize(&mut self, display: &framework::Display) { fn resize(&mut self, display: &framework::Display) {
self.projection.resize(display.config.width, display.config.height); self.projection
.resize(display.config.width, display.config.height);
self.uniforms_dirty = true; self.uniforms_dirty = true;
self.uniforms_dirty = true; self.uniforms_dirty = true;
} }
@ -278,7 +283,9 @@ impl framework::Demo for Snow {
self.uniforms_dirty = false; self.uniforms_dirty = false;
self.camera_controller.update_camera(&mut self.camera, dt); self.camera_controller.update_camera(&mut self.camera, dt);
self.uniforms.view_proj = self.projection.calc_matrix() * self.camera.calc_matrix(); self.uniforms.view_proj = self.projection.calc_matrix() * self.camera.calc_matrix();
display.queue.write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&self.uniforms)); display
.queue
.write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&self.uniforms));
} }
let dt = dt.as_secs_f32(); let dt = dt.as_secs_f32();

@ -1,9 +1,9 @@
use cgmath::*; use cgmath::*;
use winit::keyboard::KeyCode;
use std::f32::consts::FRAC_PI_2; use std::f32::consts::FRAC_PI_2;
use std::time::Duration; use std::time::Duration;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::*; use winit::event::*;
use winit::keyboard::KeyCode;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(

@ -39,7 +39,7 @@ use winit::{
pub fn run() { pub fn run() {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| match event { event_loop.run(move |event, _, control_flow| match event {

@ -7,8 +7,8 @@ For convenience, we're going to pack all the fields into a struct and create som
// lib.rs // lib.rs
use winit::window::Window; use winit::window::Window;
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -16,12 +16,12 @@ struct State {
// The window must be declared after the surface so // The window must be declared after the surface so
// it gets dropped after it as the surface contains // it gets dropped after it as the surface contains
// unsafe references to the window's resources. // unsafe references to the window's resources.
window: Window, window: &'a Window,
} }
impl State { impl<'a> State<'a> {
// Creating some of the wgpu types requires async code // Creating some of the wgpu types requires async code
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
todo!() todo!()
} }
@ -53,9 +53,9 @@ I'm glossing over `State`s fields, but they'll make more sense as I explain the
The code for this is pretty straightforward, but let's break it down a bit. The code for this is pretty straightforward, but let's break it down a bit.
```rust ```rust
impl State { impl<'a> State<'a> {
// ... // ...
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
let size = window.inner_size(); let size = window.inner_size();
// The instance is a handle to our GPU // The instance is a handle to our GPU
@ -127,10 +127,10 @@ Let's use the `adapter` to create the device and queue.
```rust ```rust
let (device, queue) = adapter.request_device( let (device, queue) = adapter.request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
// WebGL doesn't support all of wgpu's features, so if // WebGL doesn't support all of wgpu's features, so if
// we're building for the web, we'll have to disable some. // we're building for the web, we'll have to disable some.
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits::default() wgpu::Limits::default()
@ -145,7 +145,7 @@ The `features` field on `DeviceDescriptor` allows us to specify what extra featu
<div class="note"> <div class="note">
The graphics card you have limits the features you can use. If you want to use certain features, you may need to limit what devices you support or provide workarounds. The graphics card you haverequired_limits the features you can use. If you want to use certain features, you may need to limit what devices you support or provide workarounds.
You can get a list of features supported by your device using `adapter.features()` or `device.features()`. You can get a list of features supported by your device using `adapter.features()` or `device.features()`.
@ -153,7 +153,7 @@ You can view a full list of features [here](https://docs.rs/wgpu/latest/wgpu/str
</div> </div>
The `limits` field describes the limit of certain types of resources that we can create. We'll use the defaults for this tutorial so we can support most devices. You can view a list of limits [here](https://docs.rs/wgpu/latest/wgpu/struct.Limits.html). The `limits` field describes the limit of certain types of resources that we can create. We'll use the defaults for this tutorial so we can support most devices. You can view a list ofrequired_limits [here](https://docs.rs/wgpu/latest/wgpu/struct.Limits.html).
```rust ```rust
let surface_caps = surface.get_capabilities(&adapter); let surface_caps = surface.get_capabilities(&adapter);
@ -173,6 +173,7 @@ The `limits` field describes the limit of certain types of resources that we can
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&device, &config); surface.configure(&device, &config);
``` ```
@ -210,7 +211,7 @@ Regardless, `PresentMode::Fifo` will always be supported, and `PresentMode::Auto
Now that we've configured our surface properly, we can add these new fields at the end of the method. Now that we've configured our surface properly, we can add these new fields at the end of the method.
```rust ```rust
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
// ... // ...
Self { Self {
@ -233,9 +234,9 @@ Our `window` has beened moved to the State instance, we will need to update our
pub async fn run() { pub async fn run() {
// Window setup... // Window setup...
let mut state = State::new(window).await; let mut state = State::new(&window).await;
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
match event { match event {
Event::WindowEvent { Event::WindowEvent {
ref event, ref event,

@ -156,8 +156,8 @@ This is the part where we finally make the thing in the title: the pipeline. Fir
```rust ```rust
// lib.rs // lib.rs
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,

@ -247,7 +247,7 @@ struct State {
num_vertices: u32, num_vertices: u32,
} }
impl State { impl<'a> State<'a> {
// ... // ...
fn new(...) -> Self { fn new(...) -> Self {
// ... // ...
@ -380,8 +380,8 @@ let num_indices = INDICES.len() as u32;
We don't need to implement `Pod` and `Zeroable` for our indices because `bytemuck` has already implemented them for basic types such as `u16`. That means we can just add `index_buffer` and `num_indices` to the `State` struct. We don't need to implement `Pod` and `Zeroable` for our indices because `bytemuck` has already implemented them for basic types such as `u16`. That means we can just add `index_buffer` and `num_indices` to the `State` struct.
```rust ```rust
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,

@ -242,8 +242,8 @@ Looking at this, you might get a bit of déjà vu! That's because a `BindGroup`
Now that we have our `diffuse_bind_group`, let's add it to our `State` struct: Now that we have our `diffuse_bind_group`, let's add it to our `State` struct:
```rust ```rust
struct State { struct State<'a> {
surface: wgpu::Surface, surface: wgpu::Surface<'a>,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
@ -259,7 +259,7 @@ struct State {
Make sure we return these fields in the `new` method: Make sure we return these fields in the `new` method:
```rust ```rust
impl State { impl<'a> State<'a> {
async fn new() -> Self { async fn new() -> Self {
// ... // ...
Self { Self {
@ -593,7 +593,7 @@ struct State {
``` ```
```rust ```rust
impl State { impl<'a> State<'a> {
async fn new() -> Self { async fn new() -> Self {
// ... // ...
Self { Self {

@ -310,20 +310,19 @@ impl CameraController {
.. ..
} => { } => {
let is_pressed = *state == ElementState::Pressed; let is_pressed = *state == ElementState::Pressed;
match keycode { match keycode {KeyCode::KeyW | KeyCode::ArrowUp => {
VirtualKeyCode::W | VirtualKeyCode::Up => {
self.is_forward_pressed = is_pressed; self.is_forward_pressed = is_pressed;
true true
} }
VirtualKeyCode::A | VirtualKeyCode::Left => { KeyCode::KeyA | KeyCode::ArrowLeft => {
self.is_left_pressed = is_pressed; self.is_left_pressed = is_pressed;
true true
} }
VirtualKeyCode::S | VirtualKeyCode::Down => { KeyCode::KeyS | KeyCode::ArrowDown => {
self.is_backward_pressed = is_pressed; self.is_backward_pressed = is_pressed;
true true
} }
VirtualKeyCode::D | VirtualKeyCode::Right => { KeyCode::KeyD | KeyCode::ArrowRight => {
self.is_right_pressed = is_pressed; self.is_right_pressed = is_pressed;
true true
} }
@ -381,8 +380,8 @@ struct State {
// ... // ...
} }
// ... // ...
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
// ... // ...
let camera_controller = CameraController::new(0.2); let camera_controller = CameraController::new(0.2);
// ... // ...

@ -97,8 +97,8 @@ const INSTANCE_DISPLACEMENT: cgmath::Vector3<f32> = cgmath::Vector3::new(NUM_INS
Now, we can create the actual instances. Now, we can create the actual instances.
```rust ```rust
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
// ... // ...
let instances = (0..NUM_INSTANCES_PER_ROW).flat_map(|z| { let instances = (0..NUM_INSTANCES_PER_ROW).flat_map(|z| {
(0..NUM_INSTANCES_PER_ROW).map(move |x| { (0..NUM_INSTANCES_PER_ROW).map(move |x| {

@ -453,7 +453,7 @@ where
Finally, we want to add Light rendering to our render passes. Finally, we want to add Light rendering to our render passes.
```rust ```rust
impl State { impl<'a> State<'a> {
// ... // ...
fn render(&mut self) -> Result<(), wgpu::SurfaceError> { fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
// ... // ...

@ -568,7 +568,7 @@ I found a cobblestone texture with a matching normal map and created a `debug_ma
```rust ```rust
// lib.rs // lib.rs
impl State { impl<'a> State<'a> {
async fn new(window: &Window) -> Result<Self> { async fn new(window: &Window) -> Result<Self> {
// ... // ...
let debug_material = { let debug_material = {

@ -293,8 +293,8 @@ You'll need to import `winit::dpi::PhysicalPosition` if you haven't already.
We need to update `new()` as well. We need to update `new()` as well.
```rust ```rust
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> Self { async fn new(window: &'a Window) -> State<'a> {
// ... // ...
// UPDATED! // UPDATED!
@ -369,8 +369,7 @@ Here are the changes to `run()`:
```rust ```rust
fn main() { fn main() {
// ... // ...
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = ControlFlow::Poll;
match event { match event {
// ... // ...
// NEW! // NEW!
@ -389,14 +388,14 @@ fn main() {
#[cfg(not(target_arch="wasm32"))] #[cfg(not(target_arch="wasm32"))]
WindowEvent::CloseRequested WindowEvent::CloseRequested
| WindowEvent::KeyboardInput { | WindowEvent::KeyboardInput {
input: event:
KeyboardInput { KeyEvent {
state: ElementState::Pressed, state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape), physical_key: PhysicalKey::Code(KeyCode::Escape),
.. ..
}, },
.. ..
} => *control_flow = ControlFlow::Exit, } => control_flow.exit(),
WindowEvent::Resized(physical_size) => { WindowEvent::Resized(physical_size) => {
state.resize(*physical_size); state.resize(*physical_size);
} }
@ -437,10 +436,9 @@ We still need to calculate `dt`. Let's do that in the `main` function.
```rust ```rust
fn main() { fn main() {
// ... // ...
let mut state = State::new(window).await; let mut state = State::new(&window).await;
let mut last_render_time = instant::Instant::now(); // NEW! let mut last_render_time = instant::Instant::now(); // NEW!
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, control_flow| {
*control_flow = ControlFlow::Poll;
match event { match event {
// ... // ...
// UPDATED! // UPDATED!

@ -1,6 +1,6 @@
# High Dynamic Range Rendering # High Dynamic Range Rendering
Up to this point, we've been using the sRGB colorspace to render our scene. While this is fine, it limits what we can do with our lighting. We are using `TextureFormat::Bgra8UnormSrgb` (on most systems) for our surface texture. This means we have 8 bits for each red, green, blue and alpha channel. While the channels are stored as integers between 0 and 255 inclusively, they get converted to and from floating point values between 0.0 and 1.0. The TL:DR of this is that using 8-bit textures, we only get 256 possible values in each channel. Up to this point, we've been using the sRGB colorspace to render our scene. While this is fine, itrequired_limits what we can do with our lighting. We are using `TextureFormat::Bgra8UnormSrgb` (on most systems) for our surface texture. This means we have 8 bits for each red, green, blue and alpha channel. While the channels are stored as integers between 0 and 255 inclusively, they get converted to and from floating point values between 0.0 and 1.0. The TL:DR of this is that using 8-bit textures, we only get 256 possible values in each channel.
The kicker with this is most of the precision gets used to represent darker values of the scene. This means that bright objects like light bulbs have the same value as exceedingly bright objects like the sun. This inaccuracy makes realistic lighting difficult to do right. Because of this, we are going to switch our rendering system to use high dynamic range in order to give our scene more flexibility and enable us to leverage more advanced techniques such as Physically Based Rendering. The kicker with this is most of the precision gets used to represent darker values of the scene. This means that bright objects like light bulbs have the same value as exceedingly bright objects like the sun. This inaccuracy makes realistic lighting difficult to do right. Because of this, we are going to switch our rendering system to use high dynamic range in order to give our scene more flexibility and enable us to leverage more advanced techniques such as Physically Based Rendering.
@ -290,7 +290,7 @@ struct State {
hdr: hdr::HdrPipeline, hdr: hdr::HdrPipeline,
} }
impl State { impl<'a> State<'a> {
pub fn new(window: Window) -> anyhow::Result<Self> { pub fn new(window: Window) -> anyhow::Result<Self> {
// ... // ...
// NEW! // NEW!
@ -477,7 +477,7 @@ let (device, queue) = adapter
// UPDATED! // UPDATED!
features: wgpu::Features::all_webgpu_mask(), features: wgpu::Features::all_webgpu_mask(),
// UPDATED! // UPDATED!
limits: wgpu::Limits::downlevel_defaults(), required_limits: wgpu::Limits::downlevel_defaults(),
}, },
None, // Trace path None, // Trace path
) )
@ -910,8 +910,8 @@ struct State {
} }
// ... // ...
impl State { impl<'a> State<'a> {
async fn new(window: Window) -> anyhow::Result<Self> { async fn new(window: &'a Window) -> anyhow::Result<State<'a>> {
// ... // ...
Ok(Self { Ok(Self {
// ... // ...

Loading…
Cancel
Save