Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
7d5997991a

+ 6
- 10
src/map_view_gl.rs Dosyayı Görüntüle

@@ -86,13 +86,10 @@ impl MapViewGl {
86 86
         let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
87 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 91
         let mercator_tile_layer = MercatorTileLayer::new(cx, &tile_atlas);
92
+        let ortho_tile_layer = OrthoTileLayer::new(cx, &tile_atlas);
96 93
 
97 94
         MapViewGl {
98 95
             map_view,
@@ -102,7 +99,7 @@ impl MapViewGl {
102 99
             tile_atlas,
103 100
             mercator_tile_layer,
104 101
             marker_layer: MarkerLayer::new(cx),
105
-            ortho_tile_layer: OrthoTileLayer::new(cx),
102
+            ortho_tile_layer,
106 103
             projection: Projection::Mercator,
107 104
             last_draw_type: DrawType::Null,
108 105
         }
@@ -178,7 +175,7 @@ impl MapViewGl {
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 179
         if self.last_draw_type != DrawType::OrthoTiles {
183 180
             self.last_draw_type = DrawType::OrthoTiles;
184 181
             self.ortho_tile_layer.prepare_draw(cx, &self.tile_atlas);
@@ -190,7 +187,7 @@ impl MapViewGl {
190 187
             source,
191 188
             &mut self.tile_cache,
192 189
             &mut self.tile_atlas,
193
-        );
190
+        )
194 191
     }
195 192
 
196 193
     /// Returns `Err` when tile cache is too small for this view.
@@ -209,8 +206,7 @@ impl MapViewGl {
209 206
                 ret
210 207
             },
211 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 Dosyayı Görüntüle

@@ -33,10 +33,8 @@ impl MercatorTileLayer {
33 33
             include_bytes!("../shader/map.vert"),
34 34
             include_bytes!("../shader/map.frag"),
35 35
         ).unwrap();
36
-        check_gl_errors!(cx);
37 36
 
38 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 39
         program.add_attribute(
42 40
             cx,
@@ -53,6 +51,7 @@ impl MercatorTileLayer {
53 51
             CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
54 52
             &VertexAttribParams::new(4, 8, 4)
55 53
         );
54
+
56 55
         check_gl_errors!(cx);
57 56
 
58 57
         MercatorTileLayer {
@@ -100,7 +99,7 @@ impl 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 104
             let mut vertex_data: Vec<f32> = Vec::with_capacity(textured_visible_tiles.len() * (6 * 8));
106 105
             let scale_x = 2.0 / f64::from(viewport_size.0);

+ 9
- 1
src/mercator_view.rs Dosyayı Görüntüle

@@ -1,4 +1,4 @@
1
-use coord::{MapCoord, ScreenCoord, ScreenRect, TileCoord};
1
+use coord::{MapCoord, ScreenCoord, ScreenRect, TextureRect, TileCoord};
2 2
 use map_view::MapView;
3 3
 
4 4
 
@@ -14,6 +14,14 @@ pub struct VisibleTile {
14 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 25
 impl MercatorView {
18 26
     /// Constructs a `MapView` centered at Null Island with an integer zoom that fills a screen
19 27
     /// with the given dimensions.

+ 100
- 69
src/ortho_tile_layer.rs Dosyayı Görüntüle

@@ -1,12 +1,12 @@
1 1
 use buffer::{Buffer, DrawMode};
2 2
 use cgmath::Transform;
3 3
 use context::Context;
4
-use coord::{LatLonRad, ScreenCoord, TileCoord, View};
4
+use coord::{LatLonRad, ScreenCoord, View};
5 5
 use map_view::MapView;
6 6
 use orthografic_view::OrthograficView;
7 7
 use program::Program;
8 8
 use std::ffi::CStr;
9
-use tile_atlas::TileAtlas;
9
+use tile_atlas::{TileAtlas, VisibleTilesProvider};
10 10
 use tile_cache::TileCache;
11 11
 use tile_source::TileSource;
12 12
 use vertex_attrib::VertexAttribParams;
@@ -45,10 +45,10 @@ impl LatScreenEllipse {
45 45
 impl OrthoTileLayer {
46 46
     pub fn new(
47 47
         cx: &mut Context,
48
+        atlas: &TileAtlas,
48 49
     ) -> OrthoTileLayer
49 50
     {
50 51
         let buffer = Buffer::new(cx, &[], 0);
51
-        check_gl_errors!(cx);
52 52
         cx.bind_buffer(buffer.id());
53 53
 
54 54
         let mut program = Program::new(
@@ -56,7 +56,8 @@ impl OrthoTileLayer {
56 56
             include_bytes!("../shader/ortho_tile.vert"),
57 57
             include_bytes!("../shader/ortho_tile.frag"),
58 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 62
         program.add_attribute(
62 63
             cx,
@@ -73,6 +74,7 @@ impl OrthoTileLayer {
73 74
             CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
74 75
             &VertexAttribParams::new(4, 9, 5)
75 76
         );
77
+
76 78
         check_gl_errors!(cx);
77 79
 
78 80
         OrthoTileLayer {
@@ -95,7 +97,7 @@ impl OrthoTileLayer {
95 97
         source: &TileSource,
96 98
         cache: &mut TileCache,
97 99
         tile_atlas: &mut TileAtlas,
98
-    ) {
100
+    ) -> Result<usize, usize> {
99 101
         //TODO Add distance function to TileCache that takes topology of the sphere into account.
100 102
         cache.set_view_location(View {
101 103
             source_id: source.id(),
@@ -103,75 +105,104 @@ impl OrthoTileLayer {
103 105
             center: map_view.center,
104 106
         });
105 107
 
106
-        let mut vertex_data = vec![];
107
-
108 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 Dosyayı Görüntüle

@@ -1,11 +1,32 @@
1 1
 use cgmath::{Matrix3, Point3, Transform, vec3};
2
-use coord::{LatLonRad, TileCoord};
2
+use coord::{LatLonRad, TextureRect, TileCoord};
3 3
 use map_view::MapView;
4 4
 use std::collections::HashSet;
5 5
 use std::f32::consts::{PI, FRAC_1_PI};
6 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 30
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
10 31
 pub enum TileNeighbor {
11 32
     Coord(TileCoord),
@@ -118,18 +139,18 @@ impl OrthograficView {
118 139
 
119 140
     //TODO Return the transformation matrix that is used here to avoid redundant calculation.
120 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 143
         let uzoom = Self::tile_zoom(map_view);
123 144
 
124 145
         match uzoom {
125
-            0 => return vec![TileCoord::new(0, 0, 0)],
146
+            0 => return vec![TileCoord::new(0, 0, 0).into()],
126 147
             1 => {
127 148
                 // return every tile
128 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,7 +181,7 @@ impl OrthograficView {
160 181
             }
161 182
         };
162 183
 
163
-        let mut tiles = vec![center_tile];
184
+        let mut tiles = vec![center_tile.into()];
164 185
 
165 186
         let mut stack: Vec<TileNeighbor> = vec![];
166 187
         tile_neighbors(center_tile, &mut stack);
@@ -169,14 +190,14 @@ impl OrthograficView {
169 190
         visited.insert(TileNeighbor::Coord(center_tile));
170 191
         visited.extend(stack.iter());
171 192
 
172
-        let mut neighbors = vec![];
193
+        let mut neighbors = Vec::with_capacity(4);
173 194
 
174 195
         loop {
175 196
             if let Some(tn) = stack.pop() {
176 197
                 match tn {
177 198
                     TileNeighbor::Coord(tc) => {
178 199
                         if tile_is_visible(tc) {
179
-                            tiles.push(tc);
200
+                            tiles.push(tc.into());
180 201
                             tile_neighbors(tc, &mut neighbors);
181 202
                             for tn in &neighbors {
182 203
                                 if !visited.contains(tn) {

+ 106
- 15
src/tile_atlas.rs Dosyayı Görüntüle

@@ -1,8 +1,9 @@
1 1
 use context::Context;
2
-use coord::{ScreenRect, SubTileCoord, TileCoord, TextureRect};
2
+use coord::{SubTileCoord, TileCoord, TextureRect};
3 3
 use image;
4 4
 use linked_hash_map::LinkedHashMap;
5 5
 use mercator_view;
6
+use orthografic_view;
6 7
 use std::collections::HashMap;
7 8
 use std::collections::hash_map::Entry;
8 9
 use texture::Texture;
@@ -10,12 +11,6 @@ use tile::Tile;
10 11
 use tile_cache::TileCache;
11 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 15
 #[derive(Clone, Debug)]
21 16
 pub struct TileAtlas {
@@ -190,7 +185,9 @@ pub struct CacheSlot {
190 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 191
     /// Finds textures from the cache for a given slice of visible tiles. The texture atlas may not
195 192
     /// be big enough to hold all textures at once; a possible remainder of untextured visible
196 193
     /// tiles is returned as an `Option`.
@@ -199,14 +196,15 @@ pub trait VisibleTilesProvider<T> {
199 196
     fn textured_visible_tiles<'b>(
200 197
         &mut self,
201 198
         cx: &mut Context,
202
-        visible_tiles: &'b [T],
199
+        visible_tiles: &'b [U],
203 200
         max_tiles_to_use: usize,
204 201
         source: &TileSource,
205 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 208
     fn textured_visible_tiles<'b>(
211 209
         &mut self,
212 210
         cx: &mut Context,
@@ -214,7 +212,7 @@ impl VisibleTilesProvider<mercator_view::VisibleTile> for TileAtlas {
214 212
         max_tiles_to_use: usize,
215 213
         source: &TileSource,
216 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 217
         let mut tvt = Vec::with_capacity(visible_tiles.len());
220 218
 
@@ -234,7 +232,7 @@ impl VisibleTilesProvider<mercator_view::VisibleTile> for TileAtlas {
234 232
                 let tex_rect = self.slot_to_texture_rect(slot);
235 233
                 used_slots += 1;
236 234
                 tvt.push(
237
-                    TexturedVisibleTile {
235
+                    mercator_view::TexturedVisibleTile {
238 236
                         screen_rect: vt.rect,
239 237
                         tex_rect,
240 238
                         tex_minmax: tex_rect.inset(inset_x, inset_y),
@@ -274,7 +272,7 @@ impl VisibleTilesProvider<mercator_view::VisibleTile> for TileAtlas {
274 272
                         let tex_rect = self.slot_to_texture_rect(slot);
275 273
 
276 274
                         tvt.push(
277
-                            TexturedVisibleTile {
275
+                            mercator_view::TexturedVisibleTile {
278 276
                                 screen_rect: vt.rect.subdivide(&child_sub_coord),
279 277
                                 tex_rect,
280 278
                                 tex_minmax: tex_rect.inset(inset_x, inset_y),
@@ -282,7 +280,7 @@ impl VisibleTilesProvider<mercator_view::VisibleTile> for TileAtlas {
282 280
                         );
283 281
                     } else {
284 282
                         tvt.push(
285
-                            TexturedVisibleTile {
283
+                            mercator_view::TexturedVisibleTile {
286 284
                                 screen_rect: vt.rect.subdivide(&child_sub_coord),
287 285
                                 tex_rect: tex_sub_rect.subdivide(&child_sub_coord),
288 286
                                 tex_minmax: tex_rect.inset(inset_x, inset_y),
@@ -296,3 +294,96 @@ impl VisibleTilesProvider<mercator_view::VisibleTile> for TileAtlas {
296 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
+}