use std::collections::*; use std::iter::FromIterator; use crate::{ renderable_model::AttrMap, shader::ShaderProgram, }; pub struct ShaderClosure { program: ShaderProgram, uniforms: HashMap , attributes: AttrMap, } pub struct BorrowedShaderVars <'a> { pub unis: &'a HashMap , pub attrs: &'a AttrMap, } pub fn get_shader_attrs ( shader: &ShaderProgram, attr_names: &[(usize, &str)] ) -> AttrMap { let mut v = vec! [None; attr_names.iter ().map (|(i, _)| i).max ().unwrap () + 1]; let attrs = shader.get_attribute_locations (attr_names.iter ().map (|(_, v)| v).copied ()); for ((i, _), loc) in attr_names.iter ().zip (attrs.into_iter ()) { v [*i] = loc; } v } pub fn get_shader_uniforms ( shader: &ShaderProgram, uni_names: &[(u32, &str)] ) -> HashMap { let unis = shader.get_uniform_locations (uni_names.iter ().map (|(_, v)| v).copied ()); let pairs = uni_names.iter ().map (|(i, _)| i).copied () .zip (unis.into_iter ()) .filter (|(_, v)| *v >= 0) ; HashMap::from_iter (pairs) } impl ShaderClosure { pub fn new ( program: ShaderProgram, uniform_names: &[(u32, &str)], attr_names: &[(usize, &str)] ) -> Self { let uniforms = get_shader_uniforms (&program, uniform_names); let attributes = get_shader_attrs (&program, attr_names); Self { program, uniforms, attributes, } } pub fn get_id (&self) -> u32 { self.program.get_id () } pub fn with (&self, previous_id: Option , callback: F) where F: Fn (BorrowedShaderVars) { if previous_id != Some (self.get_id ()) { self.program.use_program (); } else { //println! ("Elided use_program ()"); } callback (BorrowedShaderVars { unis: &self.uniforms, attrs: &self.attributes, }); } } pub trait ShaderLookup { fn lookup <'a> (&'a self, id: u32) -> &'a ShaderClosure; }