A simple map viewer

map_view_gl.rs 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. use atmos_layer::AtmosLayer;
  2. use cgmath::vec2;
  3. use context::Context;
  4. use coord::{MapCoord, ScreenCoord};
  5. use marker_layer::MarkerLayer;
  6. use mercator_tile_layer::MercatorTileLayer;
  7. use mercator_view::MercatorView;
  8. use ortho_tile_layer::OrthoTileLayer;
  9. use orthografic_view::OrthograficView;
  10. use projection::Projection;
  11. use projection_view::ProjectionView;
  12. use session::Session;
  13. use texture::{Texture, TextureFormat};
  14. use tile_atlas::TileAtlas;
  15. use tile_cache::TileCache;
  16. use tile_source::TileSource;
  17. pub const MIN_TILE_ZOOM_OFFSET: f64 = -4.0;
  18. pub const MAX_TILE_ZOOM_OFFSET: f64 = 4.0;
  19. #[derive(Debug)]
  20. pub struct MapViewGl {
  21. proj_view: ProjectionView,
  22. /// Size in physical pixels
  23. viewport_size: (u32, u32),
  24. dpi_factor: f64,
  25. tile_cache: TileCache,
  26. tile_atlas: TileAtlas,
  27. mercator_tile_layer: MercatorTileLayer,
  28. marker_layer: MarkerLayer,
  29. ortho_tile_layer: OrthoTileLayer,
  30. atmos_layer: AtmosLayer,
  31. show_marker: bool,
  32. show_atmos: bool,
  33. last_draw_type: DrawType,
  34. }
  35. #[derive(Debug, Eq, PartialEq)]
  36. enum DrawType {
  37. Null,
  38. Tiles,
  39. Markers,
  40. OrthoTiles,
  41. Atmos,
  42. }
  43. impl MapViewGl {
  44. pub fn new<F>(
  45. cx: &mut Context,
  46. initial_size: (u32, u32),
  47. dpi_factor: f64,
  48. update_func: F,
  49. use_network: bool,
  50. use_async: bool,
  51. ) -> MapViewGl
  52. where F: Fn() + Sync + Send + 'static,
  53. {
  54. let tile_size = 256;
  55. let proj_view = ProjectionView::Mercator(
  56. MercatorView::initial_view(
  57. f64::from(initial_size.0),
  58. f64::from(initial_size.1),
  59. tile_size,
  60. )
  61. );
  62. let atlas_size = {
  63. let default_size = 2048;
  64. let max_size = cx.max_texture_size() as u32;
  65. if default_size <= max_size {
  66. default_size
  67. } else {
  68. if tile_size * 3 > max_size {
  69. error!("maximal tile size ({}) is too small", max_size);
  70. }
  71. max_size
  72. }
  73. };
  74. let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
  75. check_gl_errors!(cx);
  76. let tile_atlas = TileAtlas::new(cx, atlas_tex, tile_size, use_async);
  77. let mercator_tile_layer = MercatorTileLayer::new(cx, &tile_atlas);
  78. let ortho_tile_layer = OrthoTileLayer::new(cx, &tile_atlas);
  79. let atmos_layer = AtmosLayer::new(cx);
  80. MapViewGl {
  81. proj_view,
  82. viewport_size: initial_size,
  83. dpi_factor,
  84. tile_cache: TileCache::new(move |_tile| update_func(), use_network),
  85. tile_atlas,
  86. mercator_tile_layer,
  87. marker_layer: MarkerLayer::new(cx),
  88. ortho_tile_layer,
  89. atmos_layer,
  90. show_marker: true,
  91. show_atmos: false,
  92. last_draw_type: DrawType::Null,
  93. }
  94. }
  95. pub fn set_viewport_size(&mut self, cx: &mut Context, width: u32, height: u32) {
  96. self.viewport_size = (width, height);
  97. let vec_size = vec2(f64::from(width), f64::from(height));
  98. match &mut self.proj_view {
  99. ProjectionView::Mercator(merc) => merc.viewport_size = vec_size,
  100. ProjectionView::Orthografic(ortho) => ortho.viewport_size = vec_size,
  101. }
  102. cx.set_viewport(0, 0, width, height);
  103. }
  104. pub fn set_dpi_factor(&mut self, dpi_factor: f64) {
  105. self.dpi_factor = dpi_factor;
  106. }
  107. pub fn add_marker(&mut self, map_coord: MapCoord) {
  108. self.marker_layer.add_marker(map_coord);
  109. }
  110. pub fn map_covers_viewport(&self) -> bool {
  111. match &self.proj_view {
  112. ProjectionView::Mercator(ref merc) => merc.covers_viewport(),
  113. ProjectionView::Orthografic(ref ortho) => ortho.covers_viewport(),
  114. }
  115. }
  116. pub fn increase_atlas_size(&mut self, cx: &mut Context) -> Result<(), ()> {
  117. self.tile_atlas.double_texture_size(cx)
  118. }
  119. pub fn toggle_projection(&mut self) {
  120. self.proj_view = match &self.proj_view {
  121. ProjectionView::Orthografic(ortho) =>
  122. ProjectionView::Mercator(MercatorView::from_orthografic_view(ortho)),
  123. ProjectionView::Mercator(merc) =>
  124. ProjectionView::Orthografic(OrthograficView::from_mercator_view(merc)),
  125. };
  126. }
  127. pub fn toggle_marker(&mut self) {
  128. self.show_marker = !self.show_marker;
  129. }
  130. pub fn toggle_atmosphere(&mut self) {
  131. self.show_atmos = !self.show_atmos;
  132. }
  133. fn draw_mercator_tiles(&mut self, cx: &mut Context, merc: &MercatorView, source: &TileSource, snap_to_pixel: bool)
  134. -> Result<usize, usize>
  135. {
  136. if self.last_draw_type != DrawType::Tiles {
  137. self.last_draw_type = DrawType::Tiles;
  138. self.mercator_tile_layer.prepare_draw(cx, &self.tile_atlas);
  139. }
  140. self.mercator_tile_layer.draw(
  141. cx,
  142. merc,
  143. source,
  144. &mut self.tile_cache,
  145. &mut self.tile_atlas,
  146. snap_to_pixel
  147. )
  148. }
  149. fn draw_mercator_marker(&mut self, cx: &mut Context, merc: &MercatorView, snap_to_pixel: bool) {
  150. if self.last_draw_type != DrawType::Markers {
  151. self.last_draw_type = DrawType::Markers;
  152. self.marker_layer.prepare_draw(cx);
  153. }
  154. self.marker_layer.draw_mercator(
  155. cx,
  156. merc,
  157. self.dpi_factor,
  158. snap_to_pixel,
  159. );
  160. }
  161. fn draw_ortho_marker(&mut self, cx: &mut Context, ortho: &OrthograficView) {
  162. if self.last_draw_type != DrawType::Markers {
  163. self.last_draw_type = DrawType::Markers;
  164. self.marker_layer.prepare_draw(cx);
  165. }
  166. self.marker_layer.draw_ortho(
  167. cx,
  168. ortho,
  169. self.dpi_factor,
  170. );
  171. }
  172. fn draw_ortho_tiles(&mut self, cx: &mut Context, ortho: &OrthograficView, source: &TileSource) -> Result<usize, usize> {
  173. if self.last_draw_type != DrawType::OrthoTiles {
  174. self.last_draw_type = DrawType::OrthoTiles;
  175. self.ortho_tile_layer.prepare_draw(cx, &self.tile_atlas);
  176. }
  177. self.ortho_tile_layer.draw(
  178. cx,
  179. ortho,
  180. source,
  181. &mut self.tile_cache,
  182. &mut self.tile_atlas,
  183. )
  184. }
  185. fn draw_atmos(&mut self, cx: &mut Context, ortho: &OrthograficView) {
  186. if self.last_draw_type != DrawType::Atmos {
  187. self.last_draw_type = DrawType::Atmos;
  188. self.atmos_layer.prepare_draw(cx);
  189. }
  190. self.atmos_layer.draw(
  191. cx,
  192. ortho,
  193. )
  194. }
  195. /// Returns `Err` when tile cache is too small for this view.
  196. /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
  197. /// size of the tile atlas.
  198. pub fn draw(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
  199. match self.proj_view.clone() {
  200. ProjectionView::Mercator(ref merc) => {
  201. // only snap to pixel grid if zoom has integral value
  202. let snap_to_pixel = (merc.zoom - (merc.zoom + 0.5).floor()).abs() < 1e-10;
  203. let ret = self.draw_mercator_tiles(cx, merc, source, snap_to_pixel);
  204. if self.show_marker && !self.marker_layer.is_empty() {
  205. self.draw_mercator_marker(cx, merc, snap_to_pixel);
  206. }
  207. ret
  208. },
  209. ProjectionView::Orthografic(ref ortho) => {
  210. let ret = self.draw_ortho_tiles(cx, ortho, source);
  211. if self.show_marker && !self.marker_layer.is_empty() {
  212. self.draw_ortho_marker(cx, ortho);
  213. }
  214. if self.show_atmos {
  215. self.draw_atmos(cx, ortho);
  216. }
  217. ret
  218. },
  219. }
  220. }
  221. pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
  222. match &mut self.proj_view {
  223. ProjectionView::Mercator(merc) => {
  224. merc.step_zoom(steps, step_size);
  225. },
  226. ProjectionView::Orthografic(ortho) => {
  227. ortho.step_zoom(steps, step_size);
  228. },
  229. }
  230. }
  231. pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
  232. match &mut self.proj_view {
  233. ProjectionView::Mercator(merc) => {
  234. merc.zoom_at(pos, zoom_delta)
  235. },
  236. ProjectionView::Orthografic(ortho) => {
  237. ortho.zoom_at(pos, zoom_delta)
  238. },
  239. }
  240. }
  241. pub fn change_tile_zoom_offset(&mut self, delta_offset: f64) {
  242. match &mut self.proj_view {
  243. ProjectionView::Mercator(merc) => {
  244. merc.tile_zoom_offset = (merc.tile_zoom_offset + delta_offset)
  245. .max(MIN_TILE_ZOOM_OFFSET)
  246. .min(MAX_TILE_ZOOM_OFFSET);
  247. },
  248. ProjectionView::Orthografic(ortho) => {
  249. ortho.tile_zoom_offset = (ortho.tile_zoom_offset + delta_offset)
  250. .max(MIN_TILE_ZOOM_OFFSET)
  251. .min(MAX_TILE_ZOOM_OFFSET);
  252. },
  253. }
  254. }
  255. //TODO Make sure to use physical pixel deltas
  256. pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
  257. match &mut self.proj_view {
  258. ProjectionView::Mercator(merc) => {
  259. merc.move_pixel(delta_x, delta_y);
  260. },
  261. ProjectionView::Orthografic(ortho) => {
  262. ortho.move_pixel(delta_x, delta_y);
  263. },
  264. }
  265. }
  266. pub fn restore_session(&mut self, session: &Session) -> Result<(), String> {
  267. let viewport_size = self.proj_view.viewport_size();
  268. let tile_size = self.proj_view.tile_size();
  269. match session.projection() {
  270. Some(Projection::Mercator) => {
  271. self.proj_view = ProjectionView::Mercator(
  272. MercatorView::from_toml_table(&session.view, viewport_size, tile_size)?
  273. )
  274. },
  275. Some(Projection::Orthografic) => {
  276. self.proj_view = ProjectionView::Orthografic(
  277. OrthograficView::from_toml_table(&session.view, viewport_size, tile_size)?
  278. )
  279. },
  280. None => {},
  281. }
  282. Ok(())
  283. }
  284. pub fn to_session(&self) -> Session {
  285. let view = match &self.proj_view {
  286. ProjectionView::Mercator(merc) => {
  287. merc.toml_table()
  288. },
  289. ProjectionView::Orthografic(ortho) => {
  290. ortho.toml_table()
  291. },
  292. };
  293. Session {
  294. view,
  295. }
  296. }
  297. }