mirror of https://github.com/sotrh/learn-wgpu
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.7 KiB
Rust
197 lines
6.7 KiB
Rust
use cgmath::*;
|
|
use std::time::Duration;
|
|
use winit::dpi::*;
|
|
use winit::event::*;
|
|
use winit::window::Window;
|
|
|
|
use crate::camera::*;
|
|
use crate::data::*;
|
|
use crate::pipeline::*;
|
|
use crate::resource::*;
|
|
|
|
pub struct Demo {
|
|
surface: wgpu::Surface,
|
|
#[allow(dead_code)]
|
|
adapter: wgpu::Adapter,
|
|
device: wgpu::Device,
|
|
queue: wgpu::Queue,
|
|
sc_desc: wgpu::SwapChainDescriptor,
|
|
swap_chain: wgpu::SwapChain,
|
|
debug_pipeline: wgpu::RenderPipeline,
|
|
// other resources
|
|
axes: Mesh,
|
|
clear_color: wgpu::Color,
|
|
pub is_running: bool,
|
|
camera: Camera,
|
|
controller: CameraController,
|
|
projection: Projection,
|
|
uniforms: Uniforms,
|
|
uniforms_bind_group: wgpu::BindGroup,
|
|
last_mouse_pos: PhysicalPosition<f64>,
|
|
mouse_pressed: bool,
|
|
}
|
|
|
|
impl Demo {
|
|
pub async fn new(window: &Window) -> Self {
|
|
let surface = wgpu::Surface::create(window);
|
|
let adapter: wgpu::Adapter = wgpu::Adapter::request(
|
|
&wgpu::RequestAdapterOptions {
|
|
power_preference: wgpu::PowerPreference::Default,
|
|
compatible_surface: Some(&surface),
|
|
},
|
|
wgpu::BackendBit::PRIMARY,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
let (device, queue): (wgpu::Device, wgpu::Queue) =
|
|
adapter.request_device(&Default::default()).await;
|
|
let inner_size = window.inner_size();
|
|
let sc_desc = wgpu::SwapChainDescriptor {
|
|
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
|
width: inner_size.width,
|
|
height: inner_size.height,
|
|
present_mode: wgpu::PresentMode::Fifo,
|
|
};
|
|
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
let camera = Camera::new((0.0, 0.5, 3.0), Deg(-90.0), Deg(0.0));
|
|
let controller = CameraController::new(0.5);
|
|
let projection =
|
|
Projection::new(inner_size.width, inner_size.height, Deg(45.0), 0.1, 1000.0);
|
|
let uniforms = Uniforms::new(&device, &camera, &projection);
|
|
let (uniform_layout, uniforms_bind_group) = create_uniform_binding(&device, &uniforms);
|
|
let debug_pipeline_layout =
|
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
bind_group_layouts: &[&uniform_layout],
|
|
});
|
|
let debug_pipeline = RenderPipelineBuilder::new()
|
|
.layout(&debug_pipeline_layout)
|
|
.color_solid(sc_desc.format)
|
|
.primitive_topology(wgpu::PrimitiveTopology::LineList)
|
|
.vertex_shader(include_bytes!("debug.vert.spv"))
|
|
.fragment_shader(include_bytes!("debug.frag.spv"))
|
|
.index_format(wgpu::IndexFormat::Uint16)
|
|
.vertex_buffer(Vertex::desc())
|
|
.cull_mode(wgpu::CullMode::None)
|
|
.build(&device)
|
|
.unwrap();
|
|
let axes = Mesh::axes(&device);
|
|
|
|
Self {
|
|
surface,
|
|
adapter,
|
|
device,
|
|
queue,
|
|
sc_desc,
|
|
swap_chain,
|
|
debug_pipeline,
|
|
axes,
|
|
clear_color: wgpu::Color {
|
|
r: 0.1,
|
|
g: 0.2,
|
|
b: 0.3,
|
|
a: 1.0,
|
|
},
|
|
is_running: true,
|
|
camera,
|
|
controller,
|
|
projection,
|
|
uniforms,
|
|
uniforms_bind_group,
|
|
last_mouse_pos: (0.0, 0.0).into(),
|
|
mouse_pressed: false,
|
|
}
|
|
}
|
|
|
|
pub fn resize(&mut self, new_size: PhysicalSize<u32>) {
|
|
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);
|
|
self.projection.resize(new_size.width, new_size.height);
|
|
self.uniforms.apply_projection(&self.projection);
|
|
}
|
|
|
|
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
|
match event {
|
|
WindowEvent::KeyboardInput {
|
|
input:
|
|
KeyboardInput {
|
|
virtual_keycode: Some(key),
|
|
state,
|
|
..
|
|
},
|
|
..
|
|
} => {
|
|
self.controller.process_keyboard(*key, *state)
|
|
|| match (key, *state == ElementState::Pressed) {
|
|
(VirtualKeyCode::Escape, true) => {
|
|
self.is_running = false;
|
|
true
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
WindowEvent::MouseInput {
|
|
button: MouseButton::Left,
|
|
state,
|
|
..
|
|
} => {
|
|
self.mouse_pressed = *state == ElementState::Pressed;
|
|
true
|
|
}
|
|
WindowEvent::CursorMoved { position, .. } => {
|
|
let mouse_dx = position.x - self.last_mouse_pos.x;
|
|
let mouse_dy = position.y - self.last_mouse_pos.y;
|
|
self.last_mouse_pos = *position;
|
|
if self.mouse_pressed {
|
|
self.controller.process_mouse(mouse_dx, mouse_dy);
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn update(&mut self, dt: Duration) {
|
|
if self.controller.is_dirty() {
|
|
self.controller.update_camera(&mut self.camera, dt);
|
|
self.uniforms.apply_camera(&self.camera);
|
|
}
|
|
if let Some(cmds) = self.uniforms.update(&self.device) {
|
|
self.queue.submit(&[cmds]);
|
|
}
|
|
}
|
|
|
|
pub fn render(&mut self) {
|
|
let mut encoder = self
|
|
.device
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
let frame = self
|
|
.swap_chain
|
|
.get_next_texture()
|
|
.expect("Unable to retrieve swap chain texture");
|
|
|
|
{
|
|
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
|
attachment: &frame.view,
|
|
resolve_target: None,
|
|
load_op: wgpu::LoadOp::Clear,
|
|
store_op: wgpu::StoreOp::Store,
|
|
clear_color: self.clear_color,
|
|
}],
|
|
depth_stencil_attachment: None,
|
|
});
|
|
pass.set_pipeline(&self.debug_pipeline);
|
|
pass.set_bind_group(0, &self.uniforms_bind_group, &[]);
|
|
pass.set_index_buffer(&self.axes.index_buffer, 0, 0);
|
|
pass.set_vertex_buffer(0, &self.axes.vertex_buffer, 0, 0);
|
|
pass.draw_indexed(0..self.axes.index_count, 0, 0..1);
|
|
}
|
|
|
|
self.queue.submit(&[encoder.finish()]);
|
|
}
|
|
}
|