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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use gl;
use gl::types::*;
use error::{GlResult, GlError};
macro_rules! get_info_log {
($get_attr:path, $get_log:path, $gl_id:expr) => {{
let mut log_length_glint: GLint = 0;
$get_attr($gl_id, gl::INFO_LOG_LENGTH, &mut log_length_glint);
let log_length = log_length_glint as usize;
if log_length == 0 {
None
} else {
let mut raw_log = Vec::<u8>::with_capacity(log_length);
$get_log($gl_id, log_length as GLsizei,
0 as *mut GLsizei, raw_log.as_mut_ptr() as *mut GLchar);
raw_log.set_len(log_length);
let log = String::from_utf8(raw_log)
.expect("OpenGL returned invalid utf8 in a program info log");
Some(log)
}
}}
}
pub fn create_program() -> GlResult<GLuint> {
let gl_id = unsafe { gl::CreateProgram() };
if gl_id == 0 {
Err(GlError::ProgramCreation)
} else {
Ok(gl_id)
}
}
pub fn create_shader(kind: GLenum, source: &str) -> GlResult<GLuint> {
unsafe {
let gl_id = gl::CreateShader(kind as _);
if gl_id == 0 {
return Err(GlError::ShaderCreation);
}
gl::ShaderSource(
gl_id,
1,
&(source.as_ptr() as *const _),
&(source.len() as _)
);
gl::CompileShader(gl_id);
let mut status = 0;
gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
if status != 1 {
Err(GlError::ShaderCompilation(
get_info_log!(gl::GetShaderiv, gl::GetShaderInfoLog, gl_id)
))
} else {
Ok(gl_id)
}
}
}
pub fn get_link_status(program_id: GLuint) -> GlResult<()> {
let mut link_status = gl::FALSE as i32;
unsafe {
gl::GetProgramiv(
program_id,
gl::LINK_STATUS,
&mut link_status as *mut _
);
if link_status != gl::TRUE as i32 {
Err(GlError::ProgramLinkage(
get_info_log!(gl::GetProgramiv, gl::GetProgramInfoLog, program_id)
))
} else {
Ok(())
}
}
}
pub fn create_basic_program(vertex_source: &str, fragment_source: &str) -> GlResult<GLuint> {
let vertex_shader = create_shader(gl::VERTEX_SHADER, vertex_source)?;
let fragment_shader = create_shader(gl::FRAGMENT_SHADER, fragment_source)?;
Ok(create_linked_program(
&[
vertex_shader,
fragment_shader,
],
true
)?)
}
pub fn create_linked_program(shaders: &[GLuint], delete_shaders: bool) -> GlResult<GLuint> {
let program = create_program()?;
unsafe {
for &shader in shaders {
gl::AttachShader(program, shader);
}
gl::LinkProgram(program);
get_link_status(program)?;
for &shader in shaders {
gl::DetachShader(program, shader);
if delete_shaders {
gl::DeleteShader(shader);
}
}
}
Ok(program)
}