Browse Source

Improve tile rendering in orthografic view

* Reach feature parity with mercator view:
  * Resize tile atlas to reduce draw calls
  * Fill in tiles from other zoom layers
Johannes Hofmann 7 years ago
parent
commit
7d5997991a
6 changed files with 254 additions and 108 deletions
  1. 6
    10
      src/map_view_gl.rs
  2. 2
    3
      src/mercator_tile_layer.rs
  3. 9
    1
      src/mercator_view.rs
  4. 100
    69
      src/ortho_tile_layer.rs
  5. 31
    10
      src/orthografic_view.rs
  6. 106
    15
      src/tile_atlas.rs

+ 6
- 10
src/map_view_gl.rs View File

86
         let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
86
         let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
87
         check_gl_errors!(cx);
87
         check_gl_errors!(cx);
88
 
88
 
89
-        let mut tile_atlas = TileAtlas::new(cx, atlas_tex, tile_size, use_async);
90
-        //TODO remove this
91
-        tile_atlas.double_texture_size(cx);
92
-        tile_atlas.double_texture_size(cx);
93
-        tile_atlas.double_texture_size(cx);
89
+        let tile_atlas = TileAtlas::new(cx, atlas_tex, tile_size, use_async);
94
 
90
 
95
         let mercator_tile_layer = MercatorTileLayer::new(cx, &tile_atlas);
91
         let mercator_tile_layer = MercatorTileLayer::new(cx, &tile_atlas);
92
+        let ortho_tile_layer = OrthoTileLayer::new(cx, &tile_atlas);
96
 
93
 
97
         MapViewGl {
94
         MapViewGl {
98
             map_view,
95
             map_view,
102
             tile_atlas,
99
             tile_atlas,
103
             mercator_tile_layer,
100
             mercator_tile_layer,
104
             marker_layer: MarkerLayer::new(cx),
101
             marker_layer: MarkerLayer::new(cx),
105
-            ortho_tile_layer: OrthoTileLayer::new(cx),
102
+            ortho_tile_layer,
106
             projection: Projection::Mercator,
103
             projection: Projection::Mercator,
107
             last_draw_type: DrawType::Null,
104
             last_draw_type: DrawType::Null,
108
         }
105
         }
178
         );
175
         );
179
     }
176
     }
180
 
177
 
181
-    fn draw_ortho_tiles(&mut self, cx: &mut Context, source: &TileSource) {
178
+    fn draw_ortho_tiles(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
182
         if self.last_draw_type != DrawType::OrthoTiles {
179
         if self.last_draw_type != DrawType::OrthoTiles {
183
             self.last_draw_type = DrawType::OrthoTiles;
180
             self.last_draw_type = DrawType::OrthoTiles;
184
             self.ortho_tile_layer.prepare_draw(cx, &self.tile_atlas);
181
             self.ortho_tile_layer.prepare_draw(cx, &self.tile_atlas);
190
             source,
187
             source,
191
             &mut self.tile_cache,
188
             &mut self.tile_cache,
192
             &mut self.tile_atlas,
189
             &mut self.tile_atlas,
193
-        );
190
+        )
194
     }
191
     }
195
 
192
 
196
     /// Returns `Err` when tile cache is too small for this view.
193
     /// Returns `Err` when tile cache is too small for this view.
209
                 ret
206
                 ret
210
             },
207
             },
211
             Projection::Orthografic => {
208
             Projection::Orthografic => {
212
-                self.draw_ortho_tiles(cx, source);
213
-                Ok(1)
209
+                self.draw_ortho_tiles(cx, source)
214
             },
210
             },
215
         }
211
         }
216
     }
212
     }

+ 2
- 3
src/mercator_tile_layer.rs View File

33
             include_bytes!("../shader/map.vert"),
33
             include_bytes!("../shader/map.vert"),
34
             include_bytes!("../shader/map.frag"),
34
             include_bytes!("../shader/map.frag"),
35
         ).unwrap();
35
         ).unwrap();
36
-        check_gl_errors!(cx);
37
 
36
 
