A simple map viewer

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