use crate::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_uniform_infos(&self) -> &[FieldUniformName]; fn get_uniform_bytes(&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, T: AsUniforms> { pub field_uniform_names: &'a [FieldUniformName], pub uniforms: &'a T, pub index: usize, pub add_sampler: bool, } impl<'a, T> UniformInfoIter<'a, T> where T: AsUniforms { pub fn new(field_uniform_names: &'a [FieldUniformName], uniforms: &'a T) -> Self { UniformInfoIter { field_uniform_names, uniforms, index: 0, add_sampler: false, } } } impl<'a, T> Iterator for UniformInfoIter<'a, 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 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 { field: &'static str, uniform: &'static str, texture: &'static str, sampler: &'static str, } pub trait AsFieldBindType { fn get_field_uniform_type(&self) -> FieldBindType; } impl AsFieldBindType for ColorSource { fn get_field_uniform_type(&self) -> FieldBindType { match *self { ColorSource::Texture(_) => FieldBindType::Texture, ColorSource::Color(_) => FieldBindType::Uniform, } } } // impl AsFieldBindType for T // where // T: GetBytes, // { // fn get_field_uniform_type(&self) -> FieldBindType { // FieldBindType::Uniform // } // } pub struct UniformInfo<'a> { pub name: &'a str, pub bind_type: BindType, } pub struct DynamicUniformBufferInfo { pub indices: HashMap, pub offsets: HashMap, pub capacity: u64, pub count: u64, } impl DynamicUniformBufferInfo { pub fn new() -> Self { DynamicUniformBufferInfo { capacity: 0, count: 0, indices: HashMap::new(), offsets: HashMap::new(), } } }