Implmenting indices, and textures
This commit is contained in:
parent
b7200a4cc6
commit
0b4d062725
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
|
@ -2,27 +2,32 @@
|
|||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) color: vec3<f32>,
|
||||
};
|
||||
@location(1) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) color: vec3<f32>,
|
||||
};
|
||||
@location(0) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
model: VertexInput,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.color = model.color;
|
||||
out.tex_coords = model.tex_coords;
|
||||
out.clip_position = vec4<f32>(model.position, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fragment shader
|
||||
|
||||
@group(0) @binding(0)
|
||||
var t_diffuse: texture_2d<f32>;
|
||||
@group(0)@binding(1)
|
||||
var s_diffuse: sampler;
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(in.color, 1.0);
|
||||
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ impl<'a, 'b> Game<'static, 'static> {
|
|||
let filter = FilterFn::new(|metadata| {
|
||||
metadata.module_path()
|
||||
.unwrap_or_else(|| metadata.target())
|
||||
.starts_with("lyra_engine") && (LevelFilter::INFO >= metadata.level().to_owned())
|
||||
.starts_with("lyra_engine") && (LevelFilter::DEBUG >= metadata.level().to_owned())
|
||||
});
|
||||
|
||||
let layer = tracing_subscriber::fmt::layer();
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
use wgpu::{BindGroup, BindGroupLayout};
|
||||
|
||||
use super::{vertex::Vertex, render_buffer::{BufferStorage}};
|
||||
|
||||
pub struct Mesh {
|
||||
//material
|
||||
//texture: Option<Texture>,
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Option<Vec<u16>>,
|
||||
|
||||
pub buffer_vertex: BufferStorage,
|
||||
pub buffer_indices: Option<BufferStorage>, // TOOD: make optional
|
||||
|
||||
pub texture_bindgroup: Option<BindGroup>,
|
||||
pub texture_layout: Option<BindGroupLayout>
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn new(vertices: Vec<Vertex>, indices: Option<Vec<u16>>, buffer_vertex: BufferStorage, buffer_indices: Option<BufferStorage>, texture_bindgroup: Option<BindGroup>, texture_layout: Option<BindGroupLayout>) -> Self {
|
||||
Self {
|
||||
vertices,
|
||||
indices,
|
||||
buffer_vertex,
|
||||
buffer_indices,
|
||||
texture_bindgroup,
|
||||
texture_layout,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,3 +3,6 @@ pub mod render_pipeline;
|
|||
pub mod vertex;
|
||||
pub mod desc_buf_lay;
|
||||
pub mod render_buffer;
|
||||
pub mod render_job;
|
||||
pub mod mesh;
|
||||
pub mod texture;
|
|
@ -1,15 +1,18 @@
|
|||
use super::{desc_buf_lay::DescVertexBufferLayout, vertex::Vertex};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum RenderBuffer {
|
||||
VertexBuffer(BufferStorage),
|
||||
VertexIndexBufferPair((BufferStorage, BufferStorage)),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl RenderBuffer {
|
||||
pub fn desc<'a>(&self) -> wgpu::VertexBufferLayout<'a> {
|
||||
pub fn desc<'a>(&self) -> Option<wgpu::VertexBufferLayout<'a>> {
|
||||
match self {
|
||||
RenderBuffer::VertexBuffer(b) => Vertex::desc(),
|
||||
_ => panic!("Cannot create a VertexBufferLayout for {:?}!", *self)
|
||||
RenderBuffer::VertexBuffer(_) => Some(Vertex::desc()),
|
||||
RenderBuffer::VertexIndexBufferPair(_) => Some(Vertex::desc()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,13 +21,16 @@ impl RenderBuffer {
|
|||
pub struct BufferStorage {
|
||||
buffer: wgpu::Buffer,
|
||||
slot: u32,
|
||||
count: Option<u32>
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl BufferStorage {
|
||||
pub fn new(buffer: wgpu::Buffer, slot: u32) -> Self {
|
||||
pub fn new(buffer: wgpu::Buffer, slot: u32, count: Option<u32>) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
slot,
|
||||
count,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,4 +45,8 @@ impl BufferStorage {
|
|||
pub fn slot(&self) -> u32 {
|
||||
self.slot
|
||||
}
|
||||
|
||||
pub fn count(&self) -> Option<u32> {
|
||||
self.count
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
use super::{mesh::Mesh};
|
||||
|
||||
pub struct RenderJob {
|
||||
mesh: Mesh
|
||||
}
|
||||
|
||||
impl RenderJob {
|
||||
pub fn new(mesh: Mesh) -> Self {
|
||||
Self {
|
||||
mesh,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mesh(&self)-> &Mesh {
|
||||
&self.mesh
|
||||
}
|
||||
}
|
|
@ -1,25 +1,33 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use wgpu::{TextureFormat, PipelineLayout, RenderPipeline, VertexBufferLayout, RenderPass};
|
||||
use wgpu::{PipelineLayout, RenderPipeline, RenderPass};
|
||||
|
||||
use super::render_buffer::RenderBuffer;
|
||||
use super::{render_job::RenderJob, vertex::Vertex, desc_buf_lay::DescVertexBufferLayout};
|
||||
|
||||
pub struct FullRenderPipeline {
|
||||
layout: PipelineLayout,
|
||||
wgpu_pipeline: RenderPipeline,
|
||||
buffers: Vec<RenderBuffer>,
|
||||
jobs: Vec<RenderJob>,
|
||||
}
|
||||
|
||||
impl FullRenderPipeline {
|
||||
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, shader: &wgpu::ShaderModule, buffers: Vec<RenderBuffer>) -> Self {
|
||||
let buffer_layouts: Vec<VertexBufferLayout> = buffers.iter().map(|b| match b {
|
||||
RenderBuffer::VertexBuffer(_) => b.desc()
|
||||
}).collect();
|
||||
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, shader: &wgpu::ShaderModule, jobs: Vec<RenderJob>) -> Self {
|
||||
// Extract the layouts from all the jobs
|
||||
let mut buffer_layouts = vec![];
|
||||
let mut bind_group_layouts = vec![];
|
||||
for job in jobs.iter() {
|
||||
// Push layout for the vertex buffer, index buffer doesn't need one
|
||||
buffer_layouts.push(Vertex::desc());
|
||||
|
||||
if let Some(layout) = job.mesh().texture_layout.as_ref() {
|
||||
bind_group_layouts.push(layout);
|
||||
}
|
||||
}
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render Pipeline Layout"),
|
||||
bind_group_layouts: &[],
|
||||
bind_group_layouts: &bind_group_layouts,
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
|
@ -64,14 +72,16 @@ impl FullRenderPipeline {
|
|||
Self {
|
||||
layout: render_pipeline_layout,
|
||||
wgpu_pipeline: render_pipeline,
|
||||
buffers,
|
||||
jobs,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_layout(&self) -> &PipelineLayout {
|
||||
&self.layout
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_wgpu_pipeline(&self) -> &RenderPipeline {
|
||||
&self.wgpu_pipeline
|
||||
}
|
||||
|
@ -79,15 +89,23 @@ impl FullRenderPipeline {
|
|||
pub fn render<'a>(&'a self, pass: &mut RenderPass<'a>, vertices: Range<u32>, instances: Range<u32>) {
|
||||
pass.set_pipeline(&self.wgpu_pipeline);
|
||||
|
||||
for buffer in self.buffers.iter() {
|
||||
match buffer {
|
||||
RenderBuffer::VertexBuffer(b) => {
|
||||
pass.set_vertex_buffer(b.slot(), b.buffer().slice(..));
|
||||
},
|
||||
_ => {}
|
||||
for job in self.jobs.iter() {
|
||||
let mesh = job.mesh();
|
||||
|
||||
if let Some(tex) = mesh.texture_bindgroup.as_ref() {
|
||||
pass.set_bind_group(0, &tex, &[]);
|
||||
}
|
||||
|
||||
if let Some(indices) = mesh.buffer_indices.as_ref() {
|
||||
let indices_len = indices.count().unwrap(); // index buffers will have count, if not thats a bug
|
||||
|
||||
pass.set_vertex_buffer(mesh.buffer_vertex.slot(), mesh.buffer_vertex.buffer().slice(..));
|
||||
pass.set_index_buffer(indices.buffer().slice(..), wgpu::IndexFormat::Uint16);
|
||||
pass.draw_indexed(0..indices_len, 0, instances.clone());
|
||||
} else {
|
||||
pass.set_vertex_buffer(mesh.buffer_vertex.slot(), mesh.buffer_vertex.buffer().slice(..));
|
||||
pass.draw(vertices.clone(), instances.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pass.draw(vertices, instances);
|
||||
}
|
||||
}
|
|
@ -4,13 +4,12 @@ use std::borrow::Cow;
|
|||
use async_trait::async_trait;
|
||||
|
||||
use wgpu::util::DeviceExt;
|
||||
//use winit::{window::Window, event::WindowEvent};
|
||||
//use winit::window::Window;
|
||||
use winit::{window::Window, event::WindowEvent};
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::resources;
|
||||
|
||||
use super::{render_pipeline::FullRenderPipeline, vertex::{Vertex, VERTICES}, desc_buf_lay::DescVertexBufferLayout, render_buffer::{BufferStorage, RenderBuffer}};
|
||||
use super::texture::Texture;
|
||||
use super::{render_pipeline::FullRenderPipeline, vertex::{VERTICES}, render_buffer::BufferStorage, render_job::RenderJob, mesh::Mesh};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Renderer {
|
||||
|
@ -90,6 +89,51 @@ impl BasicRenderer {
|
|||
surface.configure(&device, &config);
|
||||
|
||||
|
||||
let diffuse_bytes = include_bytes!("../../res/happy-tree.png");
|
||||
let diffuse_texture = Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
|
||||
|
||||
let texture_bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
multisampled: false,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
// This should match the filterable field of the
|
||||
// corresponding Texture entry above.
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
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 shader_src = resources::load_string("shader.wgsl").await.expect("Failed to load shader!");
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
|
@ -105,9 +149,24 @@ impl BasicRenderer {
|
|||
}
|
||||
);
|
||||
|
||||
let index_buffer = device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(super::vertex::INDICES),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
}
|
||||
);
|
||||
|
||||
let job = RenderJob::new(Mesh::new(
|
||||
super::vertex::VERTICES.to_vec(), Some(super::vertex::INDICES.to_vec()),
|
||||
BufferStorage::new(vertex_buffer, 0, None),
|
||||
Some(BufferStorage::new(index_buffer, 0, Some(super::vertex::INDICES.len() as u32))),
|
||||
Some(diffuse_bind_group), Some(texture_bind_group_layout)
|
||||
));
|
||||
|
||||
let pipelines = vec![
|
||||
FullRenderPipeline::new(&device, &config, &shader,
|
||||
vec![RenderBuffer::VertexBuffer(BufferStorage::new(vertex_buffer, 0))])
|
||||
vec![job,])
|
||||
];
|
||||
|
||||
Self {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
use image::GenericImageView;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Texture {
|
||||
texture: wgpu::Texture,
|
||||
view: wgpu::TextureView,
|
||||
sampler: wgpu::Sampler,
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
|
||||
let img = image::load_from_memory(bytes)?;
|
||||
Self::from_image(device, queue, &img, Some(label))
|
||||
}
|
||||
|
||||
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str> ) -> anyhow::Result<Self> {
|
||||
let rgba = img.to_rgba8();
|
||||
let dimensions = img.dimensions();
|
||||
|
||||
let size = wgpu::Extent3d {
|
||||
width: dimensions.0,
|
||||
height: dimensions.1,
|
||||
depth_or_array_layers: 1,
|
||||
};
|
||||
let texture = device.create_texture(
|
||||
&wgpu::TextureDescriptor {
|
||||
label,
|
||||
size,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
}
|
||||
);
|
||||
|
||||
queue.write_texture(
|
||||
wgpu::ImageCopyTexture {
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
&rgba,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
|
||||
},
|
||||
size,
|
||||
);
|
||||
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let sampler = device.create_sampler(
|
||||
&wgpu::SamplerDescriptor {
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
Ok(Self { texture, view, sampler })
|
||||
}
|
||||
|
||||
pub fn texture(&self) -> &wgpu::Texture {
|
||||
&self.texture
|
||||
}
|
||||
|
||||
pub fn view(&self) -> &wgpu::TextureView {
|
||||
&self.view
|
||||
}
|
||||
|
||||
pub fn sampler(&self) -> &wgpu::Sampler {
|
||||
&self.sampler
|
||||
}
|
||||
}
|
|
@ -4,13 +4,22 @@ use super::desc_buf_lay::DescVertexBufferLayout;
|
|||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Vertex {
|
||||
pub position: [f32; 3],
|
||||
pub color: [f32; 3],
|
||||
//pub color: [f32; 3], // TODO: add color again
|
||||
tex_coords: [f32; 2]
|
||||
}
|
||||
|
||||
pub const VERTICES: &[Vertex] = &[
|
||||
Vertex { position: [0.0, 0.5, 0.0], color: [1.0, 0.0, 0.0] },
|
||||
Vertex { position: [-0.5, -0.5, 0.0], color: [0.0, 1.0, 0.0] },
|
||||
Vertex { position: [0.5, -0.5, 0.0], color: [0.0, 0.0, 1.0] },
|
||||
Vertex { position: [-0.0868241, 0.49240386, 0.0], tex_coords: [0.4131759, 0.00759614], }, // A
|
||||
Vertex { position: [-0.49513406, 0.06958647, 0.0], tex_coords: [0.0048659444, 0.43041354], }, // B
|
||||
Vertex { position: [-0.21918549, -0.44939706, 0.0], tex_coords: [0.28081453, 0.949397], }, // C
|
||||
Vertex { position: [0.35966998, -0.3473291, 0.0], tex_coords: [0.85967, 0.84732914], }, // D
|
||||
Vertex { position: [0.44147372, 0.2347359, 0.0], tex_coords: [0.9414737, 0.2652641], }, // E
|
||||
];
|
||||
|
||||
pub const INDICES: &[u16] = &[
|
||||
0, 1, 4,
|
||||
1, 2, 4,
|
||||
2, 3, 4,
|
||||
];
|
||||
|
||||
impl DescVertexBufferLayout for Vertex {
|
||||
|
@ -27,7 +36,7 @@ impl DescVertexBufferLayout for Vertex {
|
|||
wgpu::VertexAttribute {
|
||||
offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
|
||||
shader_location: 1,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
format: wgpu::VertexFormat::Float32x2,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue