A simple map viewer

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. use ::context;
  2. use ::std::ffi::CStr;
  3. use buffer::{Buffer, DrawMode};
  4. use context::Context;
  5. use coord::{ScreenCoord, View};
  6. use map_view::MapView;
  7. use program::Program;
  8. use texture::{Texture, TextureFormat};
  9. use tile_cache::TileCache;
  10. use tile_atlas::TileAtlas;
  11. use tile_source::TileSource;
  12. #[derive(Debug)]
  13. pub struct MapViewGl<'a> {
  14. cx: &'a Context,
  15. program: Program<'a>,
  16. buf: Buffer<'a>,
  17. viewport_size: (u32, u32),
  18. map_view: MapView,
  19. tile_cache: TileCache,
  20. tile_atlas: TileAtlas<'a>,
  21. }
  22. impl<'a> MapViewGl<'a> {
  23. pub fn new<F>(cx: &Context, initial_size: (u32, u32), update_func: F, use_network: bool) -> MapViewGl
  24. where F: Fn() + Sync + Send + 'static,
  25. {
  26. unsafe {
  27. let mut program = Program::from_paths(cx, "shader/map.vert", "shader/map.frag");
  28. check_gl_errors!(cx);
  29. let tex = Texture::empty(cx, 2048, 2048, TextureFormat::Rgb8);
  30. check_gl_errors!(cx);
  31. let buf = Buffer::new(cx, &[], 0);
  32. check_gl_errors!(cx);
  33. program.add_texture(&tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
  34. check_gl_errors!(cx);
  35. program.add_attribute(CStr::from_bytes_with_nul(b"position\0").unwrap(), 2, 8, 0);
  36. check_gl_errors!(cx);
  37. program.add_attribute(CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(), 2, 8, 2);
  38. check_gl_errors!(cx);
  39. program.add_attribute(CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
  40. check_gl_errors!(cx);
  41. program.before_render();
  42. let tile_size = 256;
  43. let mut map_view = MapView::new(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
  44. // set initial zoom
  45. {
  46. let min_dimension = f64::from(initial_size.0.min(initial_size.1));
  47. let zoom = (min_dimension / f64::from(tile_size)).log2().ceil();
  48. map_view.set_zoom(zoom);
  49. }
  50. MapViewGl {
  51. cx: cx,
  52. program: program,
  53. buf: buf,
  54. viewport_size: initial_size,
  55. map_view: map_view,
  56. tile_cache: TileCache::new(move |_tile| update_func(), use_network),
  57. tile_atlas: TileAtlas::new(tex, 256),
  58. }
  59. }
  60. }
  61. pub fn set_viewport_size(&mut self, width: u32, height: u32) {
  62. self.viewport_size = (width, height);
  63. self.map_view.set_size(f64::from(width), f64::from(height));
  64. unsafe {
  65. self.cx.gl.Viewport(
  66. 0,
  67. 0,
  68. width as context::gl::types::GLsizei,
  69. height as context::gl::types::GLsizei);
  70. }
  71. }
  72. pub fn increase_atlas_size(&mut self) -> Result<(), ()> {
  73. self.tile_atlas.double_texture_size()
  74. }
  75. /// Returns `Err` when tile cache is too small for this view.
  76. /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
  77. /// size of the tile atlas.
  78. pub fn draw(&mut self, source: &TileSource) -> Result<usize, usize> {
  79. self.tile_cache.set_view_location(View {
  80. source_id: source.id(),
  81. zoom: self.map_view.tile_zoom(),
  82. center: self.map_view.center,
  83. });
  84. self.cx.clear_color((0.2, 0.2, 0.2, 1.0));
  85. let visible_tiles = self.map_view.visible_tiles(true);
  86. let mut remainder = visible_tiles.as_slice();
  87. let mut num_draws = 0;
  88. let mut max_tiles_to_use = self.tile_cache.max_tiles();
  89. loop {
  90. let (textured_visible_tiles, remainder_opt, used_tiles) = {
  91. self.tile_atlas.textured_visible_tiles(
  92. remainder,
  93. max_tiles_to_use,
  94. source,
  95. &mut self.tile_cache,
  96. )
  97. };
  98. max_tiles_to_use -= used_tiles;
  99. let mut vertex_data: Vec<f32> = Vec::with_capacity(textured_visible_tiles.len() * (6 * 8));
  100. let scale_x = 2.0 / f64::from(self.viewport_size.0);
  101. let scale_y = -2.0 / f64::from(self.viewport_size.1);
  102. for tvt in &textured_visible_tiles {
  103. let minmax = [
  104. tvt.tex_minmax.x1 as f32,
  105. tvt.tex_minmax.y1 as f32,
  106. tvt.tex_minmax.x2 as f32,
  107. tvt.tex_minmax.y2 as f32,
  108. ];
  109. let p1 = [
  110. (tvt.screen_rect.x * scale_x - 1.0) as f32,
  111. (tvt.screen_rect.y * scale_y + 1.0) as f32,
  112. tvt.tex_rect.x1 as f32,
  113. tvt.tex_rect.y1 as f32,
  114. ];
  115. let p2 = [
  116. (tvt.screen_rect.x * scale_x - 1.0) as f32,
  117. ((tvt.screen_rect.y + tvt.screen_rect.height) * scale_y + 1.0) as f32,
  118. tvt.tex_rect.x1 as f32,
  119. tvt.tex_rect.y2 as f32,
  120. ];
  121. let p3 = [
  122. ((tvt.screen_rect.x + tvt.screen_rect.width) * scale_x - 1.0) as f32,
  123. ((tvt.screen_rect.y + tvt.screen_rect.height) * scale_y + 1.0) as f32,
  124. tvt.tex_rect.x2 as f32,
  125. tvt.tex_rect.y2 as f32,
  126. ];
  127. let p4 = [
  128. ((tvt.screen_rect.x + tvt.screen_rect.width) * scale_x - 1.0) as f32,
  129. (tvt.screen_rect.y * scale_y + 1.0) as f32,
  130. tvt.tex_rect.x2 as f32,
  131. tvt.tex_rect.y1 as f32,
  132. ];
  133. vertex_data.extend(&p1);
  134. vertex_data.extend(&minmax);
  135. vertex_data.extend(&p2);
  136. vertex_data.extend(&minmax);
  137. vertex_data.extend(&p3);
  138. vertex_data.extend(&minmax);
  139. vertex_data.extend(&p1);
  140. vertex_data.extend(&minmax);
  141. vertex_data.extend(&p3);
  142. vertex_data.extend(&minmax);
  143. vertex_data.extend(&p4);
  144. vertex_data.extend(&minmax);
  145. }
  146. self.buf.set_data(&vertex_data, vertex_data.len() / 4);
  147. self.buf.draw(DrawMode::Triangles);
  148. num_draws += 1;
  149. debug!("draw #{}: tvt.len() = {}, remainder = {:?}, max_tiles = {}",
  150. num_draws,
  151. textured_visible_tiles.len(),
  152. remainder_opt.map(|r| r.len()),
  153. max_tiles_to_use);
  154. if max_tiles_to_use == 0 {
  155. warn!("tile cache is too small for this view.");
  156. return Err(num_draws);
  157. }
  158. match remainder_opt {
  159. None => return Ok(num_draws),
  160. Some(new_remainder) => {
  161. if new_remainder.len() >= remainder.len() {
  162. warn!("failed to draw all tiles. number of remaining tiles did not decrease.");
  163. return Err(num_draws);
  164. } else {
  165. remainder = new_remainder;
  166. }
  167. },
  168. }
  169. }
  170. }
  171. pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
  172. let new_zoom = {
  173. let z = (self.map_view.zoom2 + f64::from(steps) * step_size) / step_size;
  174. if steps > 0 {
  175. z.ceil() * step_size
  176. } else {
  177. z.floor() * step_size
  178. }
  179. }.max(0.0).min(22.0);
  180. self.map_view.set_zoom(new_zoom);
  181. }
  182. pub fn zoom(&mut self, zoom_delta: f64) {
  183. if self.map_view.zoom2 + zoom_delta < 0.0 {
  184. self.map_view.set_zoom(0.0);
  185. } else if self.map_view.zoom2 + zoom_delta > 22.0 {
  186. self.map_view.set_zoom(22.0);
  187. } else {
  188. self.map_view.zoom(zoom_delta);
  189. }
  190. }
  191. pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
  192. if self.map_view.zoom2 + zoom_delta < 0.0 {
  193. self.map_view.set_zoom_at(pos, 0.0);
  194. } else if self.map_view.zoom2 + zoom_delta > 22.0 {
  195. self.map_view.set_zoom_at(pos, 22.0);
  196. } else {
  197. self.map_view.zoom_at(pos, zoom_delta);
  198. }
  199. self.map_view.center.normalize_xy();
  200. }
  201. pub fn change_tile_zoom_offset(&mut self, delta_offset: f64) {
  202. let offset = self.map_view.tile_zoom_offset();
  203. self.map_view.set_tile_zoom_offset(offset + delta_offset);
  204. }
  205. pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
  206. self.map_view.move_pixel(delta_x, delta_y);
  207. self.map_view.center.normalize_xy();
  208. }
  209. }