diff --git a/src/canvas/canvas_frame.rs b/src/canvas/canvas_frame.rs index 0c9938a8..773e6222 100644 --- a/src/canvas/canvas_frame.rs +++ b/src/canvas/canvas_frame.rs @@ -80,20 +80,20 @@ impl Pair { pub struct GenericCanvasFrame { frame_data: HashMap, Vec)>> } - -impl GenericCanvasFrame { - - /// Creates a bare canvas frame with empty accumulators - pub fn new() -> GenericCanvasFrame { - GenericCanvasFrame { - frame_data: Default::default() - } - } - - pub fn draw(&mut self, drawable: &dyn DrawableTest) { - self.frame_data - .entry(drawable.get_handle().clone()) - .or_insert(Vec::new()) - .push((drawable.get_vertices(), drawable.get_instances())); - } -} \ No newline at end of file +// +//impl GenericCanvasFrame { +// +// /// Creates a bare canvas frame with empty accumulators +// pub fn new() -> GenericCanvasFrame { +// GenericCanvasFrame { +// frame_data: Default::default() +// } +// } +// +// pub fn draw(&mut self, drawable: &dyn DrawableTest) { +// self.frame_data +// .entry(drawable.get_handle().clone()) +// .or_insert(Vec::new()) +// .push((drawable.get_vertices(), drawable.get_instances())); +// } +//} \ No newline at end of file diff --git a/src/canvas/canvas_state.rs b/src/canvas/canvas_state.rs index ebb9d7cf..6a3d1a9c 100644 --- a/src/canvas/canvas_state.rs +++ b/src/canvas/canvas_state.rs @@ -31,6 +31,7 @@ use crate::canvas::shader::text_shader::GlyphInstance; use std::fs::File; use std::io::Read; use rusttype::{Font, PositionedGlyph, Scale, Rect, point, GlyphId}; +use vulkano::pipeline::vertex::VertexDefinition; // I don't think this is going to work without getting into Box'ing @@ -322,7 +323,7 @@ impl CanvasState { filename: String, physical: PhysicalDevice, capabilities: Capabilities) -> Option> - where T: CompiledGraphicsPipeline { + where T: CompiledGraphicsPipeline, V: VertexDefinition { let handle = Arc::new(CompiledGraphicsPipelineHandle { handle: self.shader_buffers.len() as u32 diff --git a/src/canvas/shader/dynamic_vertex.rs b/src/canvas/shader/dynamic_vertex.rs new file mode 100644 index 00000000..1a592f74 --- /dev/null +++ b/src/canvas/shader/dynamic_vertex.rs @@ -0,0 +1,109 @@ +pub struct RuntimeVertexDef { + buffers: Vec<(u32, usize, InputRate)>, + vertex_buffer_ids: Vec<(usize, usize)>, + attributes: Vec<(String, u32, AttributeInfo)>, + num_vertices: u32, +} + +impl RuntimeVertexDef { + pub fn from_primitive(primitive: gltf::Primitive) -> RuntimeVertexDef { + use gltf::mesh::Attribute; + use gltf::accessor::{DataType, Dimensions}; + + let mut buffers = Vec::new(); + let mut vertex_buffer_ids = Vec::new(); + let mut attributes = Vec::new(); + + let mut num_vertices = u32::max_value(); + + for (attribute_id, attribute) in primitive.attributes().enumerate() { + let (name, accessor) = match attribute.clone() { + Attribute::Positions(accessor) => ("i_position".to_owned(), accessor), + Attribute::Normals(accessor) => ("i_normal".to_owned(), accessor), + Attribute::Tangents(accessor) => ("i_tangent".to_owned(), accessor), + Attribute::Colors(0, accessor) => ("i_color_0".to_owned(), accessor), + Attribute::TexCoords(0, accessor) => ("i_texcoord_0".to_owned(), accessor), + Attribute::TexCoords(1, accessor) => ("i_texcoord_1".to_owned(), accessor), + Attribute::Joints(0, accessor) => ("i_joints_0".to_owned(), accessor), + Attribute::Weights(0, accessor) => ("i_weights_0".to_owned(), accessor), + _ => unimplemented!(), + }; + + if (accessor.count() as u32) < num_vertices { + num_vertices = accessor.count() as u32; + } + + let infos = AttributeInfo { + offset: 0, + format: match (accessor.data_type(), accessor.dimensions()) { + (DataType::I8, Dimensions::Scalar) => Format::R8Snorm, + (DataType::U8, Dimensions::Scalar) => Format::R8Unorm, + (DataType::F32, Dimensions::Vec2) => Format::R32G32Sfloat, + (DataType::F32, Dimensions::Vec3) => Format::R32G32B32Sfloat, + (DataType::F32, Dimensions::Vec4) => Format::R32G32B32A32Sfloat, + _ => unimplemented!() + }, + }; + + let view = accessor.view(); + buffers.push((attribute_id as u32, view.stride().unwrap_or(accessor.size()), InputRate::Vertex)); + attributes.push((name, attribute_id as u32, infos)); + vertex_buffer_ids.push((view.buffer().index(), view.offset() + accessor.offset())); + } + + RuntimeVertexDef { + buffers: buffers, + vertex_buffer_ids: vertex_buffer_ids, + num_vertices: num_vertices, + attributes: attributes, + } + } + + /// Returns the indices of the buffers to bind as vertex buffers and the byte offset, when + /// drawing the primitive. + pub fn vertex_buffer_ids(&self) -> &[(usize, usize)] { + &self.vertex_buffer_ids + } +} + +unsafe impl VertexDefinition for RuntimeVertexDef + where I: ShaderInterfaceDef +{ + type BuffersIter = VecIntoIter<(u32, usize, InputRate)>; + type AttribsIter = VecIntoIter<(u32, u32, AttributeInfo)>; + + fn definition(&self, interface: &I) + -> Result<(Self::BuffersIter, Self::AttribsIter), IncompatibleVertexDefinitionError> + { + let buffers_iter = self.buffers.clone().into_iter(); + + let mut attribs_iter = self.attributes.iter().map(|&(ref name, buffer_id, ref infos)| { + let attrib_loc = interface + .elements() + .find(|e| e.name.as_ref().map(|n| &n[..]) == Some(&name[..])) + .unwrap() + .location.start; + (attrib_loc as u32, buffer_id, AttributeInfo { offset: infos.offset, format: infos.format }) + }).collect::>(); + + // Add dummy attributes. + for binding in interface.elements() { + if attribs_iter.iter().any(|a| a.0 == binding.location.start) { + continue; + } + + attribs_iter.push((binding.location.start, 0, + AttributeInfo { offset: 0, format: binding.format })); + } + + Ok((buffers_iter, attribs_iter.into_iter())) + } +} + +unsafe impl VertexSource>> for RuntimeVertexDef { + fn decode(&self, bufs: Vec>) + -> (Vec>, usize, usize) + { + (bufs.into_iter().map(|b| Box::new(b) as Box<_>).collect(), self.num_vertices as usize, 1) + } +} \ No newline at end of file diff --git a/src/canvas/shader/generic_shader.rs b/src/canvas/shader/generic_shader.rs index cbf677fb..6587e8dd 100644 --- a/src/canvas/shader/generic_shader.rs +++ b/src/canvas/shader/generic_shader.rs @@ -6,17 +6,18 @@ use std::collections::{HashSet, HashMap}; use vulkano::device::Device; use vulkano::framebuffer::{RenderPassAbstract, Subpass}; use vulkano::pipeline::GraphicsPipeline; -use vulkano::pipeline::shader::{GraphicsEntryPoint, ShaderModule, GraphicsShaderType, GeometryShaderExecutionMode}; +use vulkano::pipeline::shader::{GraphicsEntryPoint, ShaderModule, GraphicsShaderType, GeometryShaderExecutionMode, ShaderInterfaceDef}; use crate::canvas::shader::ShaderSpecializationConstants; use shade_runner::{Input, Output, Layout, Entry}; use std::ffi::CStr; use std::marker::PhantomData; use vulkano::pipeline::depth_stencil::{DepthStencil, Compare, DepthBounds, Stencil, StencilOp}; -use vulkano::pipeline::vertex::SingleBufferDefinition; +use vulkano::pipeline::vertex::{SingleBufferDefinition, VertexDefinition}; use crate::util::vertex_3d::Vertex3D; use shade_runner as sr; use crate::canvas::shader::common::CompiledGraphicsPipelineResources; use vulkano::memory::pool::PotentialDedicatedAllocation::Generic; +use vulkano::SafeDeref; /// CanvasShader holds the pipeline and render pass for the input shader source #[derive(Clone)] @@ -39,7 +40,7 @@ impl CompiledGraphicsPipelineResources for GenericShader {} impl CompiledGraphicsPipeline for GenericShader { /// This will explode when the shader does not want to compile - fn new(filename: String, + fn new(filename: String, device: Arc, handle: Arc, render_pass: Arc) -> GenericShader { diff --git a/src/canvas/shader/mod.rs b/src/canvas/shader/mod.rs index 5bda5c81..00ce26f9 100644 --- a/src/canvas/shader/mod.rs +++ b/src/canvas/shader/mod.rs @@ -3,11 +3,12 @@ use crate::canvas::shader::common::CompiledGraphicsPipeline; pub mod common; pub mod generic_shader; pub mod text_shader; +use mod dynamic_vertex; use crate::canvas::shader::common::*; use crate::canvas::shader::generic_shader::*; use crate::canvas::shader::text_shader::*; - +use crate::canvas::shader::dynamic_vertex::*; use vulkano::pipeline::shader::{SpecializationConstants, SpecializationMapEntry};