Minor cleanup
parent
5345355909
commit
6e59d95752
|
@ -174,10 +174,10 @@ pub async fn run() -> Result<()> {
|
||||||
Event::RedrawRequested(window_id) if window_id == gpu.window().id() => {
|
Event::RedrawRequested(window_id) if window_id == gpu.window().id() => {
|
||||||
gpu.update();
|
gpu.update();
|
||||||
game.update();
|
game.update();
|
||||||
match gpu.render(&game.sprites(), game.camera) {
|
match gpu.render(&game) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
// Reconfigure the surface if lost
|
// Reconfigure the surface if lost
|
||||||
Err(wgpu::SurfaceError::Lost) => gpu.resize(gpu.size),
|
Err(wgpu::SurfaceError::Lost) => gpu.resize(gpu.window_size),
|
||||||
// The system is out of memory, we should probably quit
|
// The system is out of memory, we should probably quit
|
||||||
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
||||||
// All other errors (Outdated, Timeout) should be resolved by the next frame
|
// All other errors (Outdated, Timeout) should be resolved by the next frame
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bytemuck;
|
use bytemuck;
|
||||||
use cgmath::{EuclideanSpace, Point2};
|
use cgmath::{EuclideanSpace, Point2, Vector2};
|
||||||
use std::{iter, rc::Rc};
|
use std::{iter, rc::Rc};
|
||||||
use wgpu;
|
use wgpu;
|
||||||
use winit::{self, window::Window};
|
use winit::{self, dpi::PhysicalSize, window::Window};
|
||||||
|
|
||||||
use crate::{Camera, Sprite};
|
use crate::Game;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pipeline::PipelineBuilder,
|
pipeline::PipelineBuilder,
|
||||||
|
@ -13,7 +13,7 @@ use super::{
|
||||||
util::Transform,
|
util::Transform,
|
||||||
vertexbuffer::{
|
vertexbuffer::{
|
||||||
data::{SPRITE_INDICES, SPRITE_VERTICES},
|
data::{SPRITE_INDICES, SPRITE_VERTICES},
|
||||||
types::{PlainVertex, SpriteInstance, StarInstance, TexturedVertex},
|
types::{PlainVertex, SpriteInstance, StarfieldInstance, TexturedVertex},
|
||||||
VertexBuffer,
|
VertexBuffer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,8 @@ pub struct GPUState {
|
||||||
queue: wgpu::Queue,
|
queue: wgpu::Queue,
|
||||||
|
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
pub size: winit::dpi::PhysicalSize<u32>,
|
pub window_size: winit::dpi::PhysicalSize<u32>,
|
||||||
|
window_aspect: f32,
|
||||||
|
|
||||||
sprite_pipeline: wgpu::RenderPipeline,
|
sprite_pipeline: wgpu::RenderPipeline,
|
||||||
starfield_pipeline: wgpu::RenderPipeline,
|
starfield_pipeline: wgpu::RenderPipeline,
|
||||||
|
@ -42,11 +43,12 @@ struct VertexBuffers {
|
||||||
impl GPUState {
|
impl GPUState {
|
||||||
// We can draw at most this many sprites on the screen.
|
// We can draw at most this many sprites on the screen.
|
||||||
// TODO: compile-time option
|
// TODO: compile-time option
|
||||||
pub const SPRITE_LIMIT: u64 = 100;
|
pub const SPRITE_INSTANCE_LIMIT: u64 = 100;
|
||||||
pub const STAR_LIMIT: u64 = 100;
|
pub const STARFIELD_INSTANCE_LIMIT: u64 = 100;
|
||||||
|
|
||||||
pub async fn new(window: Window) -> Result<Self> {
|
pub async fn new(window: Window) -> Result<Self> {
|
||||||
let size = window.inner_size();
|
let window_size = window.inner_size();
|
||||||
|
let window_aspect = window_size.width as f32 / window_size.height as f32;
|
||||||
|
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: wgpu::Backends::all(),
|
backends: wgpu::Backends::all(),
|
||||||
|
@ -97,8 +99,8 @@ impl GPUState {
|
||||||
config = wgpu::SurfaceConfiguration {
|
config = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format: surface_format,
|
format: surface_format,
|
||||||
width: size.width,
|
width: window_size.width,
|
||||||
height: size.height,
|
height: window_size.height,
|
||||||
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![],
|
||||||
|
@ -113,15 +115,15 @@ impl GPUState {
|
||||||
&device,
|
&device,
|
||||||
Some(SPRITE_VERTICES),
|
Some(SPRITE_VERTICES),
|
||||||
Some(SPRITE_INDICES),
|
Some(SPRITE_INDICES),
|
||||||
Self::SPRITE_LIMIT,
|
Self::SPRITE_INSTANCE_LIMIT,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
starfield: Rc::new(VertexBuffer::new::<PlainVertex, StarInstance>(
|
starfield: Rc::new(VertexBuffer::new::<PlainVertex, StarfieldInstance>(
|
||||||
"starfield",
|
"starfield",
|
||||||
&device,
|
&device,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Self::STAR_LIMIT,
|
Self::STARFIELD_INSTANCE_LIMIT,
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,7 +161,8 @@ impl GPUState {
|
||||||
queue,
|
queue,
|
||||||
|
|
||||||
window,
|
window,
|
||||||
size,
|
window_size,
|
||||||
|
window_aspect,
|
||||||
|
|
||||||
sprite_pipeline,
|
sprite_pipeline,
|
||||||
starfield_pipeline,
|
starfield_pipeline,
|
||||||
|
@ -173,9 +176,10 @@ impl GPUState {
|
||||||
&self.window
|
&self.window
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
pub fn resize(&mut self, new_size: PhysicalSize<u32>) {
|
||||||
if new_size.width > 0 && new_size.height > 0 {
|
if new_size.width > 0 && new_size.height > 0 {
|
||||||
self.size = new_size;
|
self.window_size = new_size;
|
||||||
|
self.window_aspect = new_size.width as f32 / new_size.height as f32;
|
||||||
self.config.width = new_size.width;
|
self.config.width = new_size.width;
|
||||||
self.config.height = new_size.height;
|
self.config.height = new_size.height;
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
|
@ -184,56 +188,20 @@ impl GPUState {
|
||||||
|
|
||||||
pub fn update(&mut self) {}
|
pub fn update(&mut self) {}
|
||||||
|
|
||||||
pub fn render(
|
/// Make a SpriteInstance for each of the game's visible sprites.
|
||||||
&mut self,
|
/// Will panic if SPRITE_INSTANCE_LIMIT is exceeded.
|
||||||
sprites: &Vec<Sprite>,
|
///
|
||||||
camera: Camera,
|
/// This is only called inside self.render()
|
||||||
) -> Result<(), wgpu::SurfaceError> {
|
fn make_sprite_instances(&self, game: &Game) -> Vec<SpriteInstance> {
|
||||||
let output = self.surface.get_current_texture()?;
|
let mut instances: Vec<SpriteInstance> = Vec::new();
|
||||||
let view = output
|
|
||||||
.texture
|
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
let mut encoder = self
|
|
||||||
.device
|
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
||||||
label: Some("sprite render encoder"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
||||||
label: Some("sprite render pass"),
|
|
||||||
|
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
||||||
view: &view,
|
|
||||||
resolve_target: None,
|
|
||||||
ops: wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
|
||||||
r: 0.0,
|
|
||||||
g: 0.0,
|
|
||||||
b: 0.0,
|
|
||||||
a: 1.0,
|
|
||||||
}),
|
|
||||||
store: wgpu::StoreOp::Store,
|
|
||||||
},
|
|
||||||
})],
|
|
||||||
depth_stencil_attachment: None,
|
|
||||||
occlusion_query_set: None,
|
|
||||||
timestamp_writes: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Correct for screen aspect ratio
|
|
||||||
// (it may not be square!)
|
|
||||||
let screen_aspect = self.size.width as f32 / self.size.height as f32;
|
|
||||||
|
|
||||||
// Game coordinates (relative to camera) of ne and sw corners of screen.
|
// Game coordinates (relative to camera) of ne and sw corners of screen.
|
||||||
// Used to skip off-screen sprites.
|
// Used to skip off-screen sprites.
|
||||||
let clip_ne = Point2::from((-1.0, 1.0)) * camera.zoom;
|
let clip_ne = Point2::from((-1.0, 1.0)) * game.camera.zoom;
|
||||||
let clip_sw = Point2::from((1.0, -1.0)) * camera.zoom;
|
let clip_sw = Point2::from((1.0, -1.0)) * game.camera.zoom;
|
||||||
|
|
||||||
let mut instances: Vec<SpriteInstance> = Vec::new();
|
for s in game.sprites() {
|
||||||
|
let pos = s.post_parallax_position(game.camera) - game.camera.pos.to_vec();
|
||||||
for s in sprites {
|
|
||||||
let pos = s.post_parallax_position(camera) - camera.pos.to_vec();
|
|
||||||
let texture = self.texture_array.get_texture(&s.name[..]);
|
let texture = self.texture_array.get_texture(&s.name[..]);
|
||||||
|
|
||||||
// Game dimensions of this sprite post-scale.
|
// Game dimensions of this sprite post-scale.
|
||||||
|
@ -261,14 +229,14 @@ impl GPUState {
|
||||||
//
|
//
|
||||||
// We can't use screen_pos to exclude off-screen sprites because
|
// We can't use screen_pos to exclude off-screen sprites because
|
||||||
// it can't account for height and width.
|
// it can't account for height and width.
|
||||||
let scale = height / camera.zoom;
|
let scale = height / game.camera.zoom;
|
||||||
let screen_pos: Point2<f32> = pos / camera.zoom;
|
let screen_pos: Point2<f32> = pos / game.camera.zoom;
|
||||||
|
|
||||||
instances.push(SpriteInstance {
|
instances.push(SpriteInstance {
|
||||||
transform: Transform {
|
transform: Transform {
|
||||||
pos: screen_pos,
|
pos: screen_pos,
|
||||||
aspect: texture.aspect,
|
sprite_aspect: texture.aspect,
|
||||||
screen_aspect,
|
window_aspect: self.window_aspect,
|
||||||
rotate: s.angle,
|
rotate: s.angle,
|
||||||
scale,
|
scale,
|
||||||
}
|
}
|
||||||
|
@ -279,46 +247,101 @@ impl GPUState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce sprite limit
|
// Enforce sprite limit
|
||||||
if sprites.len() as u64 > Self::SPRITE_LIMIT {
|
if instances.len() as u64 > Self::SPRITE_INSTANCE_LIMIT {
|
||||||
// TODO: no panic, handle this better.
|
// TODO: no panic, handle this better.
|
||||||
panic!("Sprite limit exceeded!")
|
unreachable!("Sprite limit exceeded!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write new sprite data to buffer
|
return instances;
|
||||||
self.queue.write_buffer(
|
}
|
||||||
&self.vertex_buffers.sprite.instances,
|
|
||||||
0,
|
|
||||||
bytemuck::cast_slice(&instances),
|
|
||||||
);
|
|
||||||
|
|
||||||
render_pass.set_bind_group(0, &self.texture_array.bind_group, &[]);
|
/// Make a StarfieldInstance for each star that needs to be drawn.
|
||||||
|
/// Will panic if STARFIELD_INSTANCE_LIMIT is exceeded.
|
||||||
let nstances: Vec<StarInstance> = (-10..10)
|
///
|
||||||
.map(|x| StarInstance {
|
/// This is only called inside self.render()
|
||||||
transform: cgmath::Matrix4::from_translation(cgmath::Vector3 {
|
fn make_starfield_instances(&self, _game: &Game) -> Vec<StarfieldInstance> {
|
||||||
|
let instances: Vec<StarfieldInstance> = (-10..10)
|
||||||
|
.map(|x| StarfieldInstance {
|
||||||
|
position: Vector2 {
|
||||||
x: x as f32 / 10.0,
|
x: x as f32 / 10.0,
|
||||||
y: 0.0,
|
y: 0.0,
|
||||||
z: 0.0,
|
}
|
||||||
})
|
|
||||||
.into(),
|
.into(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// Enforce starfield limit
|
||||||
|
if instances.len() as u64 > Self::STARFIELD_INSTANCE_LIMIT {
|
||||||
|
// TODO: no panic, handle this better.
|
||||||
|
unreachable!("Starfield limit exceeded!")
|
||||||
|
}
|
||||||
|
return instances;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self, game: &Game) -> Result<(), wgpu::SurfaceError> {
|
||||||
|
let output = self.surface.get_current_texture()?;
|
||||||
|
let view = output
|
||||||
|
.texture
|
||||||
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
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: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||||
|
r: 0.0,
|
||||||
|
g: 0.0,
|
||||||
|
b: 0.0,
|
||||||
|
a: 1.0,
|
||||||
|
}),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create sprite instances
|
||||||
|
let sprite_instances = self.make_sprite_instances(game);
|
||||||
|
self.queue.write_buffer(
|
||||||
|
&self.vertex_buffers.sprite.instances,
|
||||||
|
0,
|
||||||
|
bytemuck::cast_slice(&sprite_instances),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create starfield instances
|
||||||
|
let starfield_instances = self.make_starfield_instances(game);
|
||||||
self.queue.write_buffer(
|
self.queue.write_buffer(
|
||||||
&self.vertex_buffers.starfield.instances,
|
&self.vertex_buffers.starfield.instances,
|
||||||
0,
|
0,
|
||||||
bytemuck::cast_slice(&nstances),
|
bytemuck::cast_slice(&starfield_instances),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
render_pass.set_bind_group(0, &self.texture_array.bind_group, &[]);
|
||||||
|
|
||||||
// Starfield pipeline
|
// Starfield pipeline
|
||||||
self.vertex_buffers.starfield.set_in_pass(&mut render_pass);
|
self.vertex_buffers.starfield.set_in_pass(&mut render_pass);
|
||||||
render_pass.set_pipeline(&self.starfield_pipeline);
|
render_pass.set_pipeline(&self.starfield_pipeline);
|
||||||
render_pass.draw(0..1, 0..nstances.len() as _);
|
render_pass.draw(0..1, 0..starfield_instances.len() as _);
|
||||||
|
|
||||||
// Sprite pipeline
|
// Sprite pipeline
|
||||||
self.vertex_buffers.sprite.set_in_pass(&mut render_pass);
|
self.vertex_buffers.sprite.set_in_pass(&mut render_pass);
|
||||||
render_pass.set_pipeline(&self.sprite_pipeline);
|
render_pass.set_pipeline(&self.sprite_pipeline);
|
||||||
render_pass.draw_indexed(0..SPRITE_INDICES.len() as u32, 0, 0..instances.len() as _);
|
render_pass.draw_indexed(
|
||||||
|
0..SPRITE_INDICES.len() as u32,
|
||||||
|
0,
|
||||||
|
0..sprite_instances.len() as _,
|
||||||
|
);
|
||||||
|
|
||||||
// begin_render_pass borrows encoder mutably, so we can't call finish()
|
// begin_render_pass borrows encoder mutably, so we can't call finish()
|
||||||
// without dropping this variable.
|
// without dropping this variable.
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
// Vertex shader
|
// Vertex shader
|
||||||
struct InstanceInput {
|
struct InstanceInput {
|
||||||
@location(2) transform_matrix_0: vec4<f32>,
|
@location(2) position: vec2<f32>,
|
||||||
@location(3) transform_matrix_1: vec4<f32>,
|
|
||||||
@location(4) transform_matrix_2: vec4<f32>,
|
|
||||||
@location(5) transform_matrix_3: vec4<f32>,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
|
@ -14,19 +11,10 @@ struct VertexOutput {
|
||||||
fn vertex_shader_main(
|
fn vertex_shader_main(
|
||||||
instance: InstanceInput,
|
instance: InstanceInput,
|
||||||
) -> VertexOutput {
|
) -> VertexOutput {
|
||||||
let transform_matrix = mat4x4<f32>(
|
|
||||||
instance.transform_matrix_0,
|
|
||||||
instance.transform_matrix_1,
|
|
||||||
instance.transform_matrix_2,
|
|
||||||
instance.transform_matrix_3,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stars consist of only one vertex, so we don't need to pass a buffer into this shader.
|
// Stars consist of only one vertex, so we don't need to pass a buffer into this shader.
|
||||||
// We need one instance per star, and that's it!
|
// We need one instance per star, and that's it!
|
||||||
let pos = vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.clip_position = transform_matrix * pos;
|
out.clip_position = vec4<f32>(instance.position, 0.0, 1.0);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ use super::OPENGL_TO_WGPU_MATRIX;
|
||||||
// to put it in the right place, at the right angle, with the right scale.
|
// to put it in the right place, at the right angle, with the right scale.
|
||||||
pub struct Transform {
|
pub struct Transform {
|
||||||
pub pos: Point2<f32>, // position on screen
|
pub pos: Point2<f32>, // position on screen
|
||||||
pub screen_aspect: f32, // width / height. Screen aspect ratio.
|
pub window_aspect: f32, // width / height. Screen aspect ratio.
|
||||||
pub aspect: f32, // width / height. Sprite aspect ratio.
|
pub sprite_aspect: f32, // width / height. Sprite aspect ratio.
|
||||||
pub scale: f32, // if scale = 1, this sprite will be as tall as the screen.
|
pub scale: f32, // if scale = 1, this sprite will be as tall as the screen.
|
||||||
pub rotate: Deg<f32>, // Around this object's center, in degrees measured ccw from vertical
|
pub rotate: Deg<f32>, // Around this object's center, in degrees measured ccw from vertical
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,14 @@ impl Transform {
|
||||||
//
|
//
|
||||||
// We apply the provided scale here as well as a minor optimization
|
// We apply the provided scale here as well as a minor optimization
|
||||||
let sprite_aspect_and_scale =
|
let sprite_aspect_and_scale =
|
||||||
Matrix4::from_nonuniform_scale(self.aspect * self.scale, self.scale, 1.0);
|
Matrix4::from_nonuniform_scale(self.sprite_aspect * self.scale, self.scale, 1.0);
|
||||||
|
|
||||||
// Apply rotation
|
// Apply rotation
|
||||||
let rotate = Matrix4::from_angle_z(self.rotate);
|
let rotate = Matrix4::from_angle_z(self.rotate);
|
||||||
|
|
||||||
// Apply screen aspect ratio, again preserving height.
|
// Apply screen aspect ratio, again preserving height.
|
||||||
// This must be done AFTER rotation... think about it!
|
// This must be done AFTER rotation... think about it!
|
||||||
let screen_aspect = Matrix4::from_nonuniform_scale(1.0 / self.screen_aspect, 1.0, 1.0);
|
let screen_aspect = Matrix4::from_nonuniform_scale(1.0 / self.window_aspect, 1.0, 1.0);
|
||||||
|
|
||||||
// After finishing all op, translate.
|
// After finishing all op, translate.
|
||||||
// This must be done last, all other operations
|
// This must be done last, all other operations
|
||||||
|
|
|
@ -53,46 +53,25 @@ impl BufferObject for PlainVertex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a star instance in WGSL
|
// Represents a point in the starfield instance in WGSL
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
pub struct StarInstance {
|
pub struct StarfieldInstance {
|
||||||
// All transformations we need to put this star in its place
|
// All transformations we need to put this dot in its place
|
||||||
pub transform: [[f32; 4]; 4],
|
// TODO: we don't need that much data
|
||||||
|
pub position: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufferObject for StarInstance {
|
impl BufferObject for StarfieldInstance {
|
||||||
fn layout() -> wgpu::VertexBufferLayout<'static> {
|
fn layout() -> wgpu::VertexBufferLayout<'static> {
|
||||||
wgpu::VertexBufferLayout {
|
wgpu::VertexBufferLayout {
|
||||||
array_stride: Self::SIZE,
|
array_stride: Self::SIZE,
|
||||||
// We need to switch from using a step mode of TexturedVertex 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::VertexStepMode::Instance,
|
step_mode: wgpu::VertexStepMode::Instance,
|
||||||
attributes: &[
|
attributes: &[wgpu::VertexAttribute {
|
||||||
// A mat4 takes up 4 Texturedvertex slots as it is technically 4 vec4s. We need to define a slot
|
|
||||||
// for each vec4. We'll have to reassemble the mat4 in the shader.
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: 0,
|
offset: 0,
|
||||||
shader_location: 2,
|
shader_location: 2,
|
||||||
format: wgpu::VertexFormat::Float32x4,
|
format: wgpu::VertexFormat::Float32x2,
|
||||||
},
|
}],
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
|
|
||||||
shader_location: 3,
|
|
||||||
format: wgpu::VertexFormat::Float32x4,
|
|
||||||
},
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
|
|
||||||
shader_location: 4,
|
|
||||||
format: wgpu::VertexFormat::Float32x4,
|
|
||||||
},
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
|
|
||||||
shader_location: 5,
|
|
||||||
format: wgpu::VertexFormat::Float32x4,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +92,7 @@ impl BufferObject for SpriteInstance {
|
||||||
fn layout() -> wgpu::VertexBufferLayout<'static> {
|
fn layout() -> wgpu::VertexBufferLayout<'static> {
|
||||||
wgpu::VertexBufferLayout {
|
wgpu::VertexBufferLayout {
|
||||||
array_stride: Self::SIZE,
|
array_stride: Self::SIZE,
|
||||||
// We need to switch from using a step mode of TexturedVertex to Instance
|
// Switch to a step mode of Vertex to Instance.
|
||||||
// This means that our shaders will only change to use the next
|
// This means that our shaders will only change to use the next
|
||||||
// instance when the shader starts processing a new instance
|
// instance when the shader starts processing a new instance
|
||||||
step_mode: wgpu::VertexStepMode::Instance,
|
step_mode: wgpu::VertexStepMode::Instance,
|
||||||
|
|
Loading…
Reference in New Issue