A simple map viewer

context.rs 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. use buffer::BufferId;
  2. use glutin::GlContext;
  3. use glutin;
  4. use program::ProgramId;
  5. use std::collections::HashSet;
  6. use std::ffi::CStr;
  7. use std::mem;
  8. use vertex_attrib::VertexAttribLoc;
  9. pub(crate) mod gl {
  10. #![allow(unknown_lints)]
  11. #![allow(clippy)]
  12. pub use self::Gles2 as Gl;
  13. include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs"));
  14. }
  15. #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  16. pub struct TextureUnit(u32);
  17. impl TextureUnit {
  18. pub fn index(&self) -> u32 {
  19. self.0
  20. }
  21. }
  22. #[derive(Clone)]
  23. pub struct Context {
  24. pub(crate) gl: gl::Gl,
  25. active_texture_unit: TextureUnit,
  26. next_free_texture_unit: TextureUnit,
  27. active_program: ProgramId,
  28. active_buffer: BufferId,
  29. active_attribs: HashSet<VertexAttribLoc>,
  30. }
  31. impl ::std::fmt::Debug for Context {
  32. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  33. let version = unsafe {
  34. let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
  35. String::from_utf8(data).unwrap_or_else(|_| "".into())
  36. };
  37. write!(f, "Context {{ version: {:?} }}", version)
  38. }
  39. }
  40. macro_rules! check_gl_errors {
  41. ($cx:expr) => (
  42. $cx.check_errors(file!(), line!());
  43. )
  44. }
  45. impl Context {
  46. pub fn from_gl_window(window: &glutin::GlWindow) -> Context {
  47. let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
  48. let cx = Context {
  49. gl,
  50. /// Initial active texture unit is supposed to be GL_TEXTURE0
  51. active_texture_unit: TextureUnit(0),
  52. next_free_texture_unit: TextureUnit(0),
  53. active_program: ProgramId::invalid(),
  54. active_buffer: BufferId::invalid(),
  55. active_attribs: HashSet::new(),
  56. };
  57. // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
  58. // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
  59. if cx.gl.BindVertexArray.is_loaded() {
  60. unsafe {
  61. let mut vao = mem::uninitialized();
  62. cx.gl.GenVertexArrays(1, &mut vao);
  63. cx.gl.BindVertexArray(vao);
  64. }
  65. }
  66. info!("OpenGL version: {}", cx.gl_version());
  67. debug!("MAX_TEXTURE_SIZE: {}", cx.max_texture_size());
  68. cx
  69. }
  70. pub fn gl_version(&self) -> String {
  71. unsafe {
  72. let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
  73. String::from_utf8(data).unwrap_or_else(|_| "".into())
  74. }
  75. }
  76. pub fn max_texture_size(&self) -> i32 {
  77. unsafe {
  78. let mut size = 0;
  79. self.gl.GetIntegerv(gl::MAX_TEXTURE_SIZE, &mut size as *mut _);
  80. size
  81. }
  82. }
  83. pub fn check_errors(&self, file: &str, line: u32) {
  84. let mut fail = false;
  85. loop {
  86. match unsafe { self.gl.GetError() } {
  87. gl::NO_ERROR => break,
  88. gl::INVALID_VALUE => {
  89. error!("{}:{}, invalid value error", file, line);
  90. fail = true;
  91. },
  92. gl::INVALID_ENUM => {
  93. error!("{}:{}, invalid enum error", file, line);
  94. fail = true;
  95. },
  96. gl::INVALID_OPERATION => {
  97. error!("{}:{}, invalid operation error", file, line);
  98. fail = true;
  99. },
  100. gl::INVALID_FRAMEBUFFER_OPERATION => {
  101. error!("{}:{}, invalid framebuffer operation error", file, line);
  102. fail = true;
  103. },
  104. gl::OUT_OF_MEMORY => {
  105. error!("{}:{}, out of memory error", file, line);
  106. fail = true;
  107. },
  108. x => {
  109. error!("{}:{}, unknown error {}", file, line, x);
  110. fail = true;
  111. },
  112. }
  113. }
  114. if fail {
  115. panic!("OpenGL error");
  116. }
  117. }
  118. pub fn clear_color(&self, color: (f32, f32, f32, f32)) {
  119. unsafe {
  120. self.gl.ClearColor(color.0, color.1, color.2, color.3);
  121. self.gl.Clear(gl::COLOR_BUFFER_BIT);
  122. }
  123. }
  124. pub fn set_viewport(&self, x: i32, y: i32, width: u32, height: u32) {
  125. unsafe {
  126. self.gl.Viewport(
  127. x,
  128. y,
  129. width as gl::types::GLsizei,
  130. height as gl::types::GLsizei,
  131. );
  132. }
  133. }
  134. pub fn set_active_texture_unit(&mut self, unit: TextureUnit) {
  135. if unit != self.active_texture_unit {
  136. unsafe {
  137. self.gl.ActiveTexture(gl::TEXTURE0 + unit.0);
  138. }
  139. self.active_texture_unit = unit;
  140. }
  141. }
  142. pub fn occupy_free_texture_unit(&mut self) -> TextureUnit {
  143. let tu = self.next_free_texture_unit;
  144. //TODO check against max number of texture units
  145. //TODO add a way to free texture units
  146. self.next_free_texture_unit = TextureUnit(self.next_free_texture_unit.0 + 1);
  147. tu
  148. }
  149. pub fn use_program(&mut self, prog: ProgramId) {
  150. if prog != self.active_program {
  151. unsafe {
  152. self.gl.UseProgram(prog.index());
  153. }
  154. self.active_program = prog;
  155. }
  156. }
  157. pub fn bind_buffer(&mut self, buf: BufferId) {
  158. if buf != self.active_buffer {
  159. unsafe {
  160. self.gl.BindBuffer(gl::ARRAY_BUFFER, buf.index());
  161. }
  162. self.active_buffer = buf;
  163. }
  164. }
  165. /// Enable all vertex attributes given by their location and disable all other vertex
  166. /// attributes.
  167. //TODO group attribs by program
  168. pub fn enable_vertex_attribs(&mut self, attribs: &[VertexAttribLoc]) {
  169. let new_set: HashSet<_> = attribs.iter().cloned().collect();
  170. unsafe {
  171. for old_attrib in self.active_attribs.difference(&new_set) {
  172. self.gl.DisableVertexAttribArray(old_attrib.index());
  173. }
  174. for new_attrib in new_set.difference(&self.active_attribs) {
  175. self.gl.EnableVertexAttribArray(new_attrib.index());
  176. }
  177. }
  178. self.active_attribs = new_set;
  179. }
  180. pub fn enable_vertex_attrib(&mut self, attrib: VertexAttribLoc) {
  181. if !self.active_attribs.contains(&attrib) {
  182. unsafe {
  183. self.gl.EnableVertexAttribArray(attrib.index());
  184. }
  185. self.active_attribs.insert(attrib);
  186. }
  187. }
  188. /// Print status of vector attributes.
  189. pub fn debug_attribs(&self) {
  190. unsafe {
  191. let mut max_attribs = 0i32;
  192. self.gl.GetIntegerv(gl::MAX_VERTEX_ATTRIBS, &mut max_attribs as *mut _);
  193. for index in 0..(max_attribs as u32) {
  194. let mut enabled = 0i32;
  195. self.gl.GetVertexAttribiv(index, gl::VERTEX_ATTRIB_ARRAY_ENABLED, &mut enabled as *mut _);
  196. let enabled: bool = enabled != 0;
  197. println!("attribute {} enabled: {}", index, enabled);
  198. }
  199. }
  200. }
  201. }