use crate::{ asset::{Handle, Texture}, core::GetBytes, render::{ color::ColorSource, render_graph::{BindType, TextureViewDimension}, }, }; use legion::prelude::Entity; use std::collections::HashMap; // TODO: add ability to specify specific pipeline for uniforms pub trait AsUniforms { fn get_field_uniform_names(&self) -> &[FieldUniformName]; fn get_uniform_bytes(&self, name: &str) -> Option>; fn get_uniform_texture(&self, name: &str) -> Option>; fn get_shader_defs(&self) -> Option>; fn get_field_bind_type(&self, name: &str) -> Option; // TODO: support zero-copy uniforms // fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]>; } pub trait ShaderDefSuffixProvider { fn get_shader_def(&self) -> Option<&'static str>; } impl ShaderDefSuffixProvider for bool { fn get_shader_def(&self) -> Option<&'static str> { match *self { true => Some(""), false => None, } } } pub enum FieldBindType { Uniform, Texture, } pub struct UniformInfoIter<'a, 'b, T: AsUniforms> { pub field_uniform_names: &'a [FieldUniformName], pub uniforms: &'b T, pub index: usize, pub add_sampler: bool, } impl<'a, 'b, T> UniformInfoIter<'a, 'b, T> where T: AsUniforms, { pub fn new(field_uniform_names: &'a [FieldUniformName], uniforms: &'b T) -> Self { UniformInfoIter { field_uniform_names, uniforms, index: 0, add_sampler: false, } } } impl<'a, 'b, T> Iterator for UniformInfoIter<'a, 'b, T> where T: AsUniforms, { type Item = UniformInfo<'a>; fn next(&mut self) -> Option { if self.add_sampler { self.add_sampler = false; Some(UniformInfo { name: self.field_uniform_names[self.index - 1].sampler, bind_type: BindType::Sampler, }) } else { if self.index == self.field_uniform_names.len() { None } else { let index = self.index; self.index += 1; let ref field_uniform_name = self.field_uniform_names[index]; let bind_type = self .uniforms .get_field_bind_type(field_uniform_name.field) .unwrap(); Some(match bind_type { FieldBindType::Uniform => UniformInfo { bind_type: BindType::Uniform { dynamic: false, properties: Vec::new(), }, name: field_uniform_name.uniform, }, FieldBindType::Texture => { self.add_sampler = true; UniformInfo { bind_type: BindType::SampledTexture { dimension: TextureViewDimension::D2, multisampled: false, }, name: field_uniform_name.texture, } } }) } } } } pub struct FieldUniformName { pub field: &'static str, pub uniform: &'static str, pub texture: &'static str, pub sampler: &'static str, } pub trait AsFieldBindType { fn get_field_bind_type(&self) -> FieldBindType; } impl AsFieldBindType for ColorSource { fn get_field_bind_type(&self) -> FieldBindType { match *self { ColorSource::Texture(_) => FieldBindType::Texture, ColorSource::Color(_) => FieldBindType::Uniform, } } } impl AsFieldBindType for T where T: GetBytes, { default fn get_field_bind_type(&self) -> FieldBindType { FieldBindType::Uniform } } pub trait GetTexture { fn get_texture(&self) -> Option> { None } } impl GetTexture for T where T: GetBytes, { default fn get_texture(&self) -> Option> { None } } impl GetTexture for Handle { fn get_texture(&self) -> Option> { Some(self.clone()) } } impl GetTexture for ColorSource { fn get_texture(&self) -> Option> { match self { ColorSource::Color(_) => None, ColorSource::Texture(texture) => Some(texture.clone()), } } } pub struct UniformInfo<'a> { pub name: &'a str, pub bind_type: BindType, } pub struct DynamicUniformBufferInfo { pub offsets: HashMap, pub capacity: u64, pub count: u64, } impl DynamicUniformBufferInfo { pub fn new() -> Self { DynamicUniformBufferInfo { capacity: 0, count: 0, offsets: HashMap::new(), } } }