A simple map viewer

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. use glutin::GlContext;
  2. use glutin;
  3. use program::ProgramId;
  4. use std::ffi::CStr;
  5. use std::mem;
  6. pub(crate) mod gl {
  7. #![allow(unknown_lints)]
  8. #![allow(clippy)]
  9. pub use self::Gles2 as Gl;
  10. include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs"));
  11. }
  12. #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  13. pub struct TextureUnit(u32);
  14. impl TextureUnit {
  15. pub fn index(&self) -> u32 {
  16. self.0
  17. }
  18. }
  19. #[derive(Clone)]
  20. pub struct Context {
  21. pub(crate) gl: gl::Gl,
  22. active_texture_unit: TextureUnit,
  23. next_free_texture_unit: TextureUnit,
  24. active_program: ProgramId,
  25. }
  26. impl ::std::fmt::Debug for Context {
  27. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  28. let version = unsafe {
  29. let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
  30. String::from_utf8(data).unwrap_or_else(|_| "".into())
  31. };
  32. write!(f, "Context {{ version: {:?} }}", version)
  33. }
  34. }
  35. macro_rules! check_gl_errors {
  36. ($cx:expr) => (
  37. $cx.check_errors(file!(), line!());
  38. )
  39. }
  40. impl Context {
  41. pub fn from_gl_window(window: &glutin::GlWindow) -> Context {
  42. let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
  43. let cx = Context {
  44. gl,
  45. /// Initial active texture unit is supposed to be GL_TEXTURE0
  46. active_texture_unit: TextureUnit(0),
  47. next_free_texture_unit: TextureUnit(0),
  48. active_program: ProgramId::invalid(),
  49. };
  50. // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
  51. // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
  52. if cx.gl.BindVertexArray.is_loaded() {
  53. unsafe {
  54. let mut vao = mem::uninitialized();
  55. cx.gl.GenVertexArrays(1, &mut vao);
  56. cx.gl.BindVertexArray(vao);
  57. }
  58. }
  59. info!("OpenGL version: {}", cx.gl_version());
  60. debug!("MAX_TEXTURE_SIZE: {}", cx.max_texture_size());
  61. cx
  62. }
  63. pub fn gl_version(&self) -> String {
  64. unsafe {
  65. let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
  66. String::from_utf8(data).unwrap_or_else(|_| "".into())
  67. }
  68. }
  69. pub fn max_texture_size(&self) -> i32 {
  70. unsafe {
  71. let mut size = 0;
  72. self.gl.GetIntegerv(gl::MAX_TEXTURE_SIZE, &mut size as *mut _);
  73. size
  74. }
  75. }
  76. pub fn check_errors(&self, file: &str, line: u32) {
  77. let mut fail = false;
  78. loop {
  79. match unsafe { self.gl.GetError() } {
  80. gl::NO_ERROR => break,
  81. gl::INVALID_VALUE => {
  82. error!("{}:{}, invalid value error", file, line);
  83. fail = true;
  84. },
  85. gl::INVALID_ENUM => {
  86. error!("{}:{}, invalid enum error", file, line);
  87. fail = true;
  88. },
  89. gl::INVALID_OPERATION => {
  90. error!("{}:{}, invalid operation error", file, line);
  91. fail = true;
  92. },
  93. gl::INVALID_FRAMEBUFFER_OPERATION => {
  94. error!("{}:{}, invalid framebuffer operation error", file, line);
  95. fail = true;
  96. },
  97. gl::OUT_OF_MEMORY => {
  98. error!("{}:{}, out of memory error", file, line);
  99. fail = true;
  100. },
  101. x => {
  102. error!("{}:{}, unknown error {}", file, line, x);
  103. fail = true;
  104. },
  105. }
  106. }
  107. if fail {
  108. panic!("OpenGL error");
  109. }
  110. }
  111. pub fn clear_color(&self, color: (f32, f32, f32, f32)) {
  112. unsafe {
  113. self.gl.ClearColor(color.0, color.1, color.2, color.3);
  114. self.gl.Clear(gl::COLOR_BUFFER_BIT);
  115. }
  116. }
  117. pub fn set_viewport(&self, x: i32, y: i32, width: u32, height: u32) {
  118. unsafe {
  119. self.gl.Viewport(
  120. x,
  121. y,
  122. width as gl::types::GLsizei,
  123. height as gl::types::GLsizei,
  124. );
  125. }
  126. }
  127. pub fn set_active_texture_unit(&mut self, unit: TextureUnit) {
  128. if unit != self.active_texture_unit {
  129. unsafe {
  130. self.gl.ActiveTexture(gl::TEXTURE0 + unit.0);
  131. }
  132. self.active_texture_unit = unit;
  133. }
  134. }
  135. pub fn occupy_free_texture_unit(&mut self) -> TextureUnit {
  136. let tu = self.next_free_texture_unit;
  137. //TODO check against max number of texture units
  138. //TODO add a way to free texture units
  139. self.next_free_texture_unit = TextureUnit(self.next_free_texture_unit.0 + 1);
  140. tu
  141. }
  142. pub fn use_program(&mut self, prog: ProgramId) {
  143. if prog != self.active_program {
  144. unsafe {
  145. self.gl.UseProgram(prog.index());
  146. }
  147. self.active_program = prog;
  148. }
  149. }
  150. }