38
         program.add_texture(cx, atlas.texture(), CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
37
         program.add_texture(cx, atlas.texture(), CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
39
-        check_gl_errors!(cx);
40
 
38
 
41
         program.add_attribute(
39
         program.add_attribute(
42
             cx,
40
             cx,
53
             CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
51
             CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
54
             &VertexAttribParams::new(4, 8, 4)
52
             &VertexAttribParams::new(4, 8, 4)
55
         );
53
         );
54
+
56
         check_gl_errors!(cx);
55
         check_gl_errors!(cx);
57
 
56
 
58
         MercatorTileLayer {
57
         MercatorTileLayer {
100
                 )
99
                 )
101
             };
100
             };
102
 
101
 
103
-            max_tiles_to_use -= used_tiles;
102
+            max_tiles_to_use = max_tiles_to_use.saturating_sub(used_tiles);
104
 
103
 
105
             let mut vertex_data: Vec<f32> = Vec::with_capacity(textured_visible_tiles.len() * (6 * 8));
104
             let mut vertex_data: Vec<f32> = Vec::with_capacity(textured_visible_tiles.len() * (6 * 8));
106
             let scale_x = 2.0 / f64::from(viewport_size.0);
105
             let scale_x = 2.0 / f64::from(viewport_size.0);

+ 9
- 1
src/mercator_view.rs View File

1
-use coord::{MapCoord, ScreenCoord, ScreenRect, TileCoord};
1
+use coord::{MapCoord, ScreenCoord, ScreenRect, TextureRect, TileCoord};
2
 use map_view::MapView;
2
 use map_view::MapView;
3
 
3
 
4
 
4
 
14
     pub rect: ScreenRect,
14
     pub rect: ScreenRect,
15
 }
15
 }
16
 
16
 
