1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use super::*;
pub struct Program {
pub(crate) ugli: Rc<Ugli>,
pub(crate) handle: raw::Program,
pub(crate) attributes: HashMap<String, AttributeInfo>,
pub(crate) uniforms: HashMap<String, UniformInfo>,
phantom_data: PhantomData<*mut ()>,
}
#[derive(Debug)]
pub struct AttributeInfo {
pub(crate) location: raw::UInt,
pub(crate) info: raw::ActiveInfo,
}
#[derive(Debug)]
pub struct UniformInfo {
pub(crate) location: raw::UniformLocation,
pub(crate) info: raw::ActiveInfo,
}
impl Drop for Program {
fn drop(&mut self) {
self.ugli.inner.delete_program(&self.handle);
}
}
#[derive(Debug, Error)]
#[error("Program link failed:\n{log}")]
pub struct ProgramLinkError {
pub log: String,
}
impl Program {
pub fn new(ugli: &Rc<Ugli>, shaders: &[&Shader]) -> Result<Self, ProgramLinkError> {
let gl = &ugli.inner;
let mut program = Program {
ugli: ugli.clone(),
handle: gl.create_program().unwrap(),
uniforms: HashMap::new(),
attributes: HashMap::new(),
phantom_data: PhantomData,
};
for shader in shaders {
gl.attach_shader(&program.handle, &shader.handle);
}
gl.link_program(&program.handle);
for shader in shaders {
gl.detach_shader(&program.handle, &shader.handle);
}
let link_status = gl.get_program_parameter_bool(&program.handle, raw::LINK_STATUS);
if link_status == raw::FALSE {
return Err(ProgramLinkError {
log: gl.get_program_info_log(&program.handle),
});
}
let attribute_count =
gl.get_program_parameter_int(&program.handle, raw::ACTIVE_ATTRIBUTES) as usize;
for index in 0..attribute_count {
let info = gl.get_active_attrib(&program.handle, index as raw::UInt);
let name = info.name.clone();
let location = gl.get_attrib_location(&program.handle, &name);
assert!(location >= 0);
program.attributes.insert(
name,
AttributeInfo {
location: location as raw::UInt,
info,
},
);
}
let uniform_count =
gl.get_program_parameter_int(&program.handle, raw::ACTIVE_UNIFORMS) as usize;
for index in 0..uniform_count {
let info = gl.get_active_uniform(&program.handle, index as raw::UInt);
let name = info.name.clone();
let location = gl.get_uniform_location(&program.handle, &name).unwrap();
program
.uniforms
.insert(name, UniformInfo { location, info });
}
ugli.debug_check();
Ok(program)
}
pub(crate) fn bind(&self) {
self.ugli.inner.use_program(&self.handle);
}
}