gllite/
program.rs

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}