gl-lite 0.1.2

Wrappers around common GL objects and methods
Documentation
use std::collections::HashMap;
use super::gli;

pub struct Attribute {
  pub location: u32,
  pub size: i32,
  pub gl_type: u32,
}

pub struct Uniform {
  pub location: u32,
  pub size: i32,
  pub gl_type: u32,
}

type AttributeMap = HashMap<String, Attribute>;

type UniformMap = HashMap<String, Uniform>;

type RawShader = (u32, &'static str);

pub struct Program {
  pub attributes: AttributeMap,
  pub uniforms: UniformMap,
  program: Option<u32>,
  raw_shaders: Vec<RawShader>,
}

impl Program {
  pub fn new() -> Program {
    Program {
      attributes: HashMap::new(),
      uniforms: HashMap::new(),
      program: None,
      raw_shaders: Vec::new(),
    }
  }

  pub fn add_shader(&mut self, source: &'static str, shader_type: u32) -> &mut Program {
    if let Some(_) = self.program {
      panic!("Cannot add shader, the program has already been compiled");
    }
    self.raw_shaders.push((shader_type, source));
    self
  }

  pub fn compile(&mut self) -> &mut Program {
    if let Some(_) = self.program {
      panic!("Cannot compile, the program has already been compiled")
    }
    let raw = &mut self.raw_shaders;
    let compiled: Vec<u32> = raw.into_iter().map(|raw_shader| {
      let (shader_type, source) = raw_shader;
      let shader = gli::create_shader(*shader_type);
      gli::shader_source(shader, source);
      gli::compile_shader(shader);
      shader
    }).collect();

    let program = gli::create_program();
    for shader in compiled {
      gli::attach_shader(program, shader);
    }
    gli::link_program(program);
    self.program = Some(program);
    extract_uniforms(program, &mut self.uniforms);
    extract_attributes(program, &mut self.attributes);
    self
  }

  pub fn make_current(&self) {
    if let Some(p) = self.program {
      gli::use_program(p);
    }
  }

  pub fn get_attribute(&self, name: &String) -> Option<&Attribute> {
    self.attributes.get(name)
  }
}

fn extract_uniforms(program: u32, map: &mut UniformMap) {
  let count = gli::get_active_uniform_count(program);
  for i in 0..count {
    let (name, size, uniform_type) = gli::get_active_uniform(program, i);
    let location = gli::get_uniform_location(program, name.as_str());
    if location > -1 {
      let uniform = Uniform {
        location: location as u32,
        size: size,
        gl_type: uniform_type,
      };
      map.insert(name, uniform);
    }
  }
}

fn extract_attributes(program: u32, map: &mut AttributeMap) {
  let count = gli::get_active_attribute_count(program);
  for i in 0..count {
    let (name, size, uniform_type) = gli::get_active_attribute(program, i);
    let location = gli::get_attribute_location(program, name.as_str());
    if location > -1 {
      let attrib = Attribute {
        location: location as u32,
        size: size,
        gl_type: uniform_type,
      };
      map.insert(name, attrib);
    }
  }
}