17
+#[derive(Clone, Debug)]
18
+pub struct TexturedVisibleTile {
19
+    pub screen_rect: ScreenRect,
20
+    pub tex_rect: TextureRect,
21
+    pub tex_minmax: TextureRect,
22
+}
23
+
24
+
17
 impl MercatorView {
25
 impl MercatorView {
18
     /// Constructs a `MapView` centered at Null Island with an integer zoom that fills a screen
26
     /// Constructs a `MapView` centered at Null Island with an integer zoom that fills a screen
19
     /// with the given dimensions.
27
     /// with the given dimensions.

+ 100
- 69
src/ortho_tile_layer.rs View File

1
 use buffer::{Buffer, DrawMode};
1
 use buffer::{Buffer, DrawMode};
2
 use cgmath::Transform;
2
 use cgmath::Transform;
3
 use context::Context;
3
 use context::Context;
4
-use coord::{LatLonRad, ScreenCoord, TileCoord, View};
4
+use coord::{LatLonRad, ScreenCoord, View};
5
 use map_view::MapView;
5
 use map_view::MapView;
6
 use orthografic_view::OrthograficView;
6
 use orthografic_view::OrthograficView;
7
 use program::Program;
7
 use program::Program;
8
 use std::ffi::CStr;
8
 use std::ffi::CStr;
9
-use tile_atlas::TileAtlas;
9
+use tile_atlas::{TileAtlas, VisibleTilesProvider};
10
 use tile_cache::TileCache;
10
 use tile_cache::TileCache;
11
 use tile_source::TileSource;
11
 use tile_source::TileSource;
12
 use vertex_attrib::VertexAttribParams;
12
 use vertex_attrib::VertexAttribParams;
45
 impl OrthoTileLayer {
45
 impl OrthoTileLayer {
46
     pub fn new(
46
     pub fn new(
47
         cx: &mut Context,
47
         cx: &mut Context,
48
+        atlas: &TileAtlas,
48
     ) -> OrthoTileLayer
49
     ) -> OrthoTileLayer
49
     {
50
     {
50
         let buffer = Buffer::new(cx, &[], 0);
51
         let buffer = Buffer::new(cx, &[], 0);
51
-        check_gl_errors!(cx);
52
         cx.bind_buffer(buffer.id());
52
         cx.bind_buffer(buffer.id());
53
 
53
 
54
         let mut program = Program::new(
54
         let mut program = Program::new(
56
             include_bytes!("../shader/ortho_tile.vert"),
56
             include_bytes!("../shader/ortho_tile.vert"),
57
             include_bytes!("../shader/ortho_tile.frag"),
57
             include_bytes!("../shader/ortho_tile.frag"),
58
         ).unwrap();
58
         ).unwrap();
59
-        check_gl_errors!(cx);
59
+
60
+        program.add_texture(cx, atlas.texture(), CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
60
 
61
 
61
         program.add_attribute(
62
         program.add_attribute(
62
             cx,
63
             cx,
73
             CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
74
             CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
74
             &VertexAttribParams::new(4, 9, 5)
75
             &VertexAttribParams::new(4, 9, 5)
75
         );
76
         );
77
+
76
         check_gl_errors!(cx);
78
         check_gl_errors!(cx);
77
 
79
 
78
         OrthoTileLayer {
80
         OrthoTileLayer {
95
         source: &TileSource,
97
         source: &TileSource,
96
         cache: &mut TileCache,
98
         cache: &mut TileCache,
97
         tile_atlas: &mut TileAtlas,
99
         tile_atlas: &mut TileAtlas,
98
-    ) {
100
+    ) -> Result<usize, usize> {
99
         //TODO Add distance function to TileCache that takes topology of the sphere into account.
101
         //TODO Add distance function to TileCache that takes topology of the sphere into account.
100
         cache.set_view_location(View {
102
         cache.set_view_location(View {
101
             source_id: source.id(),
103
             source_id: source.id(),
103
             center: map_view.center,
105
             center: map_view.center,
104
         });
106
         });
105
 
107
 
106
-        let mut vertex_data = vec![];
107
-
108
         let transform = OrthograficView::transformation_matrix(map_view);
108
         let transform = OrthograficView::transformation_matrix(map_view);
109
 
109
 
110
-        let (inset_x, inset_y) = tile_atlas.texture_margins();
111
-
112
-        for tile_coord in OrthograficView::visible_tiles(map_view).into_iter() {
113
-            let slot = tile_atlas.store(cx, tile_coord, source, cache, true)
114
-                .unwrap_or_else(TileAtlas::default_slot);
115
-            let texrect = tile_atlas.slot_to_texture_rect(slot);
116
-            let tex_minmax = texrect.inset(inset_x, inset_y);
117
-
118
-            let minmax = [
119
-                tex_minmax.x1 as f32,
120
-                tex_minmax.y1 as f32,
121
-                tex_minmax.x2 as f32,
122
-                tex_minmax.y2 as f32,
123
-            ];
124
-
125
-            let subdivision = 6u32.saturating_sub(tile_coord.zoom).max(2);
126
-
127
-            for (tc, sub_tile) in tile_coord.children_iter(subdivision) {
128
-                let ll_nw = tc.latlon_rad_north_west();
129
-                let ll_se = {
130
-                    let tc = TileCoord::new(tc.zoom, tc.x + 1, tc.y + 1);
131
-                    tc.latlon_rad_north_west()
132
-                };
133
-
134
-                let ll_ne = LatLonRad::new(ll_nw.lat, ll_se.lon);
135
-                let ll_sw = LatLonRad::new(ll_se.lat, ll_nw.lon);
136
-
137
-                let p1 = ll_nw.to_sphere_point3();
138
-                let p2 = ll_ne.to_sphere_point3();
139
-                let p3 = ll_se.to_sphere_point3();
140
-                let p4 = ll_sw.to_sphere_point3();
141
-
142
-                let p1 = transform.transform_point(p1);
143
-                let p2 = transform.transform_point(p2);
144
-                let p3 = transform.transform_point(p3);
145
-                let p4 = transform.transform_point(p4);
146
-
147
-                // Discard tiles that are facing backwards
148
-                if (p1.z + p3.z) * 0.5 > 0.0 {
149
-                    continue;
110
+        let visible_tiles = OrthograficView::visible_tiles(map_view);
111
+        let mut remainder = visible_tiles.as_slice();
112
+        let mut num_draws = 0;
113
+        let mut max_tiles_to_use = cache.max_tiles();
114
+
115
+        loop {
116
+            let (textured_visible_tiles, remainder_opt, used_tiles) = {
117
+                tile_atlas.textured_visible_tiles(
118
+                    cx,
119
+                    remainder,
120
+                    max_tiles_to_use,
121
+                    source,
122
+                    cache,
123
+                )
124
+            };
125
+
126
+            max_tiles_to_use = max_tiles_to_use.saturating_sub(used_tiles);
127
+
128
+            // A low guess for the capacity
129
+            let mut vertex_data = Vec::with_capacity(textured_visible_tiles.len() * 9 * 16);
130
+
131
+            for tvt in &textured_visible_tiles {
132
+                let minmax = [
133
+                    tvt.tex_minmax.x1 as f32,
134
+                    tvt.tex_minmax.y1 as f32,
135
+                    tvt.tex_minmax.x2 as f32,
136
+                    tvt.tex_minmax.y2 as f32,
137
+                ];
138
+
139
+                let subdivision = 6u32.saturating_sub(tvt.tile_coord.zoom).max(2);
140
+
141
+                for (tc, sub_tile) in tvt.tile_coord.children_iter(subdivision) {
142
+                    let ll_nw = tc.latlon_rad_north_west();
143
+                    let ll_se = tc.latlon_rad_south_east();
144
+                    let ll_ne = LatLonRad::new(ll_nw.lat, ll_se.lon);
145
+                    let ll_sw = LatLonRad::new(ll_se.lat, ll_nw.lon);
146
+
147
+                    let p1 = transform.transform_point(ll_nw.to_sphere_point3());
148
+                    let p2 = transform.transform_point(ll_ne.to_sphere_point3());
149
+                    let p3 = transform.transform_point(ll_se.to_sphere_point3());
150
+                    let p4 = transform.transform_point(ll_sw.to_sphere_point3());
151
+
152
+                    // Discard tiles/subtiles that are facing backwards
153
+                    if (p1.z + p3.z) * 0.5 > 0.0 {
154
+                        continue;
155
+                    }
156
+
157
+                    let texrect = tvt.tex_rect.subdivide(&sub_tile);
158
+
159
+                    let p1 = [p1.x as f32, p1.y as f32, p1.z as f32, texrect.x1 as f32, texrect.y1 as f32];
160
+                    let p2 = [p2.x as f32, p2.y as f32, p2.z as f32, texrect.x2 as f32, texrect.y1 as f32];
161
+                    let p3 = [p3.x as f32, p3.y as f32, p3.z as f32, texrect.x2 as f32, texrect.y2 as f32];
162
+                    let p4 = [p4.x as f32, p4.y as f32, p4.z as f32, texrect.x1 as f32, texrect.y2 as f32];
163
+
164
+                    vertex_data.extend(&p1);
165
+                    vertex_data.extend(&minmax);
166
+                    vertex_data.extend(&p2);
167
+                    vertex_data.extend(&minmax);
168
+                    vertex_data.extend(&p3);
169
+                    vertex_data.extend(&minmax);
170
+                    vertex_data.extend(&p1);
171
+                    vertex_data.extend(&minmax);
172
+                    vertex_data.extend(&p3);
173
+                    vertex_data.extend(&minmax);
174
+                    vertex_data.extend(&p4);
175
+                    vertex_data.extend(&minmax);
150
                 }
176
                 }
177
+            }
151
 
178
 
152
-                let texrect = texrect.subdivide(&sub_tile);
153
-
154
-                let p1 = [p1.x as f32, p1.y as f32, p1.z as f32, texrect.x1 as f32, texrect.y1 as f32];
155
-                let p2 = [p2.x as f32, p2.y as f32, p2.z as f32, texrect.x2 as f32, texrect.y1 as f32];
156
-                let p3 = [p3.x as f32, p3.y as f32, p3.z as f32, texrect.x2 as f32, texrect.y2 as f32];
157
-                let p4 = [p4.x as f32, p4.y as f32, p4.z as f32, texrect.x1 as f32, texrect.y2 as f32];
158
-
159
-                vertex_data.extend(&p1);
160
-                vertex_data.extend(&minmax);
161
-                vertex_data.extend(&p2);
162
-                vertex_data.extend(&minmax);
163
-                vertex_data.extend(&p3);
164
-                vertex_data.extend(&minmax);
165
-                vertex_data.extend(&p1);
166
-                vertex_data.extend(&minmax);
167
-                vertex_data.extend(&p3);
168
-                vertex_data.extend(&minmax);
169
-                vertex_data.extend(&p4);
170
-                vertex_data.extend(&minmax);
179
+            self.buffer.set_data(cx, &vertex_data, vertex_data.len() / 4);
180
+            self.buffer.draw(cx, &self.program, DrawMode::Triangles);
181
+
182
+            num_draws += 1;
183
+
184
+            debug!("draw #{}: tvt.len() = {}, remainder = {:?}, max_tiles = {}",
185
+                num_draws,
186
+                textured_visible_tiles.len(),
187
+                remainder_opt.map(|r| r.len()),
188
+                max_tiles_to_use);
189
+
190
+            if max_tiles_to_use == 0 {
191
+                warn!("tile cache is too small for this view.");
192
+                return Err(num_draws);
171
             }
193
             }
172
-        }
173
 
194
 
174
-        self.buffer.set_data(cx, &vertex_data, vertex_data.len() / 4);
175
-        self.buffer.draw(cx, &self.program, DrawMode::Triangles);
195
+            match remainder_opt {
196
+                None => return Ok(num_draws),
197
+                Some(new_remainder) => {
198
+                    if new_remainder.len() >= remainder.len() {
199
+                        warn!("failed to draw all tiles. number of remaining tiles did not decrease.");
200
+                        return Err(num_draws);
201
+                    } else {
202
+                        remainder = new_remainder;
203
+                    }
204
+                },
205
+            }
206
+        }
176
     }
207
     }
177
 }
208
 }

+ 31
- 10
src/orthografic_view.rs View File

1
 use cgmath::{Matrix3, Point3, Transform, vec3};
1
 use cgmath::{Matrix3, Point3, Transform, vec3};
2
-use coord::{LatLonRad, TileCoord};
2
+use coord::{LatLonRad, TextureRect, TileCoord};
3
 use map_view::MapView;
3
 use map_view::MapView;
4
 use std::collections::HashSet;
4
 use std::collections::HashSet;
5
 use std::f32::consts::{PI, FRAC_1_PI};
5
 use std::f32::consts::{PI, FRAC_1_PI};
6
 use std::f64;
6
 use std::f64;
7
 
7
 
8
 
8
 
9
+#[derive(Clone, Debug)]
10
+pub struct VisibleTile {
11
+    pub tile: TileCoord,
12
+}
13
+
14
+impl From<TileCoord> for VisibleTile {
15
+    fn from(tc: TileCoord) -> Self {
16
+        VisibleTile {
17
+            tile: tc,
18
+        }
19
+    }
20
+}
21
+
22
+#[derive(Clone, Debug)]
23
+pub struct TexturedVisibleTile {
24
+    pub tile_coord: TileCoord,
25
+    pub tex_rect: TextureRect,
26
+    pub tex_minmax: TextureRect,
27
+}
28
+
29
+
9
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
30
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
10
 pub enum TileNeighbor {
31
 pub enum TileNeighbor {
11
     Coord(TileCoord),
32
     Coord(TileCoord),
118
 
139
 
119
     //TODO Return the transformation matrix that is used here to avoid redundant calculation.
140
     //TODO Return the transformation matrix that is used here to avoid redundant calculation.
120
     /// Returns a `Vec` of all tiles that are visible in the current viewport.
141
     /// Returns a `Vec` of all tiles that are visible in the current viewport.
121
-    pub fn visible_tiles(map_view: &MapView) -> Vec<TileCoord> {
142
+    pub fn visible_tiles(map_view: &MapView) -> Vec<VisibleTile> {
122
         let uzoom = Self::tile_zoom(map_view);
143
         let uzoom = Self::tile_zoom(map_view);
123
 
144
 
124
         match uzoom {
145
         match uzoom {
125
-            0 => return vec![TileCoord::new(0, 0, 0)],
146
+            0 => return vec![TileCoord::new(0, 0, 0).into()],
126
             1 => {
147
             1 => {
127
                 // return every tile
148
                 // return every tile
128
                 return vec![
149
                 return vec![
129
-                    TileCoord::new(1, 0, 0),
130
-                    TileCoord::new(1, 0, 1),
131
-                    TileCoord::new(1, 1, 0),
132
-                    TileCoord::new(1, 1, 1),
150
+                    TileCoord::new(1, 0, 0).into(),
151
+                    TileCoord::new(1, 0, 1).into(),
152
+                    TileCoord::new(1, 1, 0).into(),
153
+                    TileCoord::new(1, 1, 1).into(),
133
                 ]},
154
                 ]},
134
             _ => {},
155
             _ => {},
135
         }
156
         }
160
             }
181
             }
161
         };
182
         };
162
 
183
 
163
-        let mut tiles = vec![center_tile];
184
+        let mut tiles = vec![center_tile.into()];
164
 
185
 
165
         let mut stack: Vec<TileNeighbor> = vec![];
186
         let mut stack: Vec<TileNeighbor> = vec![];
166
         tile_neighbors(center_tile, &mut stack);
187
         tile_neighbors(center_tile, &mut stack);
169
         visited.insert(TileNeighbor::Coord(center_tile));
190
         visited.insert(TileNeighbor::Coord(center_tile));
170
         visited.extend(stack.iter());
191
         visited.extend(stack.iter());
171
 
192
 
172
-        let mut neighbors = vec![];
193
+        let mut neighbors = Vec::with_capacity(4);
173
 
194
 
174
         loop {
195
         loop {
175
             if let Some(tn) = stack.pop() {
196
             if let Some(tn) = stack.pop() {
176
                 match tn {
197
                 match tn {
177
                     TileNeighbor::Coord(tc) => {
198
                     TileNeighbor::Coord(tc) => {
178
                         if tile_is_visible(tc) {
199
                         if tile_is_visible(tc) {
179
-                            tiles.push(tc);
200
+                            tiles.push(tc.into());
180
                             tile_neighbors(tc, &mut neighbors);
201
                             tile_neighbors(tc, &mut neighbors);
181
                             for tn in &neighbors {
202
                             for tn in &neighbors {
182
                                 if !visited.contains(tn) {
203
                                 if !visited.contains(tn) {

+ 106
- 15
src/tile_atlas.rs View File

1
 use context::Context;
1
 use context::Context;
2
-use coord::{ScreenRect, SubTileCoord, TileCoord, TextureRect};
2
+use coord::{SubTileCoord, TileCoord, TextureRect};
3
 use image;
3
 use image;
4
 use linked_hash_map::LinkedHashMap;
4
 use linked_hash_map::LinkedHashMap;
5
 use mercator_view;
5
 use mercator_view;
6
+use orthografic_view;
6
 use std::collections::HashMap;
7
 use std::collections::HashMap;
7
 use std::collections::hash_map::Entry;
8
 use std::collections::hash_map::Entry;
8
 use texture::Texture;
9
 use texture::Texture;
10
 use tile_cache::TileCache;
11
 use tile_cache::TileCache;
11
 use tile_source::TileSource;
12
 use tile_source::TileSource;
12
 
13
 
13
-#[derive(Clone, Debug)]
14
-pub struct TexturedVisibleTile {
15
-    pub screen_rect: ScreenRect,
16
-    pub tex_rect: TextureRect,
17
-    pub tex_minmax: TextureRect,
18
-}
19
 
14
 
20
 #[derive(Clone, Debug)]
15
 #[derive(Clone, Debug)]
21
 pub struct TileAtlas {
16
 pub struct TileAtlas {
190
     pub y: u32,
185
     pub y: u32,
191
 }
186
 }
192
 
187
 
193
-pub trait VisibleTilesProvider<T> {
188
+/// U: Untextured Visible tile type
189
+/// T: Textured visible tile type
190
+pub trait VisibleTilesProvider<U, T> {
194
     /// Finds textures from the cache for a given slice of visible tiles. The texture atlas may not
191
     /// Finds textures from the cache for a given slice of visible tiles. The texture atlas may not
195
     /// be big enough to hold all textures at once; a possible remainder of untextured visible
192
     /// be big enough to hold all textures at once; a possible remainder of untextured visible
196
     /// tiles is returned as an `Option`.
193
     /// tiles is returned as an `Option`.
199
     fn textured_visible_tiles<'b>(
196
     fn textured_visible_tiles<'b>(
200
         &mut self,
197
         &mut self,
201
         cx: &mut Context,
198
         cx: &mut Context,
202
-        visible_tiles: &'b [T],
199
+        visible_tiles: &'b [U],
203
         max_tiles_to_use: usize,
200
         max_tiles_to_use: usize,
204
         source: &TileSource,
201
         source: &TileSource,
205
         cache: &mut TileCache,
202
         cache: &mut TileCache,
206
-    ) -> (Vec<TexturedVisibleTile>, Option<&'b [T]>, usize);
203
+    ) -> (Vec<T>, Option<&'b [U]>, usize);
207
 }
204
 }
208
 
205
 
209
-impl VisibleTilesProvider<mercator_view::VisibleTile> for TileAtlas {
206
+impl VisibleTilesProvider<mercator_view::VisibleTile, mercator_view::TexturedVisibleTile>
207
+for TileAtlas {
210
     fn textured_visible_tiles<'b>(
208
     fn textured_visible_tiles<'b>(
211
         &mut self,
209
         &mut self,
212
         cx: &mut Context,
210
         cx: &mut Context,
214
         max_tiles_to_use: usize,
212
         max_tiles_to_use: usize,
215
         source: &TileSource,
213
         source: &TileSource,
216
         cache: &mut TileCache,
214
         cache: &mut TileCache,
217
-        ) -> (Vec<TexturedVisibleTile>, Option<&'b [mercator_view::VisibleTile]>, usize)
215
+    ) -> (Vec<mercator_view::TexturedVisibleTile>, Option<&'b [mercator_view::VisibleTile]>, usize)
218
     {
216
     {
219
         let mut tvt = Vec::with_capacity(visible_tiles.len());
217
         let mut tvt = Vec::with_capacity(visible_tiles.len());
220
 
218
 
234
                 let tex_rect = self.slot_to_texture_rect(slot);
232
                 let tex_rect = self.slot_to_texture_rect(slot);
235
                 used_slots += 1;
233
                 used_slots += 1;
236
                 tvt.push(
234
                 tvt.push(
237
-                    TexturedVisibleTile {
235
+                    mercator_view::TexturedVisibleTile {
238
                         screen_rect: vt.rect,
236
                         screen_rect: vt.rect,
239
                         tex_rect,
237
                         tex_rect,
240
                         tex_minmax: tex_rect.inset(inset_x, inset_y),
238
                         tex_minmax: tex_rect.inset(inset_x, inset_y),
274
                         let tex_rect = self.slot_to_texture_rect(slot);
272
                         let tex_rect = self.slot_to_texture_rect(slot);
275
 
273
 
276
                         tvt.push(
274
                         tvt.push(
277
-                            TexturedVisibleTile {
275
+                            mercator_view::TexturedVisibleTile {
278
                                 screen_rect: vt.rect.subdivide(&child_sub_coord),
276
                                 screen_rect: vt.rect.subdivide(&child_sub_coord),
279
                                 tex_rect,
277
                                 tex_rect,
280
                                 tex_minmax: tex_rect.inset(inset_x, inset_y),
278
                                 tex_minmax: tex_rect.inset(inset_x, inset_y),
282
                         );
280
                         );
283
                     } else {
281
                     } else {
284
                         tvt.push(
282
                         tvt.push(
285
-                            TexturedVisibleTile {
283
+                            mercator_view::TexturedVisibleTile {
286
                                 screen_rect: vt.rect.subdivide(&child_sub_coord),
284
                                 screen_rect: vt.rect.subdivide(&child_sub_coord),
287
                                 tex_rect: tex_sub_rect.subdivide(&child_sub_coord),
285
                                 tex_rect: tex_sub_rect.subdivide(&child_sub_coord),
288
                                 tex_minmax: tex_rect.inset(inset_x, inset_y),
286
                                 tex_minmax: tex_rect.inset(inset_x, inset_y),
296
         (tvt, None, used_slots)
294
         (tvt, None, used_slots)
297
     }
295
     }
298
 }
296
 }
297
+
298
+impl VisibleTilesProvider<orthografic_view::VisibleTile, orthografic_view::TexturedVisibleTile>
299
+for TileAtlas {
300
+    fn textured_visible_tiles<'b>(
301
+        &mut self,
302
+        cx: &mut Context,
303
+        visible_tiles: &'b [orthografic_view::VisibleTile],
304
+        max_tiles_to_use: usize,
305
+        source: &TileSource,
306
+        cache: &mut TileCache,
307
+    ) -> (Vec<orthografic_view::TexturedVisibleTile>, Option<&'b [orthografic_view::VisibleTile]>,
308
+          usize)
309
+    {
310
+        let mut tvt = Vec::with_capacity(visible_tiles.len());
311
+
312
+        let (inset_x, inset_y) = self.texture_margins();
313
+
314
+        let num_usable_slots = self.slots_lru.len();
315
+        // The number of actually used slots may be lower, because slots can be used multiple times
316
+        // in the same view (especially the default slot).
317
+        let mut used_slots = 0_usize;
318
+
319
+        for (i, vt) in visible_tiles.iter().enumerate() {
320
+            if used_slots >= num_usable_slots || used_slots >= max_tiles_to_use {
321
+                return (tvt, Some(&visible_tiles[i..]), used_slots);
322
+            }
323
+
324
+            if let Some(slot) = self.store(cx, vt.tile, source, cache, true) {
325
+                let tex_rect = self.slot_to_texture_rect(slot);
326
+                used_slots += 1;
327
+                tvt.push(
328
+                    orthografic_view::TexturedVisibleTile {
329
+                        tile_coord: vt.tile,
330
+                        tex_rect,
331
+                        tex_minmax: tex_rect.inset(inset_x, inset_y),
332
+                    }
333
+                );
334
+            } else {
335
+                // exact tile not found
336
+
337
+                if used_slots + 5 > num_usable_slots || used_slots + 5 > max_tiles_to_use {
338
+                    return (tvt, Some(&visible_tiles[i..]), used_slots);
339
+                }
340
+
341
+                // default tile
342
+                let mut tex_sub_rect = self.slot_to_texture_rect(Self::default_slot());
343
+                let mut tex_rect = tex_sub_rect;
344
+
345
+                // look for cached tiles in lower zoom layers
346
+                for dist in 1..31 {
347
+                    if let Some((parent_tile, sub_coord)) = vt.tile.parent(dist) {
348
+                        if let Some(slot) = self.store(cx, parent_tile, source, cache, false) {
349
+                            used_slots += 1;
350
+                            tex_sub_rect = self.subslot_to_texture_rect(slot, sub_coord);
351
+                            tex_rect = self.slot_to_texture_rect(slot);
352
+                            break;
353
+                        }
354
+                    } else {
355
+                        break;
356
+                    }
357
+                }
358
+
359
+                // look for cached tiles in higher zoom layers
360
+                //TODO Just create one rect (instead of four) if there is no tile from a higher
361
+                // zoom level available
362
+                for (child_tile, child_sub_coord) in vt.tile.children_iter(1) {
363
+                    if let Some(slot) = self.store(cx, child_tile, source, cache, false) {
364
+                        used_slots += 1;
365
+                        let tex_rect = self.slot_to_texture_rect(slot);
366
+
367
+                        tvt.push(
368
+                            orthografic_view::TexturedVisibleTile {
369
+                                tile_coord: child_tile,
370
+                                tex_rect,
371
+                                tex_minmax: tex_rect.inset(inset_x, inset_y),
372
+                            }
373
+                        );
374
+                    } else {
375
+                        tvt.push(
376
+                            orthografic_view::TexturedVisibleTile {
377
+                                tile_coord: child_tile,
378
+                                tex_rect: tex_sub_rect.subdivide(&child_sub_coord),
379
+                                tex_minmax: tex_rect.inset(inset_x, inset_y),
380
+                            }
381
+                        );
382
+                    }
383
+                }
384
+            };
385
+        }
386
+
387
+        (tvt, None, used_slots)
388
+    }
389
+}