1use crate::opengl::*;
2use crate::buffers::*;
3use crate::sys::*;
4use std::ops::*;
5use num::Num;
6use nalgebra_glm as glm;
7
8use std::collections::HashMap;
9
10#[allow(unused_imports)]
11use image::{open, DynamicImage};
12
13use image::imageops::{flip_vertical, flip_vertical_in};
14
15pub trait NumDefault: Num + Default + Copy{}
16impl <T: Num + Default + Copy> NumDefault for T {}
17
18#[derive(Debug, Copy, Clone)]
19pub enum TextureFormat {
20 Alpha = gl::ALPHA as isize,
21 Rgb = gl::RGB as isize,
22 Rgba = gl::RGBA as isize,
23}
24
25pub struct Texture {
26 id: u32,
27 unit: u32,
28 pub size: glm::TVec2<u32>
29}
30
31impl Texture {
32
33 pub fn from_file(filename: &str) -> Result<Texture, String> {
34
35 let im = match image::open(filename) {
36 Ok(d) => d,
37 Err(e) => return Err(format!("Error loading file: {} :: ImageError: {}", filename, e))
38 };
39 let im = flip_vertical(&im);
40 let layout = im.sample_layout();
41
42 let format = match layout.channels {
43 3 => TextureFormat::Rgb,
44 4 => TextureFormat::Rgba,
45 _ => TextureFormat::Alpha
46 };
47 let (w, h) = (im.width(), im.height());
48
49 let t = Texture::from_memory(im.into_raw(), w, h, format);
50 Ok(t)
51 }
52
53 pub fn from_memory(data: Vec<u8>, w: u32, h: u32, format: TextureFormat) -> Texture {
54 let gl = opengl();
55
56 let tid = gl_gen_texture();
57 unsafe {
58 opengl().BindTexture(gl::TEXTURE_2D, tid);
59 gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
60 gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
61 gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
62 gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
63 }
64
65
66 unsafe {
67 gl.TexImage2D(gl::TEXTURE_2D, 0,
68 gl::RGBA as i32, w as i32, h as i32,
69 0, gl::RGBA as u32, gl::UNSIGNED_BYTE, data.as_ptr() as *const _
70 );
71 gl.GenerateMipmap(gl::TEXTURE_2D);
72 };
73
74 Texture {
75 id: tid,
76 unit: gl::TEXTURE0, size: glm::vec2(w,h)
77 }
78 }
79
80 pub fn new_blank() -> Self {
81 let texture_data = vec![255,255,255,255];
82 Texture::from_memory(texture_data.into(), 1, 1, TextureFormat::Rgba)
83 }
84
85 pub fn set_alignment(alignment: i32) {
86 unsafe { opengl().PixelStorei(gl::UNPACK_ALIGNMENT, alignment) }
87 }
88
89 pub fn unit(&self) -> u32 { self.unit }
90 pub fn set_unit(&mut self, unit_num: u32) {
91 self.unit = gl::TEXTURE0 + unit_num;
92 }
93
94 pub fn write(&self, offset: glm::TVec2<i32>, w: i32, h: i32, format: TextureFormat, dtype: DataType, data: Vec<u8>) {
95 self.apply();
96 unsafe {
97 opengl().TexSubImage2D(gl::TEXTURE_2D, 0, offset.x, offset.y, w, h, format as u32, dtype as u32, data.as_ptr() as *const _);
98 }
99 }
100
101 pub fn id(&self) -> u32 { self.id }
102
103 pub fn apply(&self) {
104 unsafe {
105 opengl().ActiveTexture(self.unit());
106 opengl().BindTexture(gl::TEXTURE_2D, self.id);
107 }
108 }
109}
110
111
112const FRAG_TEMPLATE_VARS: &'static [u8] = b"
114#version 330
115out vec4 FragColor;
116in vec2 TexCoord;
117in vec4 Color;
118in vec3 FragPos;
119
120uniform sampler2D u_texture;
121\0";
122
123const FRAG_TEMPLATE_MAIN: &'static [u8] = b"
124void main()
125{
126 FragColor = effect(Color, u_texture, TexCoord, FragPos);
127}
128\0";
129
130const VERT_TEMPLATE_DECLS: &'static [u8] = b"#version 330
131 layout(location = 0) in vec3 l_pos;
132 layout(location = 1) in vec2 l_texCoords;
133 layout(location = 2) in vec4 l_color;
134
135 out vec2 TexCoord;
136 out vec4 Color;
137 out vec3 FragPos;
138
139 uniform mat4 u_model;
140 uniform mat4 u_view;
141 uniform mat4 u_projection;
142\0";
143
144
145const VERT_TEMPLATE_MAIN: &'static [u8] = b"
146void main()
147{
148 TexCoord = l_texCoords;
149 Color = l_color;
150
151 FragPos = vec3(u_model * vec4(l_pos, 1.0));
152
153 gl_Position = position(u_projection * u_view * u_model, vec4(l_pos.x, l_pos.y, l_pos.z, 1.0));
154}
155\0";
156
157const VERT_TEMPLATE_DECLS_INSTANCED: &'static [u8] = b"#version 330
158 layout(location = 0) in vec3 l_pos;
159 layout(location = 1) in vec2 l_texCoords;
160 layout(location = 2) in vec4 l_color;
161 layout(location = 3) in mat4 l_matrixMVP;
162 layout(location = 7) in mat4 u_modelMatrix;
163
164 out vec2 TexCoord;
165 out vec4 Color;
166 out vec3 FragPos;
167 mat4 matrixMVP = l_matrixMVP;
168\0";
169
170const DEFAULT_VERT: &'static [u8] = b"#version 330
171 layout(location = 0) in vec3 l_pos;
172 layout(location = 1) in vec2 l_texCoords;
173 layout(location = 2) in vec4 l_color;
174
175 out vec2 TexCoord;
176 out vec4 Color;
177 out vec3 FragPos;
178
179 uniform mat4 u_model;
180 uniform mat4 u_view;
181 uniform mat4 u_projection;
182
183 void main()
184 {
185 TexCoord = l_texCoords;
186 Color = l_color;
187
188 mat4 mvp = u_projection * u_view * u_model;
189 gl_Position = mvp * vec4(l_pos, 1.0);
190 }
191\0";
192
193const DEFAULT_INSTANCED_VERT: &'static [u8] = b"#version 330
194layout(location = 0) in vec3 l_pos;
195layout(location = 1) in vec2 l_texCoords;
196layout(location = 2) in vec4 l_color;
197layout(location = 3) in mat4 l_matrixMVP;
198layout(location = 7) in mat4 u_modelMatrix;
199
200out vec2 TexCoord;
201out vec4 Color;
202out vec3 FragPos;
203
204void main()
205{
206 TexCoord = l_texCoords;
207 Color = l_color;
208
209 FragPos = vec3(u_modelMatrix * vec4(l_pos, 1.0));
210
211 gl_Position = l_matrixMVP * vec4(l_pos, 1.0);
212}
213\0";
214
215const DEFAULT_FRAG: &'static [u8] = b"#version 330
216out vec4 FragColor;
217
218in vec4 Color;
219in vec2 TexCoord;
220uniform sampler2D u_texture;
221
222void main()
223{
224 FragColor = texture(u_texture, TexCoord) * Color;
225}
226\0";
227
228#[derive(Debug, Copy, Clone)]
229pub enum ShaderType {
230 Vertex = gl::VERTEX_SHADER as isize,
231 Fragment = gl::FRAGMENT_SHADER as isize
232}
233
234pub struct Shader {
235 id: u32,
236 uniform_locations: std::collections::HashMap<String, i32>
237}
238
239impl Shader {
240
241 pub fn from_file(vert_filename: &str, frag_filename: &str) -> Result<Self, String> {
242 let vshader = gl_compile_shader_from_file(vert_filename, ShaderType::Vertex)?;
243 let fshader = gl_compile_shader_from_file(frag_filename, ShaderType::Fragment)?;
244
245 let shaderid = gl_create_shader_program(vshader, fshader)?;
246 let uniforms = gl_get_active_uniforms(shaderid);
247 Ok(Shader::new(shaderid, uniforms))
248 }
249
250 pub fn from_memory<T>(vert: T, frag: T) -> Result<Self, String> where T: Into<Vec<u8>> {
251 let vshader = gl_compile_shader(vert.into().as_slice(), ShaderType::Vertex)?;
252 let fshader = gl_compile_shader(frag.into().as_slice(), ShaderType::Fragment)?;
253
254 let id = gl_create_shader_program(vshader, fshader)?;
255 let uniforms = gl_get_active_uniforms(id);
256 Ok(Shader::new(id, uniforms))
257 }
258
259 pub fn from_template(position: &[u8], effect: &[u8]) -> Result<Self, String> {
260 let vert_full = Self::concat_shader_sources(VERT_TEMPLATE_DECLS, position, VERT_TEMPLATE_MAIN);
261 let frag_full = Self::concat_shader_sources(FRAG_TEMPLATE_VARS, effect, FRAG_TEMPLATE_MAIN);
262 let s = Self::from_memory(vert_full.as_slice(), frag_full.as_slice())?;
263
264 Ok(s)
265 }
266
267 pub fn from_vert_template(position: &[u8]) -> Result<Self, String> {
268 let vert_full = Shader::concat_shader_sources(VERT_TEMPLATE_DECLS, position, VERT_TEMPLATE_MAIN);
269 let frag_full = DEFAULT_FRAG;
270 let s = Shader::from_memory(vert_full.as_slice(), frag_full)?;
271 Ok(s)
272 }
273 pub fn from_frag_template(effect: &[u8]) -> Result<Self, String> {
274 let vert_full = DEFAULT_VERT;
275 let frag_full = Shader::concat_shader_sources(FRAG_TEMPLATE_VARS, effect, FRAG_TEMPLATE_MAIN);
276 let s = Shader::from_memory(vert_full, frag_full.as_slice())?;
277 Ok(s)
278 }
279
280 pub fn from_template_instanced<'a, T>(position: T, effect:T) -> Result<Self, String> where T: Into<Option<Vec<u8>>> {
281 let (position, effect) = (position.into(), effect.into());
282 assert!(position.is_some() || effect.is_some(), " Both of the arguments for function from_template_instanced() are None. Please pass at least 1 value with Some");
283 let vert_full = match position {
284 Some(s) => Shader::concat_shader_sources(VERT_TEMPLATE_DECLS_INSTANCED, s.as_slice(), VERT_TEMPLATE_MAIN),
285 None => DEFAULT_INSTANCED_VERT.into()
286 };
287 let frag_full = match effect {
288 Some(s) => Shader::concat_shader_sources(FRAG_TEMPLATE_VARS, s.as_slice(), FRAG_TEMPLATE_MAIN),
289 None => DEFAULT_FRAG.into()
290 };
291 let s = Shader::from_memory(vert_full, frag_full)?;
292 Ok(s)
293 }
294
295 pub fn set_uniform_4f(&self, name: &str, floats: (f32, f32, f32, f32)) {
296 self.apply();
297 gl_set_uniform_4f(self.uniform_locations[name], floats);
298 }
299
300 pub fn set_uniform_3f(&self, name: &str, floats: (f32, f32, f32)) {
301 self.apply();
302 gl_set_uniform_3f(self.uniform_locations[name], floats);
303 }
304
305 pub fn set_uniform_2f(&self, name: &str, floats: (f32, f32)) {
306 self.apply();
307 gl_set_uniform_2f(self.uniform_locations[name], floats);
308 }
309
310 pub fn set_uniform_f(&self, name: &str, n: f32) {
311 self.apply();
312 gl_set_uniform_f(self.uniform_locations[name], n);
313 }
314
315 pub fn set_uniform_i(&self, name: &str, n: i32) {
316 self.apply();
317 gl_set_uniform_i(self.uniform_locations[name], n);
318 }
319
320 pub fn set_uniform_matrix(&self, name: &str, mat: &glm::Mat4) {
321 self.set_uniform_matrix_xpose(name, mat, false)
322
323 }
324
325 pub fn set_uniform_matrix_xpose(&self, name: &str, mat: &glm::Mat4, transpose: bool) {
326 self.apply();
327 gl_set_uniform_matrix_xpose(self.uniform_locations[name], glm::value_ptr(mat), transpose)
328 }
329
330 pub fn apply(&self) {
331 unsafe { opengl().UseProgram(self.id) }
332 }
333
334 pub fn default_instanced() -> Self {
335 Self::from_memory(DEFAULT_INSTANCED_VERT, DEFAULT_FRAG).unwrap()
336 }
337
338 fn new(id: u32, uniform_locations: HashMap<String, i32>) -> Self {
339 Shader { id, uniform_locations }
340 }
341
342 fn concat_shader_sources<'a, T>(a: T, b: T, c: T) -> Vec<u8> where T: Into<Vec<u8>>{
343 let su = String::from_utf8;
344 let (a, b, c) = (a.into(), b.into(), c.into());
345 let (a, b, c) = (su(a).unwrap(), su(b).unwrap(), su(c).unwrap());
346 let mut result = String::from(a);
347 result.push_str(&b);
348 result.push_str(&c);
349 result.as_bytes().to_vec()
350 }
351}
352
353impl Default for Shader {
354 fn default() -> Self {
355 Self::from_memory(DEFAULT_VERT, DEFAULT_FRAG).unwrap()
356 }
357}
358
359pub struct Mesh {
360 pub transform: Transform,
361 pub buffer: VertexBuffer,
362 pub indices: Option<ElementBuffer>,
363 pub texture: Option<Texture>,
364 pub shader: Option<Shader>,
365}
366
367impl Mesh {
368 pub fn new(buffer: VertexBuffer) -> Self {
369 Self {
370 transform: Transform::default(),
371 buffer: buffer,
372 indices: None,
373 texture: None,
374 shader: None,
375 }
376 }
377
378 pub fn new_quad(usage: DrawUsage) -> Self {
379 Self {
380 transform: Transform::default(),
381 buffer: VertexBuffer::new(&Quad::default_verts(), usage),
382 indices: Some(ElementBuffer::new_quad(6)),
383 texture: None,
384 shader: None,
385
386 }
387 }
388
389 pub fn indices(&self) -> &ElementBuffer {
390 self.indices.as_ref().expect("No Elementbuffer for Mesh")
391 }
392
393 pub fn texture(&self) -> &Texture {
394 self.texture.as_ref().expect("No Texture for Mesh")
395 }
396
397 pub fn shader(&self) -> &Shader {
398 self.shader.as_ref().expect("No Shader for Mesh")
399 }
400}
401
402pub struct RenderTexture {
403 pub frame_buffer: FrameBuffer,
404 pub render_buffer: RenderBuffer,
405 pub texture: Texture
406}
407
408impl RenderTexture {
409 pub fn new(width: u32, height: u32) -> Result<Self, String> {
410 let rt = RenderTexture {
411 frame_buffer: FrameBuffer::new(),
412 render_buffer: RenderBuffer::new(width as i32, height as i32),
413 texture: Texture::from_memory(vec![], width, height, TextureFormat::Rgb)
414 };
415 rt.frame_buffer.attach_texture(&rt.texture);
416 rt.frame_buffer.attach_render_buffer(&rt.render_buffer);
417
418 unsafe {
419 if opengl().CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE {
420 return Err("OpenGL :: Could not create RenderTexture. Framebuffer is not complete".into());
421 }
422 }
423 FrameBuffer::unbind();
424 Ok(rt)
425 }
426}
427
428impl Drop for RenderTexture {
429 fn drop(&mut self) { }
430}
431
432impl Drop for Mesh {
433 fn drop(&mut self) { }
434}
435
436impl Drop for Shader {
437
438 fn drop(&mut self) {
439 unsafe { opengl().DeleteProgram(self.id) }
440 }
441}
442
443impl Drop for Texture {
444
445 fn drop(&mut self) {
446 unsafe { opengl().DeleteTextures(1, &self.id) }
447 }
448}
449