A simple map viewer

program.rs 6.6KB

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