diff --git a/examples/simple.rs b/examples/simple.rs index cb89a1a7c3..2e9cfbc40c 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -168,17 +168,10 @@ fn main() { let cube = Mesh::load(MeshType::Cube); let plane = Mesh::load(MeshType::Plane{ size: 24.5 }); - let quad = Mesh::load(MeshType::Quad { - north_west: math::vec2(100.0, 200.0), - north_east: math::vec2(200.0, 200.0), - south_west: math::vec2(100.0, 100.0), - south_east: math::vec2(200.0, 100.0), - }); let mut mesh_storage = AssetStorage::::new(); let _cube_handle = mesh_storage.add(cube, "cube"); let plane_handle = mesh_storage.add(plane, "plane"); - let quad_handle = mesh_storage.add(quad, "quad"); world.resources.insert(mesh_storage); let transform_system_bundle = transform_system_bundle::build(&mut world); @@ -287,16 +280,37 @@ fn main() { ]); world.insert((), vec![ - - // camera ( - quad_handle, - Mesh2d, + Rect { + position: math::vec2(75.0, 75.0), + dimensions: math::vec2(100.0, 100.0), + color: math::vec4(0.0, 1.0, 0.0, 1.0), + }, + ) + ]); + + world.insert((), vec![ + ( + Rect { + position: math::vec2(50.0, 50.0), + dimensions: math::vec2(100.0, 100.0), + color: math::vec4(1.0, 0.0, 0.0, 1.0), + }, + ) + ]); + + world.insert((), vec![ + ( + Rect { + position: math::vec2(100.0, 100.0), + dimensions: math::vec2(100.0, 100.0), + color: math::vec4(0.0, 0.0, 1.0, 1.0), + }, ) ]); let mut rng = StdRng::from_entropy(); - for _ in 0 .. 70000 { + for _ in 0 .. 5 { create_person(&mut world, _cube_handle.clone(), Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0))); } diff --git a/src/render/instancing.rs b/src/render/instancing.rs new file mode 100644 index 0000000000..8afa906182 --- /dev/null +++ b/src/render/instancing.rs @@ -0,0 +1,5 @@ +pub struct InstanceBufferInfo { + pub buffer: wgpu::Buffer, + pub instance_count: usize, + pub mesh_id: usize, +} \ No newline at end of file diff --git a/src/render/mod.rs b/src/render/mod.rs index f6f15de777..b52745be9b 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -3,10 +3,12 @@ pub mod shader; pub mod mesh; pub mod render_resources; pub mod passes; +pub mod instancing; mod light; mod render_graph; mod material; +mod rect; pub use light::*; pub use shader::*; @@ -14,6 +16,7 @@ pub use render_graph::*; pub use material::*; pub use mesh::*; pub use camera::*; +pub use rect::*; use std::mem; use crate::vertex::Vertex; diff --git a/src/render/passes/forward_instanced/mod.rs b/src/render/passes/forward_instanced/mod.rs index 0e075a62d7..3801de7ec8 100644 --- a/src/render/passes/forward_instanced/mod.rs +++ b/src/render/passes/forward_instanced/mod.rs @@ -1,15 +1,9 @@ -use crate::{render::*, asset::*, render::mesh::*, LocalToWorld}; +use crate::{render::{*, instancing::InstanceBufferInfo}, asset::*, render::mesh::*, LocalToWorld}; use legion::prelude::*; use std::mem; use zerocopy::AsBytes; use wgpu::{Device, SwapChainOutput}; -pub struct InstanceBufferInfo { - pub buffer: wgpu::Buffer, - pub instance_count: usize, - pub mesh_id: usize, -} - pub struct ForwardInstancedPipeline { pub pipeline: Option, pub depth_format: wgpu::TextureFormat, diff --git a/src/render/passes/ui/mod.rs b/src/render/passes/ui/mod.rs index ceb2aecd55..56a88f13cc 100644 --- a/src/render/passes/ui/mod.rs +++ b/src/render/passes/ui/mod.rs @@ -1,10 +1,21 @@ -use crate::{render::*, asset::*, render::mesh::*}; +use crate::{render::{*, instancing::InstanceBufferInfo}, asset::*, render::mesh::*, math}; use legion::prelude::*; +use zerocopy::{AsBytes, FromBytes}; use wgpu::SwapChainOutput; +#[repr(C)] +#[derive(Clone, Copy, AsBytes, FromBytes)] +pub struct RectData { + pub position: [f32; 2], + pub dimensions: [f32; 2], + pub color: [f32; 4], + pub z_index: f32, +} + pub struct UiPipeline { pub pipeline: Option, pub depth_format: wgpu::TextureFormat, + pub quad: Option>, pub bind_group: Option, } @@ -13,13 +24,48 @@ impl UiPipeline { UiPipeline { pipeline: None, bind_group: None, + quad: None, depth_format: wgpu::TextureFormat::Depth32Float } } + + pub fn create_rect_buffers(&self, device: &wgpu::Device, world: &World) -> Vec { + let mut rect_query = >::query(); + let rect_count = rect_query.iter_immutable(world).count(); + + let mut data = Vec::with_capacity(rect_count); + // TODO: this probably isn't the best way to handle z-ordering + let mut z = 0.9999; + for rect in rect_query.iter_immutable(world) + { + data.push(RectData { + position: rect.position.into(), + dimensions: rect.dimensions.into(), + color: rect.color.into(), + z_index: z, + }); + + z -= 0.0001; + } + + let buffer = device + .create_buffer_with_data(data.as_bytes(), wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX); + + let mesh_id = *self.quad.as_ref().unwrap().id.read().unwrap(); + + let mut instance_buffer_infos = Vec::new(); + instance_buffer_infos.push(InstanceBufferInfo { + mesh_id: mesh_id, + buffer: buffer, + instance_count: rect_count, + }); + + instance_buffer_infos + } } impl Pipeline for UiPipeline { - fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) { + fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) { let vs_bytes = shader::load_glsl( include_str!("ui.vert"), shader::ShaderStage::Vertex, @@ -56,11 +102,50 @@ impl Pipeline for UiPipeline { }) }); + { + let mut mesh_storage = world.resources.get_mut::>().unwrap(); + + let quad = Mesh::load(MeshType::Quad { + north_west: math::vec2(-0.5, 0.5), + north_east: math::vec2(0.5, 0.5), + south_west: math::vec2(-0.5, -0.5), + south_east: math::vec2(0.5, -0.5), + }); + self.quad = Some(mesh_storage.add(quad, "ui_quad")); + } + let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], }); let vertex_buffer_descriptor = get_vertex_buffer_descriptor(); + let rect_data_size = mem::size_of::(); + let instance_buffer_descriptor = wgpu::VertexBufferDescriptor { + stride: rect_data_size as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &[ + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Float2, + offset: 0, + shader_location: 2, + }, + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Float2, + offset: 2 * 4, + shader_location: 3, + }, + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Float4, + offset: 4 * 4, + shader_location: 4, + }, + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Float, + offset: 8 * 4, + shader_location: 5, + }, + ], + }; let vs_module = render_graph.device.create_shader_module(&vs_bytes); let fs_module = render_graph.device.create_shader_module(&fs_bytes); @@ -101,7 +186,7 @@ impl Pipeline for UiPipeline { stencil_write_mask: 0, }), index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[vertex_buffer_descriptor], + vertex_buffers: &[vertex_buffer_descriptor, instance_buffer_descriptor], sample_count: 1, sample_mask: !0, alpha_to_coverage_enabled: false, @@ -109,34 +194,18 @@ impl Pipeline for UiPipeline { } fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) { + let instance_buffer_infos = Some(self.create_rect_buffers(&render_graph.device, world)); pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]); let mut mesh_storage = world.resources.get_mut::>().unwrap(); - let mut last_mesh_id = None; - let mut mesh_query = - <(Read>, Read)>::query() - .filter(!component::()); - for (mesh, _) in mesh_query.iter_immutable(world) { - let current_mesh_id = *mesh.id.read().unwrap(); - - let mut should_load_mesh = last_mesh_id == None; - if let Some(last) = last_mesh_id { - should_load_mesh = last != current_mesh_id; - } - - if should_load_mesh { - if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - mesh_asset.setup_buffers(&render_graph.device); - pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); - pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); - }; - } - - if let Some(ref mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1); + for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() { + if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) { + mesh_asset.setup_buffers(&render_graph.device); + pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); + pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); + pass.set_vertex_buffers(1, &[(&instance_buffer_info.buffer, 0)]); + pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. instance_buffer_info.instance_count as u32); }; - - last_mesh_id = Some(current_mesh_id); } } diff --git a/src/render/passes/ui/ui.frag b/src/render/passes/ui/ui.frag index 9673b6c4ce..50ec9a991b 100644 --- a/src/render/passes/ui/ui.frag +++ b/src/render/passes/ui/ui.frag @@ -1,10 +1,9 @@ #version 450 -layout(location = 0) in vec3 v_Normal; -layout(location = 1) in vec4 v_Position; +layout(location = 0) in vec4 v_Color; layout(location = 0) out vec4 o_Target; void main() { - o_Target = vec4(1.0, 0.0, 0.0, 1.0); + o_Target = v_Color; } diff --git a/src/render/passes/ui/ui.vert b/src/render/passes/ui/ui.vert index 4fa1006812..325c6883b2 100644 --- a/src/render/passes/ui/ui.vert +++ b/src/render/passes/ui/ui.vert @@ -1,17 +1,24 @@ #version 450 +// vertex attributes layout(location = 0) in vec4 a_Pos; layout(location = 1) in vec4 a_Normal; -layout(location = 0) out vec3 v_Normal; -layout(location = 1) out vec4 v_Position; +// instanced attributes (RectData) +layout (location = 2) in vec2 a_RectPosition; +layout (location = 3) in vec2 a_RectDimensions; +layout (location = 4) in vec4 a_RectColor; +layout (location = 5) in float a_RectZIndex; + +layout(location = 0) out vec4 v_Color; layout(set = 0, binding = 0) uniform Globals { mat4 u_ViewProj; }; void main() { - v_Normal = vec3(a_Normal.xyz); - v_Position = vec4(a_Pos); - gl_Position = u_ViewProj * v_Position; + v_Color = a_RectColor; + vec4 position = a_Pos * vec4(a_RectDimensions, 0.0, 1.0); + position = position + vec4(a_RectPosition, -a_RectZIndex, 0.0); + gl_Position = u_ViewProj * position; } diff --git a/src/render/rect.rs b/src/render/rect.rs new file mode 100644 index 0000000000..4e06e2e48f --- /dev/null +++ b/src/render/rect.rs @@ -0,0 +1,17 @@ +use crate::math::{Vec2, Vec4}; + +pub struct Rect { + pub position: Vec2, + pub dimensions: Vec2, + pub color: Vec4, +} + +impl Rect { + pub fn new(position: Vec2, dimensions: Vec2, color: Vec4) -> Self { + Rect { + position, + dimensions, + color, + } + } +} \ No newline at end of file