A simple map viewer

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