1use std::collections::HashMap;
2use super::gli;
3
4pub struct Attribute {
5 pub location: u32,
6 pub size: i32,
7 pub gl_type: u32,
8}
9
10pub struct Uniform {
11 pub location: u32,
12 pub size: i32,
13 pub gl_type: u32,
14}
15
16type AttributeMap = HashMap<String, Attribute>;
17
18type UniformMap = HashMap<String, Uniform>;
19
20type RawShader = (u32, &'static str);
21
22pub struct Program {
23 pub attributes: AttributeMap,
24 pub uniforms: UniformMap,
25 program: Option<u32>,
26 raw_shaders: Vec<RawShader>,
27}
28
29impl Program {
30 pub fn new() -> Program {
31 Program {
32 attributes: HashMap::new(),
33 uniforms: HashMap::new(),
34 program: None,
35 raw_shaders: Vec::new(),
36 }
37 }
38
39 pub fn add_shader(&mut self, source: &'static str, shader_type: u32) -> &mut Program {
40 if let Some(_) = self.program {
41 panic!("Cannot add shader, the program has already been compiled");
42 }
43 self.raw_shaders.push((shader_type, source));
44 self
45 }
46
47 pub fn compile(&mut self) -> &mut Program {
48 if let Some(_) = self.program {
49 panic!("Cannot compile, the program has already been compiled")
50 }
51 let raw = &mut self.raw_shaders;
52 let compiled: Vec<u32> = raw.into_iter().map(|raw_shader| {
53 let (shader_type, source) = raw_shader;
54 let shader = gli::create_shader(*shader_type);
55 gli::shader_source(shader, source);
56 gli::compile_shader(shader);
57 shader
58 }).collect();
59
60 let program = gli::create_program();
61 for shader in compiled {
62 gli::attach_shader(program, shader);
63 }
64 gli::link_program(program);
65 self.program = Some(program);
66 extract_uniforms(program, &mut self.uniforms);
67 extract_attributes(program, &mut self.attributes);
68 self
69 }
70
71 pub fn make_current(&self) {
72 if let Some(p) = self.program {
73 gli::use_program(p);
74 }
75 }
76
77 pub fn get_attribute(&self, name: &String) -> Option<&Attribute> {
78 self.attributes.get(name)
79 }
80}
81
82fn extract_uniforms(program: u32, map: &mut UniformMap) {
83 let count = gli::get_active_uniform_count(program);
84 for i in 0..count {
85 let (name, size, uniform_type) = gli::get_active_uniform(program, i);
86 let location = gli::get_uniform_location(program, name.as_str());
87 if location > -1 {
88 let uniform = Uniform {
89 location: location as u32,
90 size: size,
91 gl_type: uniform_type,
92 };
93 map.insert(name, uniform);
94 }
95 }
96}
97
98fn extract_attributes(program: u32, map: &mut AttributeMap) {
99 let count = gli::get_active_attribute_count(program);
100 for i in 0..count {
101 let (name, size, uniform_type) = gli::get_active_attribute(program, i);
102 let location = gli::get_attribute_location(program, name.as_str());
103 if location > -1 {
104 let attrib = Attribute {
105 location: location as u32,
106 size: size,
107 gl_type: uniform_type,
108 };
109 map.insert(name, attrib);
110 }
111 }
112}