A simple map viewer

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. use ::context;
  2. use buffer::Buffer;
  3. use context::Context;
  4. use std::ffi::CStr;
  5. use std::fs::File;
  6. use std::io::BufReader;
  7. use std::io::Read;
  8. use std::mem;
  9. use std::path::Path;
  10. use texture::Texture;
  11. use vertex_attrib::{VertexAttribLoc, VertexAttribParams};
  12. #[derive(Clone, Debug)]
  13. pub struct Program {
  14. vert_obj: u32,
  15. frag_obj: u32,
  16. program_id: ProgramId,
  17. attrib_locs: Vec<VertexAttribLoc>,
  18. attrib_params: Vec<VertexAttribParams>,
  19. }
  20. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  21. pub struct ProgramId {
  22. id: u32,
  23. }
  24. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  25. pub struct UniformId {
  26. id: i32,
  27. }
  28. impl ProgramId {
  29. /// Returns an invalid `ProgramId`.
  30. pub fn invalid() -> Self {
  31. ProgramId{ id: 0 }
  32. }
  33. pub fn index(&self) -> u32 {
  34. self.id
  35. }
  36. }
  37. impl Program {
  38. pub fn from_paths<P: AsRef<Path>>(
  39. cx: &mut Context,
  40. vert_path: P,
  41. frag_path: P,
  42. ) -> Result<Program, String> {
  43. let vert_src = {
  44. let file = File::open(&vert_path)
  45. .map_err(|e| format!("{}", e))?;
  46. let mut reader = BufReader::new(file);
  47. let mut buf: Vec<u8> = vec![];
  48. reader.read_to_end(&mut buf)
  49. .map_err(|e| format!("{}", e))?;
  50. buf
  51. };
  52. let frag_src = {
  53. let file = File::open(&frag_path)
  54. .map_err(|e| format!("{}", e))?;
  55. let mut reader = BufReader::new(file);
  56. let mut buf: Vec<u8> = vec![];
  57. reader.read_to_end(&mut buf)
  58. .map_err(|e| format!("{}", e))?;
  59. buf
  60. };
  61. Self::new(cx, &vert_src, &frag_src)
  62. }
  63. pub fn new(
  64. cx: &mut Context,
  65. vert_src: &[u8],
  66. frag_src: &[u8],
  67. ) -> Result<Program, String> {
  68. unsafe {
  69. let vert_obj = {
  70. let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
  71. let vert_len = vert_src.len() as i32;
  72. cx.gl.ShaderSource(
  73. vert_obj,
  74. 1,
  75. [vert_src.as_ptr() as *const _].as_ptr(),
  76. &vert_len as *const _);
  77. cx.gl.CompileShader(vert_obj);
  78. check_compile_errors(cx, vert_obj)?;
  79. check_gl_errors!(cx);
  80. vert_obj
  81. };
  82. let frag_obj = {
  83. let frag_obj = cx.gl.CreateShader(context::gl::FRAGMENT_SHADER);
  84. let frag_len = frag_src.len() as i32;
  85. cx.gl.ShaderSource(
  86. frag_obj,
  87. 1,
  88. [frag_src.as_ptr() as *const _].as_ptr(),
  89. &frag_len as *const _);
  90. cx.gl.CompileShader(frag_obj);
  91. check_compile_errors(cx, frag_obj)?;
  92. check_gl_errors!(cx);
  93. frag_obj
  94. };
  95. let program_id = {
  96. let prog = cx.gl.CreateProgram();
  97. cx.gl.AttachShader(prog, vert_obj);
  98. cx.gl.AttachShader(prog, frag_obj);
  99. cx.gl.LinkProgram(prog);
  100. check_link_errors(cx, prog)?;
  101. ProgramId { id: prog }
  102. };
  103. cx.use_program(program_id);
  104. check_gl_errors!(cx);
  105. Ok(
  106. Program {
  107. vert_obj,
  108. frag_obj,
  109. program_id,
  110. attrib_locs: vec![],
  111. attrib_params: vec![],
  112. }
  113. )
  114. }
  115. }
  116. pub fn add_texture(&mut self, cx: &mut Context, texture: &Texture, uniform_name: &CStr) {
  117. //TODO store reference to texture
  118. cx.use_program(self.program_id);
  119. unsafe {
  120. let tex_loc = cx.gl.GetUniformLocation(self.program_id.index(), uniform_name.as_ptr() as *const _);
  121. check_gl_errors!(cx);
  122. cx.gl.Uniform1i(tex_loc, texture.unit().index() as i32);
  123. }
  124. }
  125. pub fn get_uniform_id(&mut self, cx: &mut Context, uniform_name: &CStr) -> Option<UniformId> {
  126. cx.use_program(self.program_id);
  127. let loc: i32 = unsafe {
  128. cx.gl.GetUniformLocation(self.program_id.index(), uniform_name.as_ptr() as *const _)
  129. };
  130. check_gl_errors!(cx);
  131. if loc == -1 {
  132. None
  133. } else {
  134. Some(UniformId { id: loc })
  135. }
  136. }
  137. pub fn set_uniform_2f(&mut self, cx: &mut Context, uniform_id: UniformId, v0: f32, v1: f32) {
  138. cx.use_program(self.program_id);
  139. unsafe {
  140. cx.gl.Uniform2f(uniform_id.id, v0, v1);
  141. };
  142. }
  143. //TODO rename function or integrate into new()
  144. pub fn add_attribute(
  145. &mut self,
  146. cx: &mut Context,
  147. name: &CStr,
  148. params: &VertexAttribParams,
  149. ) {
  150. cx.use_program(self.program_id);
  151. let attrib_loc = unsafe {
  152. cx.gl.GetAttribLocation(self.program_id.index(), name.as_ptr() as *const _)
  153. };
  154. if attrib_loc < 0 {
  155. panic!("Attribute location not found: {:?}", name);
  156. }
  157. let attrib_loc = VertexAttribLoc::new(attrib_loc as u32);
  158. check_gl_errors!(cx);
  159. self.attrib_locs.push(attrib_loc);
  160. self.attrib_params.push(params.clone());
  161. }
  162. pub fn enable_vertex_attribs(&self, cx: &mut Context) {
  163. cx.enable_vertex_attribs(&self.attrib_locs)
  164. }
  165. //TODO use separate buffer for each attribute
  166. pub fn set_vertex_attribs(
  167. &self,
  168. cx: &mut Context,
  169. buffer: &Buffer,
  170. ) {
  171. cx.bind_buffer(buffer.id());
  172. for (params, loc) in self.attrib_params.iter().zip(self.attrib_locs.iter()) {
  173. params.set(cx, *loc);
  174. }
  175. }
  176. pub fn id(&self) -> ProgramId {
  177. self.program_id
  178. }
  179. }
  180. fn check_link_errors(cx: &Context, program_obj: u32) -> Result<(), String> {
  181. unsafe {
  182. let mut link_success: i32 = mem::uninitialized();
  183. cx.gl.GetProgramiv(program_obj, context::gl::LINK_STATUS, &mut link_success);
  184. if link_success == 0 {
  185. let mut error_log_size: i32 = mem::uninitialized();
  186. cx.gl.GetProgramiv(program_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. cx.gl.GetProgramInfoLog(program_obj, error_log_size, &mut error_log_size,
  189. error_log.as_mut_ptr() as *mut context::gl::types::GLchar);
  190. error_log.set_len(error_log_size as usize);
  191. Err(String::from_utf8_lossy(&error_log).into())
  192. } else {
  193. Ok(())
  194. }
  195. }
  196. }
  197. fn check_compile_errors(cx: &Context, shader_obj: u32) -> Result<(), String> {
  198. unsafe {
  199. // checking compilation success by reading a flag on the shader
  200. let compilation_success = {
  201. let mut compilation_success: i32 = mem::uninitialized();
  202. cx.gl.GetShaderiv(shader_obj, context::gl::COMPILE_STATUS, &mut compilation_success);
  203. compilation_success
  204. };
  205. if compilation_success != 1 {
  206. // compilation error
  207. let mut error_log_size: i32 = mem::uninitialized();
  208. cx.gl.GetShaderiv(shader_obj, context::gl::INFO_LOG_LENGTH, &mut error_log_size);
  209. let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
  210. cx.gl.GetShaderInfoLog(shader_obj, error_log_size, &mut error_log_size,
  211. error_log.as_mut_ptr() as *mut _);
  212. error_log.set_len(error_log_size as usize);
  213. Err(String::from_utf8_lossy(&error_log).into())
  214. } else {
  215. Ok(())
  216. }
  217. }
  218. }