|
|
|
@ -158,6 +158,11 @@ impl Instance {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct State {
|
|
|
|
|
surface: wgpu::Surface,
|
|
|
|
|
device: wgpu::Device,
|
|
|
|
|
queue: wgpu::Queue,
|
|
|
|
|
sc_desc: wgpu::SwapChainDescriptor,
|
|
|
|
|
swap_chain: wgpu::SwapChain,
|
|
|
|
|
render_pipeline: wgpu::RenderPipeline,
|
|
|
|
|
obj_model: model::Model,
|
|
|
|
|
camera: Camera,
|
|
|
|
@ -169,13 +174,41 @@ struct State {
|
|
|
|
|
instance_buffer: wgpu::Buffer,
|
|
|
|
|
depth_texture: wgpu::Texture,
|
|
|
|
|
depth_texture_view: wgpu::TextureView,
|
|
|
|
|
size: winit::dpi::PhysicalSize<u32>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
|
fn new(
|
|
|
|
|
sc_desc: &wgpu::SwapChainDescriptor,
|
|
|
|
|
device: &wgpu::Device,
|
|
|
|
|
) -> (Self, Option<Vec<wgpu::CommandBuffer>>) {
|
|
|
|
|
async fn new(window: &Window) -> Self {
|
|
|
|
|
let size = window.inner_size();
|
|
|
|
|
|
|
|
|
|
let surface = wgpu::Surface::create(window);
|
|
|
|
|
|
|
|
|
|
let adapter = wgpu::Adapter::request(
|
|
|
|
|
&wgpu::RequestAdapterOptions {
|
|
|
|
|
power_preference: wgpu::PowerPreference::Default,
|
|
|
|
|
compatible_surface: Some(&surface),
|
|
|
|
|
},
|
|
|
|
|
wgpu::BackendBit::PRIMARY, // Vulkan + Metal + DX12 + Browser WebGPU
|
|
|
|
|
).await.unwrap();
|
|
|
|
|
|
|
|
|
|
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
|
|
|
|
|
extensions: wgpu::Extensions {
|
|
|
|
|
anisotropic_filtering: false,
|
|
|
|
|
},
|
|
|
|
|
limits: Default::default(),
|
|
|
|
|
}).await;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let sc_desc = wgpu::SwapChainDescriptor {
|
|
|
|
|
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
|
|
|
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
|
|
|
|
width: size.width,
|
|
|
|
|
height: size.height,
|
|
|
|
|
present_mode: wgpu::PresentMode::Fifo,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
|
|
|
|
|
|
|
|
let texture_bind_group_layout =
|
|
|
|
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
|
|
|
bindings: &[
|
|
|
|
@ -300,7 +333,7 @@ impl State {
|
|
|
|
|
"code/beginner/tutorial9-models/src/res/cube.obj",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
queue.submit(&cmds);
|
|
|
|
|
let vs_src = include_str!("shader.vert");
|
|
|
|
|
let fs_src = include_str!("shader.frag");
|
|
|
|
|
let vs_spirv = glsl_to_spirv::compile(vs_src, glsl_to_spirv::ShaderType::Vertex).unwrap();
|
|
|
|
@ -360,7 +393,12 @@ impl State {
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let state = Self {
|
|
|
|
|
Self {
|
|
|
|
|
surface,
|
|
|
|
|
device,
|
|
|
|
|
queue,
|
|
|
|
|
sc_desc,
|
|
|
|
|
swap_chain,
|
|
|
|
|
render_pipeline,
|
|
|
|
|
obj_model,
|
|
|
|
|
camera,
|
|
|
|
@ -372,34 +410,31 @@ impl State {
|
|
|
|
|
instance_buffer,
|
|
|
|
|
depth_texture,
|
|
|
|
|
depth_texture_view,
|
|
|
|
|
};
|
|
|
|
|
(state, Some(cmds))
|
|
|
|
|
size,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn resize(
|
|
|
|
|
&mut self,
|
|
|
|
|
sc_desc: &wgpu::SwapChainDescriptor,
|
|
|
|
|
device: &wgpu::Device,
|
|
|
|
|
) -> Option<wgpu::CommandBuffer> {
|
|
|
|
|
self.depth_texture = texture::Texture::create_depth_texture(device, sc_desc).texture;
|
|
|
|
|
async fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
|
|
|
|
self.depth_texture = texture::Texture::create_depth_texture(&self.device, &self.sc_desc).texture;
|
|
|
|
|
self.depth_texture_view = self.depth_texture.create_default_view();
|
|
|
|
|
self.camera.aspect = sc_desc.width as f32 / sc_desc.height as f32;
|
|
|
|
|
|
|
|
|
|
None
|
|
|
|
|
self.camera.aspect = self.sc_desc.width as f32 / self.sc_desc.height as f32;
|
|
|
|
|
self.size = new_size;
|
|
|
|
|
self.sc_desc.width = new_size.width;
|
|
|
|
|
self.sc_desc.height = new_size.height;
|
|
|
|
|
self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn input(&mut self, event: &WindowEvent) -> bool {
|
|
|
|
|
self.camera_controller.process_events(event)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update(&mut self, device: &wgpu::Device) -> Option<wgpu::CommandBuffer> {
|
|
|
|
|
async fn update(&mut self) {
|
|
|
|
|
self.camera_controller.update_camera(&mut self.camera);
|
|
|
|
|
self.uniforms.update_view_proj(&self.camera);
|
|
|
|
|
|
|
|
|
|
let mut encoder =
|
|
|
|
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
|
|
|
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
|
|
|
|
|
|
|
|
let staging_buffer = device.create_buffer_with_data(
|
|
|
|
|
let staging_buffer = self.device.create_buffer_with_data(
|
|
|
|
|
bytemuck::cast_slice(&[self.uniforms]),
|
|
|
|
|
wgpu::BufferUsage::COPY_SRC,
|
|
|
|
|
);
|
|
|
|
@ -412,16 +447,14 @@ impl State {
|
|
|
|
|
std::mem::size_of::<Uniforms>() as wgpu::BufferAddress,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Some(encoder.finish())
|
|
|
|
|
self.queue.submit(&[encoder.finish()]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn render(
|
|
|
|
|
&mut self,
|
|
|
|
|
frame: &wgpu::SwapChainOutput,
|
|
|
|
|
device: &wgpu::Device,
|
|
|
|
|
) -> wgpu::CommandBuffer {
|
|
|
|
|
async fn render(&mut self) {
|
|
|
|
|
let frame = self.swap_chain.get_next_texture()
|
|
|
|
|
.expect("Timeout getting texture");
|
|
|
|
|
let mut encoder =
|
|
|
|
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
|
|
|
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
|
|
@ -456,105 +489,10 @@ impl State {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
encoder.finish()
|
|
|
|
|
self.queue.submit(&[encoder.finish()]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async fn run_async(event_loop: EventLoop<()>, window: Window) {
|
|
|
|
|
let size = window.inner_size();
|
|
|
|
|
let surface = wgpu::Surface::create(&window);
|
|
|
|
|
let adapter = wgpu::Adapter::request(
|
|
|
|
|
&wgpu::RequestAdapterOptions {
|
|
|
|
|
power_preference: wgpu::PowerPreference::Default,
|
|
|
|
|
compatible_surface: Some(&surface),
|
|
|
|
|
},
|
|
|
|
|
wgpu::BackendBit::PRIMARY,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
let (device, queue) = adapter
|
|
|
|
|
.request_device(&wgpu::DeviceDescriptor {
|
|
|
|
|
extensions: wgpu::Extensions {
|
|
|
|
|
anisotropic_filtering: false,
|
|
|
|
|
},
|
|
|
|
|
limits: wgpu::Limits::default(),
|
|
|
|
|
})
|
|
|
|
|
.await;
|
|
|
|
|
let mut sc_desc = wgpu::SwapChainDescriptor {
|
|
|
|
|
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
|
|
|
|
format: if cfg!(target_arch = "wasm32") {
|
|
|
|
|
wgpu::TextureFormat::Bgra8Unorm
|
|
|
|
|
} else {
|
|
|
|
|
wgpu::TextureFormat::Bgra8UnormSrgb
|
|
|
|
|
},
|
|
|
|
|
width: size.width,
|
|
|
|
|
height: size.height,
|
|
|
|
|
present_mode: wgpu::PresentMode::Mailbox,
|
|
|
|
|
};
|
|
|
|
|
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
|
|
|
|
|
|
|
|
let (mut state, init_cmds_buf) = State::new(&sc_desc, &device);
|
|
|
|
|
|
|
|
|
|
if let Some(cmds_buf) = init_cmds_buf {
|
|
|
|
|
queue.submit(&cmds_buf);
|
|
|
|
|
}
|
|
|
|
|
event_loop.run(move |event, _, control_flow| {
|
|
|
|
|
*control_flow = ControlFlow::Poll;
|
|
|
|
|
match event {
|
|
|
|
|
Event::MainEventsCleared => window.request_redraw(),
|
|
|
|
|
Event::WindowEvent {
|
|
|
|
|
ref event,
|
|
|
|
|
window_id,
|
|
|
|
|
} if window_id == window.id() => {
|
|
|
|
|
if !state.input(event) {
|
|
|
|
|
match event {
|
|
|
|
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
|
|
|
|
WindowEvent::KeyboardInput { input, .. } => match input {
|
|
|
|
|
KeyboardInput {
|
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
|
virtual_keycode: Some(VirtualKeyCode::Escape),
|
|
|
|
|
..
|
|
|
|
|
} => {
|
|
|
|
|
*control_flow = ControlFlow::Exit;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
},
|
|
|
|
|
WindowEvent::Resized(physical_size) => {
|
|
|
|
|
sc_desc.width = physical_size.width;
|
|
|
|
|
sc_desc.height = physical_size.height;
|
|
|
|
|
swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
|
|
|
|
|
|
|
|
let cmd_buf = state.resize(&sc_desc, &device);
|
|
|
|
|
if let Some(cmd_buf) = cmd_buf {
|
|
|
|
|
queue.submit(&[cmd_buf]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
|
|
|
|
sc_desc.width = new_inner_size.width;
|
|
|
|
|
sc_desc.height = new_inner_size.height;
|
|
|
|
|
swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
|
|
|
let cmd_buf = state.resize(&sc_desc, &device);
|
|
|
|
|
if let Some(cmd_buf) = cmd_buf {
|
|
|
|
|
queue.submit(&[cmd_buf]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Event::RedrawRequested(_) => {
|
|
|
|
|
if let Some(cmd_buf) = state.update(&device) {
|
|
|
|
|
queue.submit(&[cmd_buf]);
|
|
|
|
|
}
|
|
|
|
|
let frame = swap_chain
|
|
|
|
|
.get_next_texture()
|
|
|
|
|
.expect("Timeout when acquiring next swap chain texture");
|
|
|
|
|
let command_buf = state.render(&frame, &device);
|
|
|
|
|
queue.submit(&[command_buf]);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
let event_loop = EventLoop::new();
|
|
|
|
|
let title = "tutorial9-models";
|
|
|
|
@ -562,7 +500,46 @@ fn main() {
|
|
|
|
|
.with_title(title)
|
|
|
|
|
.build(&event_loop)
|
|
|
|
|
.unwrap();
|
|
|
|
|
futures::executor::block_on(run_async(event_loop, window));
|
|
|
|
|
use futures::executor::block_on;
|
|
|
|
|
let mut state = block_on(State::new(&window));
|
|
|
|
|
event_loop.run(move |event, _, control_flow| {
|
|
|
|
|
*control_flow = ControlFlow::Poll;
|
|
|
|
|
match event {
|
|
|
|
|
Event::MainEventsCleared => window.request_redraw(),
|
|
|
|
|
Event::WindowEvent {
|
|
|
|
|
ref event,
|
|
|
|
|
window_id,
|
|
|
|
|
} if window_id == window.id() => {
|
|
|
|
|
if !state.input(event) {
|
|
|
|
|
match event {
|
|
|
|
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
|
|
|
|
WindowEvent::KeyboardInput { input, .. } => match input {
|
|
|
|
|
KeyboardInput {
|
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
|
virtual_keycode: Some(VirtualKeyCode::Escape),
|
|
|
|
|
..
|
|
|
|
|
} => {
|
|
|
|
|
*control_flow = ControlFlow::Exit;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
},
|
|
|
|
|
WindowEvent::Resized(physical_size) => {
|
|
|
|
|
block_on(state.resize(*physical_size));
|
|
|
|
|
}
|
|
|
|
|
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
|
|
|
|
block_on(state.resize(**new_inner_size));
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Event::RedrawRequested(_) => {
|
|
|
|
|
block_on(state.update());
|
|
|
|
|
block_on(state.render());
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn matrix4f_cast_slice(a: &[Vec<cgmath::Matrix4<f32>>]) -> &[u8] {
|
|
|
|
|