|
|
@@ -1,5 +1,6 @@
|
|
1
|
1
|
use ::context;
|
|
2
|
2
|
use context::Context;
|
|
|
3
|
+use std::error::Error;
|
|
3
|
4
|
use std::ffi::CStr;
|
|
4
|
5
|
use std::fs::File;
|
|
5
|
6
|
use std::io::BufReader;
|
|
|
@@ -8,6 +9,7 @@ use std::mem;
|
|
8
|
9
|
use std::path::Path;
|
|
9
|
10
|
use texture::{Texture, TextureId};
|
|
10
|
11
|
|
|
|
12
|
+
|
|
11
|
13
|
#[derive(Clone, Debug)]
|
|
12
|
14
|
pub struct Program<'a> {
|
|
13
|
15
|
cx: &'a ::context::Context,
|
|
|
@@ -24,110 +26,118 @@ pub struct ProgramId {
|
|
24
|
26
|
}
|
|
25
|
27
|
|
|
26
|
28
|
impl<'a> Program<'a> {
|
|
27
|
|
- pub unsafe fn from_paths<P: AsRef<Path>>(cx: &'a Context, vert_path: P, frag_path: P) -> Program<'a> {
|
|
|
29
|
+ pub fn from_paths<P: AsRef<Path>>(cx: &'a Context, vert_path: P, frag_path: P) -> Result<Program<'a>, String> {
|
|
28
|
30
|
let vert_src = {
|
|
29
|
|
- let file = File::open(&vert_path).unwrap();
|
|
|
31
|
+ let file = File::open(&vert_path)
|
|
|
32
|
+ .map_err(|e| e.description().to_string())?;
|
|
30
|
33
|
let mut reader = BufReader::new(file);
|
|
31
|
34
|
let mut buf: Vec<u8> = vec![];
|
|
32
|
|
- reader.read_to_end(&mut buf).unwrap();
|
|
|
35
|
+ reader.read_to_end(&mut buf)
|
|
|
36
|
+ .map_err(|e| e.description().to_string())?;
|
|
33
|
37
|
buf
|
|
34
|
38
|
};
|
|
35
|
39
|
|
|
36
|
40
|
let frag_src = {
|
|
37
|
|
- let file = File::open(&frag_path).unwrap();
|
|
|
41
|
+ let file = File::open(&frag_path)
|
|
|
42
|
+ .map_err(|e| e.description().to_string())?;
|
|
38
|
43
|
let mut reader = BufReader::new(file);
|
|
39
|
44
|
let mut buf: Vec<u8> = vec![];
|
|
40
|
|
- reader.read_to_end(&mut buf).unwrap();
|
|
|
45
|
+ reader.read_to_end(&mut buf)
|
|
|
46
|
+ .map_err(|e| e.description().to_string())?;
|
|
41
|
47
|
buf
|
|
42
|
48
|
};
|
|
43
|
49
|
|
|
44
|
50
|
Self::new(cx, &vert_src, &frag_src)
|
|
45
|
51
|
}
|
|
46
|
52
|
|
|
47
|
|
- pub unsafe fn new(cx: &'a Context, vert_src: &[u8], frag_src: &[u8]) -> Program<'a> {
|
|
48
|
|
- let vert_obj = {
|
|
49
|
|
- let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
|
|
50
|
|
- let vert_len = vert_src.len() as i32;
|
|
51
|
|
- cx.gl.ShaderSource(
|
|
52
|
|
- vert_obj,
|
|
53
|
|
- 1,
|
|
54
|
|
- [vert_src.as_ptr() as *const _].as_ptr(),
|
|
55
|
|
- &vert_len as *const _);
|
|
56
|
|
- cx.gl.CompileShader(vert_obj);
|
|
57
|
|
- check_compile_errors(cx, vert_obj);
|
|
58
|
|
- check_gl_errors!(cx);
|
|
59
|
|
- vert_obj
|
|
60
|
|
- };
|
|
61
|
|
-
|
|
62
|
|
- let frag_obj = {
|
|
63
|
|
- let frag_obj = cx.gl.CreateShader(context::gl::FRAGMENT_SHADER);
|
|
64
|
|
- let frag_len = frag_src.len() as i32;
|
|
65
|
|
- cx.gl.ShaderSource(
|
|
66
|
|
- frag_obj,
|
|
67
|
|
- 1,
|
|
68
|
|
- [frag_src.as_ptr() as *const _].as_ptr(),
|
|
69
|
|
- &frag_len as *const _);
|
|
70
|
|
- cx.gl.CompileShader(frag_obj);
|
|
71
|
|
- check_compile_errors(cx, frag_obj);
|
|
72
|
|
- check_gl_errors!(cx);
|
|
73
|
|
- frag_obj
|
|
74
|
|
- };
|
|
75
|
|
-
|
|
76
|
|
- let program_obj = {
|
|
77
|
|
- let prog = cx.gl.CreateProgram();
|
|
78
|
|
- cx.gl.AttachShader(prog, vert_obj);
|
|
79
|
|
- cx.gl.AttachShader(prog, frag_obj);
|
|
80
|
|
- cx.gl.LinkProgram(prog);
|
|
81
|
|
- check_link_errors(cx, prog);
|
|
82
|
|
-
|
|
83
|
|
- cx.gl.UseProgram(prog);
|
|
84
|
|
- check_gl_errors!(cx);
|
|
85
|
|
- prog
|
|
86
|
|
- };
|
|
87
|
|
-
|
|
88
|
|
- Program {
|
|
89
|
|
- cx: cx,
|
|
90
|
|
- vert_obj: vert_obj,
|
|
91
|
|
- frag_obj: frag_obj,
|
|
92
|
|
- program_obj: program_obj,
|
|
93
|
|
- tex_ids: vec![],
|
|
94
|
|
- tex_locations: vec![],
|
|
|
53
|
+ pub fn new(cx: &'a Context, vert_src: &[u8], frag_src: &[u8]) -> Result<Program<'a>, String> {
|
|
|
54
|
+ unsafe {
|
|
|
55
|
+ let vert_obj = {
|
|
|
56
|
+ let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
|
|
|
57
|
+ let vert_len = vert_src.len() as i32;
|
|
|
58
|
+ cx.gl.ShaderSource(
|
|
|
59
|
+ vert_obj,
|
|
|
60
|
+ 1,
|
|
|
61
|
+ [vert_src.as_ptr() as *const _].as_ptr(),
|
|
|
62
|
+ &vert_len as *const _);
|
|
|
63
|
+ cx.gl.CompileShader(vert_obj);
|
|
|
64
|
+ check_compile_errors(cx, vert_obj)?;
|
|
|
65
|
+ check_gl_errors!(cx);
|
|
|
66
|
+ vert_obj
|
|
|
67
|
+ };
|
|
|
68
|
+
|
|
|
69
|
+ let frag_obj = {
|
|
|
70
|
+ let frag_obj = cx.gl.CreateShader(context::gl::FRAGMENT_SHADER);
|
|
|
71
|
+ let frag_len = frag_src.len() as i32;
|
|
|
72
|
+ cx.gl.ShaderSource(
|
|
|
73
|
+ frag_obj,
|
|
|
74
|
+ 1,
|
|
|
75
|
+ [frag_src.as_ptr() as *const _].as_ptr(),
|
|
|
76
|
+ &frag_len as *const _);
|
|
|
77
|
+ cx.gl.CompileShader(frag_obj);
|
|
|
78
|
+ check_compile_errors(cx, frag_obj)?;
|
|
|
79
|
+ check_gl_errors!(cx);
|
|
|
80
|
+ frag_obj
|
|
|
81
|
+ };
|
|
|
82
|
+
|
|
|
83
|
+ let program_obj = {
|
|
|
84
|
+ let prog = cx.gl.CreateProgram();
|
|
|
85
|
+ cx.gl.AttachShader(prog, vert_obj);
|
|
|
86
|
+ cx.gl.AttachShader(prog, frag_obj);
|
|
|
87
|
+ cx.gl.LinkProgram(prog);
|
|
|
88
|
+ check_link_errors(cx, prog)?;
|
|
|
89
|
+
|
|
|
90
|
+ cx.gl.UseProgram(prog);
|
|
|
91
|
+ check_gl_errors!(cx);
|
|
|
92
|
+ prog
|
|
|
93
|
+ };
|
|
|
94
|
+
|
|
|
95
|
+ Ok(Program {
|
|
|
96
|
+ cx: cx,
|
|
|
97
|
+ vert_obj: vert_obj,
|
|
|
98
|
+ frag_obj: frag_obj,
|
|
|
99
|
+ program_obj: program_obj,
|
|
|
100
|
+ tex_ids: vec![],
|
|
|
101
|
+ tex_locations: vec![],
|
|
|
102
|
+ })
|
|
95
|
103
|
}
|
|
96
|
104
|
}
|
|
97
|
105
|
|
|
98
|
|
- pub unsafe fn add_texture(&mut self, texture: &Texture, uniform_name: &CStr) {
|
|
|
106
|
+ pub fn add_texture(&mut self, texture: &Texture, uniform_name: &CStr) {
|
|
99
|
107
|
//TODO store reference to texture
|
|
100
|
|
- let tex_loc = self.cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
|
|
101
|
|
- check_gl_errors!(self.cx);
|
|
102
|
|
-
|
|
103
|
|
- self.tex_ids.push(texture.id());
|
|
104
|
|
- self.tex_locations.push(tex_loc);
|
|
|
108
|
+ unsafe {
|
|
|
109
|
+ let tex_loc = self.cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
|
|
|
110
|
+ check_gl_errors!(self.cx);
|
|
105
|
111
|
|
|
|
112
|
+ self.tex_ids.push(texture.id());
|
|
|
113
|
+ self.tex_locations.push(tex_loc);
|
|
|
114
|
+ }
|
|
106
|
115
|
}
|
|
107
|
116
|
|
|
108
|
|
- pub unsafe fn add_attribute(&mut self, name: &CStr, number_components: u32, stride: usize, offset: usize) {
|
|
109
|
|
- let attrib_id = self.cx.gl.GetAttribLocation(self.program_obj, name.as_ptr() as *const _);
|
|
110
|
|
- check_gl_errors!(self.cx);
|
|
111
|
|
- self.cx.gl.VertexAttribPointer(
|
|
112
|
|
- attrib_id as u32,
|
|
113
|
|
- number_components as i32, // size
|
|
114
|
|
- context::gl::FLOAT, // type
|
|
115
|
|
- 0, // normalized
|
|
116
|
|
- (stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
|
|
117
|
|
- (offset * mem::size_of::<f32>()) as *const () as *const _);
|
|
118
|
|
- check_gl_errors!(self.cx);
|
|
119
|
|
- self.cx.gl.EnableVertexAttribArray(attrib_id as u32);
|
|
|
117
|
+ pub fn add_attribute(&mut self, name: &CStr, number_components: u32, stride: usize, offset: usize) {
|
|
|
118
|
+ unsafe {
|
|
|
119
|
+ let attrib_id = self.cx.gl.GetAttribLocation(self.program_obj, name.as_ptr() as *const _);
|
|
|
120
|
+ self.cx.gl.VertexAttribPointer(
|
|
|
121
|
+ attrib_id as u32,
|
|
|
122
|
+ number_components as i32, // size
|
|
|
123
|
+ context::gl::FLOAT, // type
|
|
|
124
|
+ 0, // normalized
|
|
|
125
|
+ (stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
|
|
|
126
|
+ (offset * mem::size_of::<f32>()) as *const () as *const _);
|
|
|
127
|
+ self.cx.gl.EnableVertexAttribArray(attrib_id as u32);
|
|
|
128
|
+ }
|
|
120
|
129
|
check_gl_errors!(self.cx);
|
|
121
|
130
|
}
|
|
122
|
131
|
|
|
123
|
|
- pub unsafe fn before_render(&self) {
|
|
124
|
|
- check_gl_errors!(self.cx);
|
|
125
|
|
- //self.cx.gl.UseProgram(self.program_obj);
|
|
126
|
|
- //TODO check max texture number
|
|
127
|
|
- for (i, (tex_id, &tex_loc)) in self.tex_ids.iter().zip(&self.tex_locations).enumerate() {
|
|
128
|
|
- self.cx.gl.ActiveTexture(context::gl::TEXTURE0 + i as u32);
|
|
129
|
|
- self.cx.gl.BindTexture(context::gl::TEXTURE_2D, tex_id.id);
|
|
130
|
|
- self.cx.gl.Uniform1i(tex_loc, i as i32);
|
|
|
132
|
+ pub fn before_render(&self) {
|
|
|
133
|
+ unsafe {
|
|
|
134
|
+ //self.cx.gl.UseProgram(self.program_obj);
|
|
|
135
|
+ //TODO check max texture number
|
|
|
136
|
+ for (i, (tex_id, &tex_loc)) in self.tex_ids.iter().zip(&self.tex_locations).enumerate() {
|
|
|
137
|
+ self.cx.gl.ActiveTexture(context::gl::TEXTURE0 + i as u32);
|
|
|
138
|
+ self.cx.gl.BindTexture(context::gl::TEXTURE_2D, tex_id.id);
|
|
|
139
|
+ self.cx.gl.Uniform1i(tex_loc, i as i32);
|
|
|
140
|
+ }
|
|
131
|
141
|
}
|
|
132
|
142
|
}
|
|
133
|
143
|
|
|
|
@@ -138,66 +148,51 @@ impl<'a> Program<'a> {
|
|
138
|
148
|
}
|
|
139
|
149
|
}
|
|
140
|
150
|
|
|
141
|
|
-unsafe fn check_link_errors(cx: &Context, program_obj: u32)
|
|
142
|
|
-{
|
|
143
|
|
- let mut link_success: i32 = mem::uninitialized();
|
|
144
|
|
-
|
|
145
|
|
- cx.gl.GetProgramiv(program_obj, context::gl::LINK_STATUS, &mut link_success);
|
|
146
|
|
-
|
|
147
|
|
- if link_success == 0 {
|
|
148
|
|
-
|
|
149
|
|
- match cx.gl.GetError() {
|
|
150
|
|
- context::gl::NO_ERROR => (),
|
|
151
|
|
- context::gl::INVALID_VALUE => {
|
|
152
|
|
- error!("invalid value");
|
|
153
|
|
- return;
|
|
154
|
|
- },
|
|
155
|
|
- context::gl::INVALID_OPERATION => {
|
|
156
|
|
- error!("invalid operation");
|
|
157
|
|
- return;
|
|
158
|
|
- },
|
|
159
|
|
- _ => {
|
|
160
|
|
- error!("unknown error");
|
|
161
|
|
- return;
|
|
162
|
|
- }
|
|
163
|
|
- };
|
|
164
|
|
-
|
|
165
|
|
- let mut error_log_size: i32 = mem::uninitialized();
|
|
|
151
|
+fn check_link_errors(cx: &Context, program_obj: u32) -> Result<(), String> {
|
|
|
152
|
+ unsafe {
|
|
|
153
|
+ let mut link_success: i32 = mem::uninitialized();
|
|
166
|
154
|
|
|
167
|
|
- cx.gl.GetProgramiv(program_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
|
|
|
155
|
+ cx.gl.GetProgramiv(program_obj, context::gl::LINK_STATUS, &mut link_success);
|
|
168
|
156
|
|
|
169
|
|
- let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
|
|
|
157
|
+ if link_success == 0 {
|
|
|
158
|
+ let mut error_log_size: i32 = mem::uninitialized();
|
|
|
159
|
+ cx.gl.GetProgramiv(program_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
|
|
170
|
160
|
|
|
171
|
|
- cx.gl.GetProgramInfoLog(program_obj, error_log_size, &mut error_log_size,
|
|
172
|
|
- error_log.as_mut_ptr() as *mut context::gl::types::GLchar);
|
|
|
161
|
+ let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
|
|
|
162
|
+ cx.gl.GetProgramInfoLog(program_obj, error_log_size, &mut error_log_size,
|
|
|
163
|
+ error_log.as_mut_ptr() as *mut context::gl::types::GLchar);
|
|
173
|
164
|
|
|
174
|
|
- error_log.set_len(error_log_size as usize);
|
|
|
165
|
+ error_log.set_len(error_log_size as usize);
|
|
175
|
166
|
|
|
176
|
|
- let msg = String::from_utf8(error_log).unwrap();
|
|
177
|
|
- error!("{}", msg);
|
|
|
167
|
+ Err(String::from_utf8_lossy(&error_log).into())
|
|
|
168
|
+ } else {
|
|
|
169
|
+ Ok(())
|
|
|
170
|
+ }
|
|
178
|
171
|
}
|
|
179
|
172
|
}
|
|
180
|
173
|
|
|
181
|
|
-unsafe fn check_compile_errors(cx: &Context, shader_obj: u32) {
|
|
182
|
|
- // checking compilation success by reading a flag on the shader
|
|
183
|
|
- let compilation_success = {
|
|
184
|
|
- let mut compilation_success: i32 = mem::uninitialized();
|
|
185
|
|
- cx.gl.GetShaderiv(shader_obj, context::gl::COMPILE_STATUS, &mut compilation_success);
|
|
186
|
|
- compilation_success
|
|
187
|
|
- };
|
|
188
|
|
-
|
|
189
|
|
- if compilation_success != 1 {
|
|
190
|
|
- // compilation error
|
|
191
|
|
- let mut error_log_size: i32 = mem::uninitialized();
|
|
192
|
|
- cx.gl.GetShaderiv(shader_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
|
|
193
|
|
- let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
|
|
194
|
|
-
|
|
195
|
|
- cx.gl.GetShaderInfoLog(shader_obj, error_log_size, &mut error_log_size,
|
|
196
|
|
- error_log.as_mut_ptr() as *mut _);
|
|
197
|
|
- error_log.set_len(error_log_size as usize);
|
|
198
|
|
-
|
|
199
|
|
- if let Ok(msg) = String::from_utf8(error_log) {
|
|
200
|
|
- error!("{}", msg);
|
|
|
174
|
+fn check_compile_errors(cx: &Context, shader_obj: u32) -> Result<(), String> {
|
|
|
175
|
+ unsafe {
|
|
|
176
|
+ // checking compilation success by reading a flag on the shader
|
|
|
177
|
+ let compilation_success = {
|
|
|
178
|
+ let mut compilation_success: i32 = mem::uninitialized();
|
|
|
179
|
+ cx.gl.GetShaderiv(shader_obj, context::gl::COMPILE_STATUS, &mut compilation_success);
|
|
|
180
|
+ compilation_success
|
|
|
181
|
+ };
|
|
|
182
|
+
|
|
|
183
|
+ if compilation_success != 1 {
|
|
|
184
|
+ // compilation error
|
|
|
185
|
+ let mut error_log_size: i32 = mem::uninitialized();
|
|
|
186
|
+ cx.gl.GetShaderiv(shader_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
|
|
|
187
|
+ let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
|
|
|
188
|
+
|
|
|
189
|
+ cx.gl.GetShaderInfoLog(shader_obj, error_log_size, &mut error_log_size,
|
|
|
190
|
+ error_log.as_mut_ptr() as *mut _);
|
|
|
191
|
+ error_log.set_len(error_log_size as usize);
|
|
|
192
|
+
|
|
|
193
|
+ Err(String::from_utf8_lossy(&error_log).into())
|
|
|
194
|
+ } else {
|
|
|
195
|
+ Ok(())
|
|
201
|
196
|
}
|
|
202
|
197
|
}
|
|
203
|
198
|
}
|