use super::batch::SpriteBatch;
use super::super::gpu::{GraphicsContext, RenderPipeline};
use super::super::resources::{Vertex, TextureCache};
use crate::runtime::AssetManager;
pub struct RenderCommands<'a> {
graphics: &'a GraphicsContext,
render_pipeline: &'a RenderPipeline,
}
impl<'a> RenderCommands<'a> {
pub fn new(
graphics: &'a GraphicsContext,
render_pipeline: &'a RenderPipeline,
) -> Self {
Self {
graphics,
render_pipeline,
}
}
pub fn execute_render_pass_with_textures(
&self,
encoder: &mut wgpu::CommandEncoder,
view: &wgpu::TextureView,
sprite_batch: &SpriteBatch,
texture_cache: &mut TextureCache,
asset_manager: &mut AssetManager,
) {
if sprite_batch.is_empty() {
return;
}
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
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: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
render_pass.set_pipeline(self.render_pipeline.pipeline());
let mut bind_groups = Vec::new();
let mut vertex_buffers = Vec::new();
let mut index_buffers = Vec::new();
for sprite_data in sprite_batch.sprites().iter() {
let cached_texture = texture_cache.get_or_load(
&sprite_data.texture_path,
asset_manager,
);
let bind_group = self.graphics.device().create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Texture Bind Group"),
layout: self.render_pipeline.texture_bind_group_layout(),
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&cached_texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&cached_texture.sampler),
},
],
});
bind_groups.push(bind_group);
let vertex_buffer = self.create_vertex_buffer(&sprite_data.vertices);
let index_buffer = self.create_index_buffer(&sprite_data.indices);
vertex_buffers.push(vertex_buffer);
index_buffers.push(index_buffer);
}
for idx in 0..sprite_batch.sprites().len() {
render_pass.set_bind_group(0, &bind_groups[idx], &[]);
render_pass.set_vertex_buffer(0, vertex_buffers[idx].slice(..));
render_pass.set_index_buffer(index_buffers[idx].slice(..), wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(0..6, 0, 0..1);
}
}
fn create_vertex_buffer(&self, sprites: &[Vertex]) -> wgpu::Buffer {
let buffer = self.graphics.device().create_buffer(&wgpu::BufferDescriptor {
label: Some("Vertex Buffer"),
size: (std::mem::size_of::<Vertex>() * sprites.len()) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
self.graphics.queue().write_buffer(&buffer, 0, bytemuck::cast_slice(sprites));
buffer
}
fn create_index_buffer(&self, indices: &[u16]) -> wgpu::Buffer {
let buffer = self.graphics.device().create_buffer(&wgpu::BufferDescriptor {
label: Some("Index Buffer"),
size: (std::mem::size_of::<u16>() * indices.len()) as u64,
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
self.graphics.queue().write_buffer(&buffer, 0, bytemuck::cast_slice(indices));
buffer
}
}