1use gl;
4use gl::types::*;
5use nalgebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4};
6use std;
7use std::ffi::CString;
8use std::fs::File;
9use std::io;
10use std::io::Read;
11use std::ptr;
12
13lazy_static! {
14 pub static ref DEFAULT_SHADER: Shader = Shader::default();
15}
16
17lazy_static! {
18 pub static ref SPRITE_SHADER: Shader = {
19 let (vert, frag, id);
20 unsafe {
21 let (v, f, i) = Shader::do_shader(
22 &CString::new(SPRITE_VS.as_bytes()).unwrap(),
23 &CString::new(SPRITE_FS.as_bytes()).unwrap(),
24 )
25 .unwrap();
26 frag = f;
27 vert = v;
28 id = i;
29 }
30 Shader { id, frag, vert }
31 };
32}
33
34lazy_static! {
35 pub static ref BATCH_SHADER: Shader = {
36 let (vert, frag, id);
37 unsafe {
38 let (v, f, i) = Shader::do_shader(
39 &CString::new(BATCH_VS.as_bytes()).unwrap(),
40 &CString::new(FS.as_bytes()).unwrap(),
41 )
42 .unwrap();
43 vert = v;
44 frag = f;
45 id = i;
46 }
47 Shader {
48 id: id,
49 frag: frag,
50 vert: vert,
51 }
52 };
53}
54
55lazy_static! {
56 pub static ref NO_TEXTURE_SHADER: Shader = {
57 let (vert, frag, id);
58 unsafe {
59 let (v, f, i) = Shader::do_shader(
60 &CString::new(VS.as_bytes()).unwrap(),
61 &CString::new(NO_TEXTURE_FS.as_bytes()).unwrap(),
62 )
63 .unwrap();
64 vert = v;
65 frag = f;
66 id = i;
67 }
68 Shader {
69 id: id,
70 frag: frag,
71 vert: vert,
72 }
73 };
74}
75
76#[derive(Debug)]
78pub struct Shader {
79 id: u32,
80 vert: u32,
81 frag: u32,
82}
83
84static SPRITE_VS: &'static str = "#version 330 core
85layout (location = 0) in vec2 aPos;
86layout (location = 1) in vec2 aTexCoord;
87layout (location = 2) in vec3 aColor;
88out vec3 ourColor;
89out vec2 TexCoord;
90uniform mat4 transform;
91uniform mat4 model;
92uniform mat4 projection;
93
94void main()
95{
96 gl_Position = projection * transform * vec4(aPos.xy, 0.0, 1.0);
97 ourColor = aColor;
98 TexCoord = aTexCoord;
99}";
100
101static SPRITE_FS: &'static str = "#version 330 core
102out vec4 FragColor;
103in vec3 ourColor;
104in vec2 TexCoord;
105uniform sampler2D ourTexture;
106
107void main()
108{
109 FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
110}";
111
112static BATCH_VS: &'static str = "#version 330 core
113layout (location = 0) in vec2 aPos;
114layout (location = 1) in vec2 aTexCoord;
115layout (location = 2) in vec3 aColor;
116out vec3 ourColor;
117out vec2 TexCoord;
118uniform mat4 glob_model;
119uniform mat4 projection;
120
121void main()
122{
123 gl_Position = projection * glob_model * vec4(aPos.xy, 0.0, 1.0);
124 ourColor = aColor;
125 TexCoord = aTexCoord;
126}
127";
128
129static VS: &'static str = "#version 330 core
130layout (location = 0) in vec2 aPos;
131layout (location = 1) in vec2 aTexCoord;
132layout (location = 2) in vec3 aColor;
133out vec3 ourColor;
134out vec2 TexCoord;
135uniform mat4 transform;
136uniform mat4 projection;
137
138void main()
139{
140 gl_Position = projection * transform * vec4(aPos.xy, 0.0, 1.0);
141 ourColor = aColor;
142 TexCoord = aTexCoord;
143}";
144
145static FS: &'static str = "#version 330 core
146out vec4 FragColor;
147in vec3 ourColor;
148in vec2 TexCoord;
149uniform sampler2D ourTexture;
150
151void main()
152{
153 FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
154}";
155
156static NO_TEXTURE_FS: &'static str = "#version 330 core
157out vec4 FragColor;
158in vec3 ourColor;
159
160void main()
161{
162 FragColor = vec4(ourColor, 1.0);
163}";
164
165pub fn file_to_cstring(name: &str) -> Result<CString, io::Error> {
167 let mut content = String::new();
168 File::open(name)?.read_to_string(&mut content)?;
169 Ok(CString::new(content.as_bytes()).unwrap())
170}
171
172impl Shader {
173 pub fn new(vert: &str, frag: &str) -> Result<Shader, io::Error> {
177 let vert_source = file_to_cstring(vert)?;
178 let frag_source = file_to_cstring(frag)?;
179 let (vert_id, frag_id, id);
180
181 unsafe {
182 let (v, f, i) = Shader::do_shader(&vert_source, &frag_source)?;
183 vert_id = v;
184 frag_id = f;
185 id = i;
186 }
187
188 Ok(Shader {
189 id,
190 frag: frag_id,
191 vert: vert_id,
192 })
193 }
194
195 unsafe fn do_shader(
197 vert_code: &CString,
198 frag_code: &CString,
199 ) -> Result<(u32, u32, u32), io::Error> {
200 let id = gl::CreateProgram();
201 let vert_id = Shader::compile_shader(&vert_code, gl::VERTEX_SHADER);
202 let frag_id = Shader::compile_shader(&frag_code, gl::FRAGMENT_SHADER);
203
204 gl::AttachShader(id, vert_id);
205 gl::AttachShader(id, frag_id);
206 gl::LinkProgram(id);
207
208 let mut status: i32 = 0;
209 let s: String = std::iter::repeat(' ').take(512).collect();
210 let info_log: CString = CString::new(s.as_bytes()).unwrap();
211 gl::GetProgramiv(id, gl::LINK_STATUS, &mut status);
212 if status == 0 {
213 gl::GetProgramInfoLog(id, 512, ptr::null_mut(), info_log.as_ptr() as *mut _);
214 println!("Could not link shaders {}", info_log.into_string().unwrap());
215 }
216 gl::DeleteShader(vert_id);
217 gl::DeleteShader(frag_id);
218 Ok((vert_id, frag_id, id))
219 }
220
221 unsafe fn compile_shader(code: &CString, gl_type: GLenum) -> u32 {
223 let id = gl::CreateShader(gl_type);
224 gl::ShaderSource(id, 1, &code.as_ptr(), ptr::null());
225 gl::CompileShader(id);
226 let mut success: i32 = 0;
227 let s: String = std::iter::repeat(' ').take(512).collect();
228 let info_log: CString = CString::new(s.as_bytes()).unwrap();
229 gl::GetShaderiv(id, gl::COMPILE_STATUS, &mut success);
230 if success == 0 {
231 gl::GetShaderInfoLog(id, 512, ptr::null_mut(), info_log.as_ptr() as *mut _);
232 println!(
233 "Could not compile shaders {}",
234 info_log.into_string().unwrap()
235 );
236 };
237 id
238 }
239
240 pub fn activate(&self) {
244 unsafe {
245 gl::UseProgram(self.id);
246 }
247 }
248
249 pub fn uniform_f4(&mut self, name: &str, value: Vector4<f32>) {
252 unsafe {
253 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
254 gl::Uniform4f(pos, value.x, value.y, value.z, value.w);
255 }
256 }
257
258 pub fn uniform_f3(&mut self, name: &str, value: Vector3<f32>) {
259 unsafe {
260 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
261 gl::Uniform3f(pos, value.x, value.y, value.z);
262 }
263 }
264
265 pub fn uniform_f2(&mut self, name: &str, value: Vector2<f32>) {
266 unsafe {
267 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
268 gl::Uniform2f(pos, value.x, value.y);
269 }
270 }
271
272 pub fn uniform_f(&mut self, name: &str, value: f32) {
273 unsafe {
274 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
275 gl::Uniform1f(pos, value);
276 }
277 }
278
279 pub fn uniform_bool(&mut self, name: &str, value: bool) {
282 self.uniform_int(name, value as i32);
283 }
284
285 pub fn uniform_int(&mut self, name: &str, value: i32) {
286 unsafe {
287 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
288 gl::Uniform1i(pos, value);
289 }
290 }
291
292 pub fn uniform_int2(&mut self, name: &str, value: Vector2<i32>) {
293 unsafe {
294 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
295 gl::Uniform2i(pos, value.x, value.y);
296 }
297 }
298
299 pub fn uniform_int3(&mut self, name: &str, value: Vector3<i32>) {
300 unsafe {
301 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
302 gl::Uniform3i(pos, value.x, value.y, value.z);
303 }
304 }
305
306 pub fn uniform_int4(&mut self, name: &str, value: Vector4<i32>) {
307 unsafe {
308 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
309 gl::Uniform4i(pos, value.x, value.y, value.z, value.w);
310 }
311 }
312
313 pub fn uniform_mat4f(&self, name: &str, value: &Matrix4<f32>) {
316 unsafe {
317 let string = CString::new(name.as_bytes()).unwrap();
318 let pos = gl::GetUniformLocation(self.id, string.as_ptr());
319 gl::UniformMatrix4fv(pos, 1, gl::FALSE, value.as_slice().as_ptr());
320 }
321 }
322
323 pub fn uniform_mat3f(&mut self, name: &str, value: Matrix3<f32>) {
324 unsafe {
325 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
326 gl::UniformMatrix3fv(pos, 1, gl::FALSE, value.as_slice().as_ptr());
327 }
328 }
329
330 pub fn uniform_mat2f(&mut self, name: &str, value: Matrix2<f32>) {
331 unsafe {
332 let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
333 gl::UniformMatrix2fv(pos, 1, gl::FALSE, value.as_slice().as_ptr());
334 }
335 }
336}
337
338impl Default for Shader {
339 fn default() -> Shader {
341 let vert_source = CString::new(VS.as_bytes()).unwrap();
342 let frag_source = CString::new(FS.as_bytes()).unwrap();
343 let (vert_id, frag_id, id);
344
345 unsafe {
346 let (v, f, i) = Shader::do_shader(&vert_source, &frag_source).unwrap();
347 vert_id = v;
348 frag_id = f;
349 id = i;
350 }
351
352 Shader {
353 id,
354 frag: frag_id,
355 vert: vert_id,
356 }
357 }
358}
359
360impl Drop for Shader {
361 fn drop(&mut self) {
362 unsafe {
363 gl::DeleteShader(self.vert);
364 gl::DeleteShader(self.frag);
365 gl::DeleteProgram(self.id);
366 }
367 println!("Shaders {} deleted.", self.id);
368 }
369}