| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067 |
- use std::iter;
- use rand::Rng;
- use cgmath::prelude::*;
- use wgpu::util::DeviceExt;
- use winit::{
- event::*,
- event_loop::{ControlFlow, EventLoop},
- window::Window,
- };
- use sapvi::gfx::{model, texture};
- use model::{DrawLight, DrawModel, Vertex};
- use std::time::Instant;
- #[macro_use]
- extern crate lazy_static;
- lazy_static! {
- static ref START: Instant = Instant::now();
- }
- fn get_time() -> f32 {
- START.elapsed().as_secs_f32()
- }
- const FONT_BYTES: &[u8] = include_bytes!("../../res/font/PressStart2P-Regular.ttf");
- #[rustfmt::skip]
- pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 0.5, 0.0,
- 0.0, 0.0, 0.5, 1.0,
- );
- const NUM_INSTANCES_PER_ROW: u32 = 10;
- struct Camera {
- eye: cgmath::Point3<f32>,
- target: cgmath::Point3<f32>,
- up: cgmath::Vector3<f32>,
- aspect: f32,
- fovy: f32,
- znear: f32,
- zfar: f32,
- }
- impl Camera {
- fn build_view_projection_matrix(&self) -> cgmath::Matrix4<f32> {
- let view = cgmath::Matrix4::look_at(self.eye, self.target, self.up);
- let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
- proj * view
- }
- }
- #[repr(C)]
- #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
- struct Uniforms {
- view_position: [f32; 4],
- view_proj: [[f32; 4]; 4],
- }
- impl Uniforms {
- fn new() -> Self {
- Self {
- view_position: [0.0; 4],
- view_proj: cgmath::Matrix4::identity().into(),
- }
- }
- fn update_view_proj(&mut self, camera: &Camera) {
- // We don't specifically need homogeneous coordinates since we're just using
- // a vec3 in the shader. We're using Point3 for the camera.eye, and this is
- // the easiest way to convert to Vector4. We're using Vector4 because of
- // the uniforms 16 byte spacing requirement
- self.view_position = camera.eye.to_homogeneous().into();
- // self.view_proj = OPENGL_TO_WGPU_MATRIX * camera.build_view_projection_matrix();
- self.view_proj = camera.build_view_projection_matrix().into();
- }
- }
- struct CameraController {
- speed: f32,
- is_up_pressed: bool,
- is_down_pressed: bool,
- is_forward_pressed: bool,
- is_backward_pressed: bool,
- is_left_pressed: bool,
- is_right_pressed: bool,
- }
- impl CameraController {
- fn new(speed: f32) -> Self {
- Self {
- speed,
- is_up_pressed: false,
- is_down_pressed: false,
- is_forward_pressed: false,
- is_backward_pressed: false,
- is_left_pressed: false,
- is_right_pressed: false,
- }
- }
- fn process_events(&mut self, event: &WindowEvent) -> bool {
- match event {
- WindowEvent::KeyboardInput {
- input:
- KeyboardInput {
- state,
- virtual_keycode: Some(keycode),
- ..
- },
- ..
- } => {
- let is_pressed = *state == ElementState::Pressed;
- match keycode {
- VirtualKeyCode::Space => {
- self.is_up_pressed = is_pressed;
- true
- }
- VirtualKeyCode::LShift => {
- self.is_down_pressed = is_pressed;
- true
- }
- VirtualKeyCode::W | VirtualKeyCode::Up => {
- self.is_forward_pressed = is_pressed;
- true
- }
- VirtualKeyCode::A | VirtualKeyCode::Left => {
- self.is_left_pressed = is_pressed;
- true
- }
- VirtualKeyCode::S | VirtualKeyCode::Down => {
- self.is_backward_pressed = is_pressed;
- true
- }
- VirtualKeyCode::D | VirtualKeyCode::Right => {
- self.is_right_pressed = is_pressed;
- true
- }
- _ => false,
- }
- }
- _ => false,
- }
- }
- fn update_camera(&self, camera: &mut Camera) {
- let forward = camera.target - camera.eye;
- let forward_norm = forward.normalize();
- let forward_mag = forward.magnitude();
- // Prevents glitching when camera gets too close to the
- // center of the scene.
- if self.is_forward_pressed && forward_mag > self.speed {
- camera.eye += forward_norm * self.speed;
- }
- if self.is_backward_pressed {
- camera.eye -= forward_norm * self.speed;
- }
- let right = forward_norm.cross(camera.up);
- // Redo radius calc in case the up/ down is pressed.
- let forward = camera.target - camera.eye;
- let forward_mag = forward.magnitude();
- if self.is_right_pressed {
- // Rescale the distance between the target and eye so
- // that it doesn't change. The eye therefore still
- // lies on the circle made by the target and eye.
- camera.eye = camera.target - (forward + right * self.speed).normalize() * forward_mag;
- }
- if self.is_left_pressed {
- camera.eye = camera.target - (forward - right * self.speed).normalize() * forward_mag;
- }
- }
- }
- struct Instance {
- position: cgmath::Vector3<f32>,
- rotation: cgmath::Quaternion<f32>,
- }
- impl Instance {
- fn to_raw(&self) -> InstanceRaw {
- InstanceRaw {
- model: (cgmath::Matrix4::from_translation(self.position)
- * cgmath::Matrix4::from(self.rotation))
- .into(),
- }
- }
- }
- #[repr(C)]
- #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
- struct InstanceRaw {
- #[allow(dead_code)]
- model: [[f32; 4]; 4],
- }
- impl model::Vertex for InstanceRaw {
- fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
- use std::mem;
- wgpu::VertexBufferLayout {
- array_stride: mem::size_of::<InstanceRaw>() as wgpu::BufferAddress,
- // We need to switch from using a step mode of Vertex to Instance
- // This means that our shaders will only change to use the next
- // instance when the shader starts processing a new instance
- step_mode: wgpu::InputStepMode::Instance,
- attributes: &[
- wgpu::VertexAttribute {
- offset: 0,
- // While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll
- // be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later
- shader_location: 5,
- format: wgpu::VertexFormat::Float4,
- },
- // A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot
- // for each vec4. We don't have to do this in code though.
- wgpu::VertexAttribute {
- offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
- shader_location: 6,
- format: wgpu::VertexFormat::Float4,
- },
- wgpu::VertexAttribute {
- offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
- shader_location: 7,
- format: wgpu::VertexFormat::Float4,
- },
- wgpu::VertexAttribute {
- offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
- shader_location: 8,
- format: wgpu::VertexFormat::Float4,
- },
- ],
- }
- }
- }
- #[repr(C)]
- #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
- struct Light {
- position: [f32; 3],
- // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here
- _padding: u32,
- color: [f32; 3],
- }
- pub const UNBOUNDED_F32: f32 = std::f32::INFINITY;
- #[derive(Debug)]
- pub struct Text {
- pub position: cgmath::Vector2<f32>,
- pub bounds: cgmath::Vector2<f32>,
- pub color: cgmath::Vector4<f32>,
- pub text: String,
- pub size: f32,
- pub visible: bool,
- pub focused: bool,
- pub centered: bool,
- }
- impl Default for Text {
- fn default() -> Self {
- Self {
- position: (0.0, 0.0).into(),
- bounds: (UNBOUNDED_F32, UNBOUNDED_F32).into(),
- color: (1.0, 1.0, 1.0, 1.0).into(),
- text: String::new(),
- size: 16.0,
- visible: false,
- focused: false,
- centered: false,
- }
- }
- }
- const VERTEX_Z: f32 = 0.0;
- // (-1, 1) (1, 1)
- // +-----------------------+
- // | |
- // | |
- // | |
- // | |
- // | |
- // | |
- // | |
- // +-----------------------+
- // (-1, -1) (1, -1)
- const VERTICES: &[model::ModelVertex] = &[
- // top left
- model::ModelVertex {
- position: [-1.0, 1.0, VERTEX_Z],
- tex_coords: [0.0, 0.0],
- },
- // bottom left
- model::ModelVertex {
- position: [-1.0, 0.5, VERTEX_Z],
- tex_coords: [0.0, 1.0],
- },
- // bottom right
- model::ModelVertex {
- position: [-0.5, 0.5, VERTEX_Z],
- tex_coords: [1.0, 1.0],
- },
- // top right
- model::ModelVertex {
- position: [-0.5, 1.0, VERTEX_Z],
- tex_coords: [1.0, 0.0],
- },
- ];
- //const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];
- const INDICES: &[u16] = &[0, 1, 2, 0, 2, 3];
- 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,
- camera_controller: CameraController,
- uniforms: Uniforms,
- uniform_buffer: wgpu::Buffer,
- uniform_bind_group: wgpu::BindGroup,
- instances: Vec<Instance>,
- #[allow(dead_code)]
- instance_buffer: wgpu::Buffer,
- depth_texture: texture::Texture,
- size: winit::dpi::PhysicalSize<u32>,
- light: Light,
- light_buffer: wgpu::Buffer,
- light_bind_group: wgpu::BindGroup,
- light_render_pipeline: wgpu::RenderPipeline,
- ui_render_pipeline: wgpu::RenderPipeline,
- vertex_buffer: wgpu::Buffer,
- index_buffer: wgpu::Buffer,
- num_indices: u32,
- #[allow(dead_code)]
- diffuse_texture: texture::Texture,
- diffuse_bind_group: wgpu::BindGroup,
- #[allow(dead_code)]
- cartoon_texture: texture::Texture,
- cartoon_bind_group: wgpu::BindGroup,
- glyph_brush: wgpu_glyph::GlyphBrush<()>,
- staging_belt: wgpu::util::StagingBelt,
- is_space_pressed: bool,
- }
- fn create_render_pipeline(
- device: &wgpu::Device,
- layout: &wgpu::PipelineLayout,
- color_format: wgpu::TextureFormat,
- depth_format: Option<wgpu::TextureFormat>,
- vertex_layouts: &[wgpu::VertexBufferLayout],
- vs_src: wgpu::ShaderModuleDescriptor,
- fs_src: wgpu::ShaderModuleDescriptor,
- ) -> wgpu::RenderPipeline {
- let vs_module = device.create_shader_module(&vs_src);
- let fs_module = device.create_shader_module(&fs_src);
- device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
- label: Some("Render Pipeline"),
- layout: Some(&layout),
- vertex: wgpu::VertexState {
- module: &vs_module,
- entry_point: "main",
- buffers: vertex_layouts,
- },
- fragment: Some(wgpu::FragmentState {
- module: &fs_module,
- entry_point: "main",
- targets: &[wgpu::ColorTargetState {
- format: color_format,
- alpha_blend: wgpu::BlendState::REPLACE,
- color_blend: wgpu::BlendState::REPLACE,
- write_mask: wgpu::ColorWrite::ALL,
- }],
- }),
- primitive: wgpu::PrimitiveState {
- topology: wgpu::PrimitiveTopology::TriangleList,
- strip_index_format: None,
- front_face: wgpu::FrontFace::Ccw,
- cull_mode: wgpu::CullMode::Back,
- // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
- polygon_mode: wgpu::PolygonMode::Fill,
- },
- depth_stencil: depth_format.map(|format| wgpu::DepthStencilState {
- format,
- depth_write_enabled: true,
- depth_compare: wgpu::CompareFunction::Less,
- stencil: wgpu::StencilState::default(),
- bias: wgpu::DepthBiasState::default(),
- // Setting this to true requires Features::DEPTH_CLAMPING
- clamp_depth: false,
- }),
- multisample: wgpu::MultisampleState {
- count: 1,
- mask: !0,
- alpha_to_coverage_enabled: false,
- },
- })
- }
- impl State {
- async fn new(window: &Window) -> Self {
- let size = window.inner_size();
- // The instance is a handle to our GPU
- // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU
- let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
- let surface = unsafe { instance.create_surface(window) };
- let adapter = instance
- .request_adapter(&wgpu::RequestAdapterOptions {
- power_preference: wgpu::PowerPreference::default(),
- compatible_surface: Some(&surface),
- })
- .await
- .unwrap();
- let (device, queue) = adapter
- .request_device(
- &wgpu::DeviceDescriptor {
- label: None,
- features: wgpu::Features::empty(),
- limits: wgpu::Limits::default(),
- },
- None, // Trace path
- )
- .await
- .unwrap();
- let sc_desc = wgpu::SwapChainDescriptor {
- usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
- format: adapter.get_swap_chain_preferred_format(&surface),
- 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 {
- entries: &[
- wgpu::BindGroupLayoutEntry {
- binding: 0,
- visibility: wgpu::ShaderStage::FRAGMENT,
- ty: wgpu::BindingType::Texture {
- multisampled: false,
- view_dimension: wgpu::TextureViewDimension::D2,
- sample_type: wgpu::TextureSampleType::Float { filterable: false },
- },
- count: None,
- },
- wgpu::BindGroupLayoutEntry {
- binding: 1,
- visibility: wgpu::ShaderStage::FRAGMENT,
- ty: wgpu::BindingType::Sampler {
- comparison: false,
- filtering: true,
- },
- count: None,
- },
- ],
- label: Some("texture_bind_group_layout"),
- });
- let camera = Camera {
- eye: (0.0, 5.0, -10.0).into(),
- target: (0.0, 0.0, 0.0).into(),
- up: cgmath::Vector3::unit_y(),
- aspect: sc_desc.width as f32 / sc_desc.height as f32,
- fovy: 45.0,
- znear: 0.1,
- zfar: 100.0,
- };
- let camera_controller = CameraController::new(0.2);
- let mut uniforms = Uniforms::new();
- uniforms.update_view_proj(&camera);
- let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
- label: Some("Uniform Buffer"),
- contents: bytemuck::cast_slice(&[uniforms]),
- usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
- });
- const SPACE_BETWEEN: f32 = 3.0;
- let instances = (0..NUM_INSTANCES_PER_ROW)
- .flat_map(|z| {
- (0..NUM_INSTANCES_PER_ROW).map(move |x| {
- let x = SPACE_BETWEEN * (x as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
- let z = SPACE_BETWEEN * (z as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
- let time = get_time() * 100.0;
- println!("{} {} {}", x, z, time);
- let y = ((x + time).sin() + (z + time).sin()) * 20.0;
- let position = cgmath::Vector3 { x, y, z };
- let rotation =
- cgmath::Quaternion::from_axis_angle(
- cgmath::Vector3::unit_z(),
- cgmath::Deg(180.0 + 0.0),
- );
- /*
- let rotation = if position.is_zero() {
- cgmath::Quaternion::from_axis_angle(
- cgmath::Vector3::unit_z(),
- cgmath::Deg(180.0 + 0.0),
- )
- } else {
- cgmath::Quaternion::from_axis_angle(
- position.clone().normalize(),
- cgmath::Deg(180.0 + 45.0),
- )
- };
- */
- Instance { position, rotation }
- })
- })
- .collect::<Vec<_>>();
- let instance_data = instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
- let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
- label: Some("Instance Buffer"),
- contents: bytemuck::cast_slice(&instance_data),
- usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
- });
- let uniform_bind_group_layout =
- device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
- entries: &[wgpu::BindGroupLayoutEntry {
- binding: 0,
- visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
- ty: wgpu::BindingType::Buffer {
- ty: wgpu::BufferBindingType::Uniform,
- has_dynamic_offset: false,
- min_binding_size: None,
- },
- count: None,
- }],
- label: Some("uniform_bind_group_layout"),
- });
- let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
- layout: &uniform_bind_group_layout,
- entries: &[wgpu::BindGroupEntry {
- binding: 0,
- resource: uniform_buffer.as_entire_binding(),
- }],
- label: Some("uniform_bind_group"),
- });
- let res_dir = std::path::Path::new("res/model/");
- let obj_model = model::Model::load(
- &device,
- &queue,
- &texture_bind_group_layout,
- res_dir.join("earth.obj"),
- )
- .unwrap();
- let light = Light {
- position: [4.0, 4.0, 2.0],
- _padding: 0,
- color: [1.0, 1.0, 1.0],
- };
- let light_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
- label: Some("Light VB"),
- contents: bytemuck::cast_slice(&[light]),
- usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
- });
- let light_bind_group_layout =
- device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
- entries: &[wgpu::BindGroupLayoutEntry {
- binding: 0,
- visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
- ty: wgpu::BindingType::Buffer {
- ty: wgpu::BufferBindingType::Uniform,
- has_dynamic_offset: false,
- min_binding_size: None,
- },
- count: None,
- }],
- label: None,
- });
- let light_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
- layout: &light_bind_group_layout,
- entries: &[wgpu::BindGroupEntry {
- binding: 0,
- resource: light_buffer.as_entire_binding(),
- }],
- label: None,
- });
- let depth_texture =
- texture::Texture::create_depth_texture(&device, &sc_desc, "depth_texture");
- let render_pipeline_layout =
- device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
- label: Some("Render Pipeline Layout"),
- bind_group_layouts: &[
- &texture_bind_group_layout,
- &uniform_bind_group_layout,
- &light_bind_group_layout,
- ],
- push_constant_ranges: &[],
- });
- let render_pipeline = create_render_pipeline(
- &device,
- &render_pipeline_layout,
- sc_desc.format,
- Some(texture::Texture::DEPTH_FORMAT),
- &[model::ModelVertex::desc(), InstanceRaw::desc()],
- wgpu::include_spirv!("../../res/shader/shader.vert.spv"),
- wgpu::include_spirv!("../../res/shader/shader.frag.spv"),
- );
- let light_render_pipeline = {
- let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
- label: Some("Light Pipeline Layout"),
- bind_group_layouts: &[&uniform_bind_group_layout, &light_bind_group_layout],
- push_constant_ranges: &[],
- });
- create_render_pipeline(
- &device,
- &layout,
- sc_desc.format,
- Some(texture::Texture::DEPTH_FORMAT),
- &[model::ModelVertex::desc()],
- wgpu::include_spirv!("../../res/shader/light.vert.spv"),
- wgpu::include_spirv!("../../res/shader/light.frag.spv"),
- )
- };
- //-------------------
- let texture_bind_group_layout =
- device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
- entries: &[
- wgpu::BindGroupLayoutEntry {
- binding: 0,
- visibility: wgpu::ShaderStage::FRAGMENT,
- ty: wgpu::BindingType::Texture {
- multisampled: false,
- view_dimension: wgpu::TextureViewDimension::D2,
- sample_type: wgpu::TextureSampleType::Float { filterable: false },
- },
- count: None,
- },
- wgpu::BindGroupLayoutEntry {
- binding: 1,
- visibility: wgpu::ShaderStage::FRAGMENT,
- ty: wgpu::BindingType::Sampler {
- comparison: false,
- filtering: true,
- },
- count: None,
- },
- ],
- label: Some("texture_bind_group_layout"),
- });
- let diffuse_bytes = include_bytes!("../../res/img/absolutely-proprietary.png");
- let diffuse_texture =
- texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "stallman1").unwrap();
- let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
- layout: &texture_bind_group_layout,
- entries: &[
- wgpu::BindGroupEntry {
- binding: 0,
- resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
- },
- wgpu::BindGroupEntry {
- binding: 1,
- resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
- },
- ],
- label: Some("diffuse_bind_group"),
- });
- let cartoon_bytes = include_bytes!("../../res/img/absolutely-proprietary2.png");
- let cartoon_texture =
- texture::Texture::from_bytes(&device, &queue, cartoon_bytes, "stallman2")
- .unwrap();
- let cartoon_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
- layout: &texture_bind_group_layout,
- entries: &[
- wgpu::BindGroupEntry {
- binding: 0,
- resource: wgpu::BindingResource::TextureView(&cartoon_texture.view),
- },
- wgpu::BindGroupEntry {
- binding: 1,
- resource: wgpu::BindingResource::Sampler(&cartoon_texture.sampler),
- },
- ],
- label: Some("cartoon_bind_group"),
- });
- let vs_module = device.create_shader_module(&wgpu::include_spirv!("../../res/shader/ui_shader.vert.spv"));
- let fs_module = device.create_shader_module(&wgpu::include_spirv!("../../res/shader/ui_shader.frag.spv"));
- let render_pipeline_layout =
- device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
- label: Some("Render Pipeline Layout"),
- bind_group_layouts: &[&texture_bind_group_layout],
- push_constant_ranges: &[],
- });
- let ui_render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
- label: Some("Render Pipeline"),
- layout: Some(&render_pipeline_layout),
- vertex: wgpu::VertexState {
- module: &vs_module,
- entry_point: "main",
- buffers: &[model::ModelVertex::desc()],
- },
- fragment: Some(wgpu::FragmentState {
- module: &fs_module,
- entry_point: "main",
- targets: &[wgpu::ColorTargetState {
- format: sc_desc.format,
- alpha_blend: wgpu::BlendState::REPLACE,
- color_blend: wgpu::BlendState::REPLACE,
- write_mask: wgpu::ColorWrite::ALL,
- }],
- }),
- primitive: wgpu::PrimitiveState {
- topology: wgpu::PrimitiveTopology::TriangleList,
- strip_index_format: None,
- front_face: wgpu::FrontFace::Ccw,
- cull_mode: wgpu::CullMode::Back,
- // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
- polygon_mode: wgpu::PolygonMode::Fill,
- },
- depth_stencil: Some(wgpu::DepthStencilState {
- format: texture::Texture::DEPTH_FORMAT,
- depth_write_enabled: true,
- depth_compare: wgpu::CompareFunction::Less,
- stencil: wgpu::StencilState::default(),
- bias: wgpu::DepthBiasState::default(),
- // Setting this to true requires Features::DEPTH_CLAMPING
- clamp_depth: false,
- }),
- multisample: wgpu::MultisampleState {
- count: 1,
- mask: !0,
- alpha_to_coverage_enabled: false,
- },
- });
- let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
- label: Some("Vertex Buffer"),
- contents: bytemuck::cast_slice(VERTICES),
- usage: wgpu::BufferUsage::VERTEX,
- });
- let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
- label: Some("Index Buffer"),
- contents: bytemuck::cast_slice(INDICES),
- usage: wgpu::BufferUsage::INDEX,
- });
- let num_indices = INDICES.len() as u32;
- let font = wgpu_glyph::ab_glyph::FontArc::try_from_slice(FONT_BYTES).unwrap();
- let glyph_brush =
- wgpu_glyph::GlyphBrushBuilder::using_font(font).build(&device, sc_desc.format);
- let staging_belt = wgpu::util::StagingBelt::new(1024);
- Self {
- surface,
- device,
- queue,
- sc_desc,
- swap_chain,
- render_pipeline,
- obj_model,
- camera,
- camera_controller,
- uniform_buffer,
- uniform_bind_group,
- uniforms,
- instances,
- instance_buffer,
- depth_texture,
- size,
- light,
- light_buffer,
- light_bind_group,
- light_render_pipeline,
- ui_render_pipeline,
- vertex_buffer,
- index_buffer,
- num_indices,
- diffuse_texture,
- diffuse_bind_group,
- cartoon_texture,
- cartoon_bind_group,
- glyph_brush,
- staging_belt,
- is_space_pressed: true,
- }
- }
- fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
- 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);
- self.depth_texture =
- texture::Texture::create_depth_texture(&self.device, &self.sc_desc, "depth_texture");
- }
- fn input(&mut self, event: &WindowEvent) -> bool {
- self.camera_controller.process_events(event)
- }
- fn update(&mut self) {
- if rand::thread_rng().gen_range(0, 5) == 0 {
- self.is_space_pressed = !self.is_space_pressed;
- }
- self.camera_controller.update_camera(&mut self.camera);
- self.uniforms.update_view_proj(&self.camera);
- self.queue.write_buffer(
- &self.uniform_buffer,
- 0,
- bytemuck::cast_slice(&[self.uniforms]),
- );
- let time = get_time();
- const SPACE_BETWEEN: f32 = 3.0;
- let instances = (0..NUM_INSTANCES_PER_ROW)
- .flat_map(|z| {
- (0..NUM_INSTANCES_PER_ROW).map(move |x| {
- let x = SPACE_BETWEEN * (x as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
- let z = SPACE_BETWEEN * (z as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
- //println!("{} {} {}", x, z, time);
- let y = ((x/3.0 + time).sin() + (z/3.0 + time).cos()) * 1.5;
- let position = cgmath::Vector3 { x, y, z };
- let rotation =
- cgmath::Quaternion::from_axis_angle(
- cgmath::Vector3::unit_z(),
- cgmath::Deg(180.0 + 0.0),
- );
- Instance { position, rotation }
- })
- })
- .collect::<Vec<_>>();
- let instance_data = instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
- self.queue.write_buffer(&self.instance_buffer, 0,
- bytemuck::cast_slice(&instance_data));
- // Update the light
- let old_position: cgmath::Vector3<_> = self.light.position.into();
- self.light.position =
- (cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0))
- * old_position)
- .into();
- self.queue
- .write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light]));
- }
- fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
- let frame = self.swap_chain.get_current_frame()?.output;
- let mut encoder = self
- .device
- .create_command_encoder(&wgpu::CommandEncoderDescriptor {
- label: Some("Render Encoder"),
- });
- {
- let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
- label: Some("Render Pass"),
- color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
- attachment: &frame.view,
- resolve_target: None,
- ops: wgpu::Operations {
- load: wgpu::LoadOp::Clear(wgpu::Color {
- r: 0.1,
- g: 0.2,
- b: 0.3,
- a: 1.0,
- }),
- store: true,
- },
- }],
- depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
- attachment: &self.depth_texture.view,
- depth_ops: Some(wgpu::Operations {
- load: wgpu::LoadOp::Clear(1.0),
- store: true,
- }),
- stencil_ops: None,
- }),
- });
- render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..));
- //render_pass.set_pipeline(&self.light_render_pipeline);
- //render_pass.draw_light_model(
- // &self.obj_model,
- // &self.uniform_bind_group,
- // &self.light_bind_group,
- //);
- render_pass.set_pipeline(&self.render_pipeline);
- render_pass.draw_model_instanced(
- &self.obj_model,
- 0..self.instances.len() as u32,
- &self.uniform_bind_group,
- &self.light_bind_group,
- );
- let bind_group = if self.is_space_pressed {
- &self.cartoon_bind_group
- } else {
- &self.diffuse_bind_group
- };
- render_pass.set_pipeline(&self.ui_render_pipeline);
- render_pass.set_bind_group(0, bind_group, &[]);
- render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
- render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
- render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
- }
- let play_text = Text {
- position: (40.0, 40.0).into(),
- color: (1.0, 1.0, 1.0, 1.0).into(),
- text: String::from("Absolutely Proprietary"),
- size: 32.0,
- centered: false,
- ..Default::default()
- };
- draw_text(&play_text, &mut self.glyph_brush);
- self.glyph_brush
- .draw_queued(
- &self.device,
- &mut self.staging_belt,
- &mut encoder,
- &frame.view,
- self.sc_desc.width,
- self.sc_desc.height,
- )
- .unwrap();
- self.staging_belt.finish();
- self.queue.submit(iter::once(encoder.finish()));
- Ok(())
- }
- }
- fn draw_text(text: &Text, glyph_brush: &mut wgpu_glyph::GlyphBrush<()>) {
- let layout = wgpu_glyph::Layout::default().h_align(if text.centered {
- wgpu_glyph::HorizontalAlign::Center
- } else {
- wgpu_glyph::HorizontalAlign::Left
- });
- let section =
- wgpu_glyph::Section {
- screen_position: text.position.into(),
- bounds: text.bounds.into(),
- layout,
- ..Default::default()
- }
- .add_text(wgpu_glyph::Text::new(&text.text).with_color(text.color).with_scale(
- if text.focused {
- text.size + 8.0
- } else {
- text.size
- },
- ));
- glyph_brush.queue(section);
- }
- fn main() {
- env_logger::init();
- let event_loop = EventLoop::new();
- let title = env!("CARGO_PKG_NAME");
- let window = winit::window::WindowBuilder::new()
- .with_title(title)
- .build(&event_loop)
- .unwrap();
- 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) => {
- state.resize(*physical_size);
- }
- WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
- state.resize(**new_inner_size);
- }
- _ => {}
- }
- }
- }
- Event::RedrawRequested(_) => {
- state.update();
- match state.render() {
- Ok(_) => {}
- // Recreate the swap_chain if lost
- Err(wgpu::SwapChainError::Lost) => state.resize(state.size),
- // The system is out of memory, we should probably quit
- Err(wgpu::SwapChainError::OutOfMemory) => *control_flow = ControlFlow::Exit,
- // All other errors (Outdated, Timeout) should be resolved by the next frame
- Err(e) => eprintln!("{:?}", e),
- }
- }
- _ => {}
- }
- });
- }
|