ソースを参照

Render the map as a sphere

A work in progress...
Johannes Hofmann 7 年 前
コミット
d7a9681521
共有8 個のファイルを変更した347 個の追加48 個の削除を含む
  1. 9
    0
      shader/globe_tile.frag
  2. 12
    0
      shader/globe_tile.vert
  3. 73
    2
      src/coord.rs
  4. 173
    0
      src/globe_tile_layer.rs
  5. 1
    0
      src/main.rs
  6. 67
    5
      src/map_view_gl.rs
  7. 1
    1
      src/tile_atlas.rs
  8. 11
    40
      src/tile_layer.rs

+ 9
- 0
shader/globe_tile.frag ファイルの表示

@@ -0,0 +1,9 @@
1
+#version 100
2
+precision mediump float;
3
+
4
+varying vec2 v_tex;
5
+uniform sampler2D tex_map;
6
+
7
+void main() {
8
+    gl_FragColor = vec4(texture2D(tex_map, v_tex.xy).rgb, 1.0);
9
+}

+ 12
- 0
shader/globe_tile.vert ファイルの表示

@@ -0,0 +1,12 @@
1
+#version 100
2
+precision mediump float;
3
+
4
+attribute vec3 position;
5
+attribute vec2 tex_coord;
6
+
7
+varying vec2 v_tex;
8
+
9
+void main() {
10
+    gl_Position = vec4(position.xy, 0.0, 1.0);
11
+    v_tex = tex_coord;
12
+}

+ 73
- 2
src/coord.rs ファイルの表示

@@ -1,8 +1,12 @@
1
-use std::f64::consts::PI;
1
+use std::f64::consts::{PI, FRAC_1_PI};
2 2
 use tile_source::TileSourceId;
3
+use cgmath::{Point3};
3 4
 
4 5
 
5 6
 /// A position in latitude, longitude.
7
+/// Values are in degrees and usually in these intervals:
8
+/// latitude: [-90.0, 90.0]
9
+/// longitude: [-180, 180.0]
6 10
 #[derive(Copy, Debug, PartialEq, Clone)]
7 11
 pub struct LatLon {
8 12
     pub lat: f64,
@@ -15,6 +19,53 @@ impl LatLon {
15 19
     }
16 20
 }
17 21
 
22
+//TODO Add more conversions from/to LatLonRad
23
+/// A position in latitude, longitude.
24
+/// Values are in radians and usually in these intervals:
25
+/// latitude: [-0.5 * π, 0.5 * π]
26
+/// longitude: [-π, π]
27
+#[derive(Copy, Debug, PartialEq, Clone)]
28
+pub struct LatLonRad {
29
+    pub lat: f64,
30
+    pub lon: f64,
31
+}
32
+
33
+impl LatLonRad {
34
+    pub fn new(lat: f64, lon: f64) -> Self {
35
+        LatLonRad { lat, lon }
36
+    }
37
+
38
+    pub fn to_sphere_xyz(&self, radius: f64) -> SphereXYZ {
39
+        SphereXYZ {
40
+            x: radius * self.lat.cos() * self.lon.cos(),
41
+            y: radius * self.lat.sin(),
42
+            z: radius * self.lat.cos() * self.lon.sin(),
43
+        }
44
+    }
45
+
46
+    pub fn to_sphere_point3(&self, radius: f64) -> Point3<f32> {
47
+        let p = self.to_sphere_xyz(radius);
48
+        Point3::new(
49
+            p.x as f32,
50
+            p.y as f32,
51
+            p.z as f32,
52
+        )
53
+    }
54
+}
55
+
56
+#[derive(Copy, Debug, PartialEq, Clone)]
57
+pub struct SphereXYZ {
58
+    pub x: f64,
59
+    pub y: f64,
60
+    pub z: f64,
61
+}
62
+
63
+impl SphereXYZ {
64
+    pub fn new(x: f64, y: f64, z: f64) -> Self {
65
+        SphereXYZ { x, y, z }
66
+    }
67
+}
68
+
18 69
 /// A position in map coordinates.
19 70
 /// Valid values for x and y lie in the interval [0.0, 1.0].
20 71
 #[derive(Copy, Debug, PartialEq, Clone)]
@@ -28,7 +79,7 @@ impl From<LatLon> for MapCoord
28 79
     fn from(pos: LatLon) -> MapCoord {
29 80
         let x = pos.lon * (1.0 / 360.0) + 0.5;
30 81
         let pi_lat = pos.lat * (PI / 180.0);
31
-        let y = f64::ln(f64::tan(pi_lat) + 1.0 / f64::cos(pi_lat)) * (-0.5 / PI) + 0.5;
82
+        let y = f64::ln(f64::tan(pi_lat) + 1.0 / f64::cos(pi_lat)) * (-0.5 * FRAC_1_PI) + 0.5;
32 83
 
33 84
         MapCoord { x, y }
34 85
     }
@@ -61,6 +112,12 @@ impl MapCoord {
61 112
         self.y = 0.0f64.max(1.0f64.min(self.y));
62 113
     }
63 114
 
115
+    pub fn to_latlon_rad(&self) -> LatLonRad {
116
+        LatLonRad {
117
+            lat: (PI - self.y * (2.0 * PI)).sinh().atan(),
118
+            lon: self.x * (2.0 * PI) - PI,
119
+        }
120
+    }
64 121
 }
65 122
 
66 123
 /// A position on the screen in pixels. Top-left corner is (0.0, 0.0).
@@ -195,6 +252,20 @@ impl TileCoord {
195 252
         MapCoord::new(f64::from(self.x) * inv_zoom_factor, f64::from(self.y) * inv_zoom_factor)
196 253
     }
197 254
 
255
+    // Return the LatLonRad coordinate of the top left corner of the current tile.
256
+    pub fn latlon_rad_north_west(&self) -> LatLonRad {
257
+        let factor = f64::powi(2.0, -(self.zoom as i32)) * (2.0 * PI);
258
+        LatLonRad::new(
259
+            (PI - f64::from(self.y) * factor).sinh().atan(),
260
+            f64::from(self.x) * factor - PI,
261
+        )
262
+    }
263
+
264
+    // Return the LatLonRad coordinate of the bottom right corner of the current tile.
265
+    pub fn latlon_rad_south_east(&self) -> LatLonRad {
266
+        TileCoord { zoom: self.zoom, x: self.x + 1, y: self.y + 1 }.latlon_rad_north_west()
267
+    }
268
+
198 269
     // Return the MapCoord of the center of the current tile.
199 270
     pub fn map_coord_center(&self) -> MapCoord {
200 271
         let inv_zoom_factor = f64::powi(2.0, -(self.zoom as i32));

+ 173
- 0
src/globe_tile_layer.rs ファイルの表示

@@ -0,0 +1,173 @@
1
+use std::f32::consts::{PI, FRAC_1_PI};
2
+use std::ffi::CStr;
3
+use buffer::{Buffer, DrawMode};
4
+use cgmath::{Matrix3, Point3, Transform, vec3};
5
+use context::Context;
6
+use coord::{LatLonRad, TileCoord, View};
7
+use map_view::MapView;
8
+use program::Program;
9
+use tile_atlas::TileAtlas;
10
+use tile_cache::TileCache;
11
+use tile_source::TileSource;
12
+use vertex_attrib::VertexAttribParams;
13
+
14
+
15
+#[derive(Debug)]
16
+pub struct GlobeTileLayer {
17
+    program: Program,
18
+    buffer: Buffer,
19
+}
20
+
21
+
22
+impl GlobeTileLayer {
23
+    pub fn new(
24
+        cx: &mut Context,
25
+    ) -> GlobeTileLayer
26
+    {
27
+        let buffer = Buffer::new(cx, &[], 0);
28
+        check_gl_errors!(cx);
29
+        cx.bind_buffer(buffer.id());
30
+
31
+        let mut program = Program::new(
32
+            cx,
33
+            include_bytes!("../shader/globe_tile.vert"),
34
+            include_bytes!("../shader/globe_tile.frag"),
35
+        ).unwrap();
36
+        check_gl_errors!(cx);
37
+
38
+        program.add_attribute(
39
+            cx,
40
+            CStr::from_bytes_with_nul(b"position\0").unwrap(),
41
+            &VertexAttribParams::new(3, 5, 0)
42
+        );
43
+        program.add_attribute(
44
+            cx,
45
+            CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(),
46
+            &VertexAttribParams::new(2, 5, 3)
47
+        );
48
+        check_gl_errors!(cx);
49
+
50
+        GlobeTileLayer {
51
+            program,
52
+            buffer,
53
+        }
54
+    }
55
+
56
+    // Has to be called once before one or multiple calls to `draw`.
57
+    pub fn prepare_draw(&mut self, cx: &mut Context, atlas: &TileAtlas) {
58
+        self.program.enable_vertex_attribs(cx);
59
+        self.program.set_vertex_attribs(cx, &self.buffer);
60
+        cx.set_active_texture_unit(atlas.texture().unit());
61
+    }
62
+
63
+    pub fn draw(
64
+        &mut self,
65
+        cx: &mut Context,
66
+        map_view: &MapView,
67
+        source: &TileSource,
68
+        cache: &mut TileCache,
69
+        tile_atlas: &mut TileAtlas,
70
+        viewport_size: (u32, u32),
71
+    ) {
72
+        cache.set_view_location(View {
73
+            source_id: source.id(),
74
+            zoom: map_view.tile_zoom(),
75
+            center: map_view.center,
76
+        });
77
+
78
+        let mut vertex_data = vec![];
79
+
80
+        let (scale_x, scale_y) = {
81
+            let factor = 2.0f32.powf(map_view.zoom as f32) *
82
+                (FRAC_1_PI * map_view.tile_size as f32);
83
+            (factor / viewport_size.0 as f32, factor / viewport_size.1 as f32)
84
+        };
85
+
86
+        let screen_mat: Matrix3<f32> = Matrix3::from_cols(
87
+            vec3(scale_x, 0.0, 0.0),
88
+            vec3(0.0, scale_y, 0.0),
89
+            vec3(0.0, 0.0, 1.0),
90
+        );
91
+
92
+        let rot_mat_x: Matrix3<f32> = {
93
+            let center_latlon = map_view.center.to_latlon_rad();
94
+            let alpha = center_latlon.lon as f32 + (PI * 0.5);
95
+            let cosa = alpha.cos();
96
+            let sina = alpha.sin();
97
+                Matrix3::from_cols(
98
+                vec3(cosa, 0.0, -sina),
99
+                vec3(0.0, 1.0, 0.0),
100
+                vec3(sina, 0.0, cosa),
101
+            )
102
+        };
103
+
104
+        let rot_mat_y: Matrix3<f32> = {
105
+            let center_latlon = map_view.center.to_latlon_rad();
106
+            let alpha = (-center_latlon.lat) as f32;
107
+            let cosa = alpha.cos();
108
+            let sina = alpha.sin();
109
+                Matrix3::from_cols(
110
+                vec3(1.0, 0.0, 0.0),
111
+                vec3(0.0, cosa, sina),
112
+                vec3(0.0, -sina, cosa),
113
+            )
114
+        };
115
+
116
+        let rot_mat = Transform::<Point3<f32>>::concat(&rot_mat_y, &rot_mat_x);
117
+
118
+        for tile_y in 0..16 {
119
+            for tile_x in 0..16 {
120
+                let tc = TileCoord::new(4, tile_x, tile_y);
121
+                let slot = tile_atlas.store(cx, tc, source, cache, true)
122
+                    .unwrap_or_else(TileAtlas::default_slot);
123
+                let texrect = tile_atlas.slot_to_texture_rect(slot);
124
+
125
+                for &(tc, sub_tile_a) in &tc.children() {
126
+                    for &(tc, sub_tile_b) in &tc.children() {
127
+                        let sub_tile = sub_tile_a.subdivide(&sub_tile_b);
128
+
129
+                        let ll_nw = tc.latlon_rad_north_west();
130
+                        let ll_se = {
131
+                            let tc = TileCoord::new(tc.zoom, tc.x + 1, tc.y + 1);
132
+                            tc.latlon_rad_north_west()
133
+                        };
134
+
135
+                        let ll_ne = LatLonRad::new(ll_nw.lat, ll_se.lon);
136
+                        let ll_sw = LatLonRad::new(ll_se.lat, ll_nw.lon);
137
+
138
+                        let p1 = ll_nw.to_sphere_point3(1.0);
139
+                        let p2 = ll_ne.to_sphere_point3(1.0);
140
+                        let p3 = ll_se.to_sphere_point3(1.0);
141
+                        let p4 = ll_sw.to_sphere_point3(1.0);
142
+
143
+                        let p1 = screen_mat.transform_point(rot_mat.transform_point(p1));
144
+                        let p2 = screen_mat.transform_point(rot_mat.transform_point(p2));
145
+                        let p3 = screen_mat.transform_point(rot_mat.transform_point(p3));
146
+                        let p4 = screen_mat.transform_point(rot_mat.transform_point(p4));
147
+
148
+                        if p1.z > 0.0 || p2.z > 0.0 || p3.z > 0.0 || p4.z > 0.0 {
149
+                            continue;
150
+                        }
151
+
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(&p2);
161
+                        vertex_data.extend(&p3);
162
+                        vertex_data.extend(&p1);
163
+                        vertex_data.extend(&p3);
164
+                        vertex_data.extend(&p4);
165
+                    }
166
+                }
167
+            }
168
+        }
169
+
170
+        self.buffer.set_data(cx, &vertex_data, vertex_data.len() / 4);
171
+        self.buffer.draw(cx, &self.program, DrawMode::Triangles);
172
+    }
173
+}

+ 1
- 0
src/main.rs ファイルの表示

@@ -23,6 +23,7 @@ pub mod config;
23 23
 #[macro_use]
24 24
 pub mod context;
25 25
 pub mod coord;
26
+pub mod globe_tile_layer;
26 27
 pub mod map_view;
27 28
 pub mod map_view_gl;
28 29
 pub mod marker_layer;

+ 67
- 5
src/map_view_gl.rs ファイルの表示

@@ -1,8 +1,12 @@
1 1
 use context::Context;
2 2
 use coord::{MapCoord, ScreenCoord};
3
+use globe_tile_layer::GlobeTileLayer;
3 4
 use map_view::MapView;
4 5
 use marker_layer::MarkerLayer;
5 6
 use session::Session;
7
+use texture::{Texture, TextureFormat};
8
+use tile_atlas::TileAtlas;
9
+use tile_cache::TileCache;
6 10
 use tile_layer::TileLayer;
7 11
 use tile_source::TileSource;
8 12
 
@@ -14,8 +18,11 @@ const MAX_ZOOM_LEVEL: f64 = 22.0;
14 18
 pub struct MapViewGl {
15 19
     map_view: MapView,
16 20
     viewport_size: (u32, u32),
21
+    tile_cache: TileCache,
22
+    tile_atlas: TileAtlas,
17 23
     tile_layer: TileLayer,
18 24
     marker_layer: MarkerLayer,
25
+    globe_tile_layer: GlobeTileLayer,
19 26
     last_draw_type: DrawType,
20 27
 }
21 28
 
@@ -23,7 +30,8 @@ pub struct MapViewGl {
23 30
 enum DrawType {
24 31
     Null,
25 32
     Tiles,
26
-    Markers
33
+    Markers,
34
+    Globe,
27 35
 }
28 36
 
29 37
 impl MapViewGl {
@@ -44,11 +52,39 @@ impl MapViewGl {
44 52
             map_view.zoom = MIN_ZOOM_LEVEL;
45 53
         }
46 54
 
55
+        let atlas_size = {
56
+            let default_size = 2048;
57
+            let max_size = cx.max_texture_size() as u32;
58
+            if default_size <= max_size {
59
+                default_size
60
+            } else {
61
+                if tile_size * 3 > max_size {
62
+                    error!("maximal tile size ({}) is too small", max_size);
63
+                }
64
+
65
+                max_size
66
+            }
67
+        };
68
+
69
+        let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
70
+        check_gl_errors!(cx);
71
+
72
+        let mut tile_atlas = TileAtlas::new(cx, atlas_tex, tile_size, use_async);
73
+        //TODO remove this
74
+        tile_atlas.double_texture_size(cx);
75
+        tile_atlas.double_texture_size(cx);
76
+        tile_atlas.double_texture_size(cx);
77
+
78
+        let tile_layer = TileLayer::new(cx, &tile_atlas);
79
+
47 80
         MapViewGl {
48 81
             map_view,
49 82
             viewport_size: initial_size,
50
-            tile_layer: TileLayer::new(cx, move |_| update_func(), tile_size, use_network, use_async),
83
+            tile_cache: TileCache::new(move |_tile| update_func(), use_network),
84
+            tile_atlas,
85
+            tile_layer,
51 86
             marker_layer: MarkerLayer::new(cx),
87
+            globe_tile_layer: GlobeTileLayer::new(cx),
52 88
             last_draw_type: DrawType::Null,
53 89
         }
54 90
     }
@@ -68,7 +104,7 @@ impl MapViewGl {
68 104
     }
69 105
 
70 106
     pub fn increase_atlas_size(&mut self, cx: &mut Context) -> Result<(), ()> {
71
-        self.tile_layer.double_atlas_size(cx)
107
+        self.tile_atlas.double_texture_size(cx)
72 108
     }
73 109
 
74 110
     fn draw_tiles(&mut self, cx: &mut Context, source: &TileSource, snap_to_pixel: bool)
@@ -76,10 +112,18 @@ impl MapViewGl {
76 112
     {
77 113
         if self.last_draw_type != DrawType::Tiles {
78 114
             self.last_draw_type = DrawType::Tiles;
79
-            self.tile_layer.prepare_draw(cx);
115
+            self.tile_layer.prepare_draw(cx, &self.tile_atlas);
80 116
         }
81 117
 
82
-        self.tile_layer.draw(cx, &self.map_view, source, self.viewport_size, snap_to_pixel)
118
+        self.tile_layer.draw(
119
+            cx,
120
+            &self.map_view,
121
+            source,
122
+            &mut self.tile_cache,
123
+            &mut self.tile_atlas,
124
+            self.viewport_size,
125
+            snap_to_pixel
126
+        )
83 127
     }
84 128
 
85 129
     fn draw_marker(&mut self, cx: &mut Context, snap_to_pixel: bool) {
@@ -91,6 +135,22 @@ impl MapViewGl {
91 135
         self.marker_layer.draw(cx, &self.map_view, self.viewport_size, snap_to_pixel);
92 136
     }
93 137
 
138
+    fn draw_globe(&mut self, cx: &mut Context, source: &TileSource) {
139
+        if self.last_draw_type != DrawType::Globe {
140
+            self.last_draw_type = DrawType::Globe;
141
+            self.globe_tile_layer.prepare_draw(cx, &self.tile_atlas);
142
+        }
143
+
144
+        self.globe_tile_layer.draw(
145
+            cx,
146
+            &self.map_view,
147
+            source,
148
+            &mut self.tile_cache,
149
+            &mut self.tile_atlas,
150
+            self.viewport_size,
151
+        );
152
+    }
153
+
94 154
     /// Returns `Err` when tile cache is too small for this view.
95 155
     /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
96 156
     /// size of the tile atlas.
@@ -104,6 +164,8 @@ impl MapViewGl {
104 164
             self.draw_marker(cx, snap_to_pixel);
105 165
         }
106 166
 
167
+        self.draw_globe(cx, source);
168
+
107 169
         ret
108 170
     }
109 171
 

+ 1
- 1
src/tile_atlas.rs ファイルの表示

@@ -233,7 +233,7 @@ impl TileAtlas {
233 233
         (tvt, None, used_slots)
234 234
     }
235 235
 
236
-    fn slot_to_texture_rect(&self, slot: CacheSlot) -> TextureRect {
236
+    pub fn slot_to_texture_rect(&self, slot: CacheSlot) -> TextureRect {
237 237
         let scale_x = f64::from(self.tile_size) / f64::from(self.texture.width());
238 238
         let scale_y = f64::from(self.tile_size) / f64::from(self.texture.height());
239 239
 

+ 11
- 40
src/tile_layer.rs ファイルの表示

@@ -4,8 +4,6 @@ use context::Context;
4 4
 use coord::View;
5 5
 use map_view::MapView;
6 6
 use program::Program;
7
-use texture::{Texture, TextureFormat};
8
-use tile::Tile;
9 7
 use tile_atlas::TileAtlas;
10 8
 use tile_cache::TileCache;
11 9
 use tile_source::TileSource;
@@ -16,20 +14,14 @@ use vertex_attrib::VertexAttribParams;
16 14
 pub struct TileLayer {
17 15
     program: Program,
18 16
     buffer: Buffer,
19
-    cache: TileCache,
20
-    atlas: TileAtlas,
21 17
 }
22 18
 
23 19
 
24 20
 impl TileLayer {
25
-    pub fn new<F>(
21
+    pub fn new(
26 22
         cx: &mut Context,
27
-        update_func: F,
28
-        tile_size: u32,
29
-        use_network: bool,
30
-        use_async: bool,
23
+        atlas: &TileAtlas,
31 24
     ) -> TileLayer
32
-        where F: Fn(Tile) + Sync + Send + 'static,
33 25
     {
34 26
         let buffer = Buffer::new(cx, &[], 0);
35 27
         check_gl_errors!(cx);
@@ -42,24 +34,7 @@ impl TileLayer {
42 34
         ).unwrap();
43 35
         check_gl_errors!(cx);
44 36
 
45
-        let atlas_size = {
46
-            let default_size = 2048;
47
-            let max_size = cx.max_texture_size() as u32;
48
-            if default_size <= max_size {
49
-                default_size
50
-            } else {
51
-                if tile_size * 3 > max_size {
52
-                    error!("maximal tile size ({}) is too small", max_size);
53
-                }
54
-
55
-                max_size
56
-            }
57
-        };
58
-
59
-        let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
60
-        check_gl_errors!(cx);
61
-
62
-        program.add_texture(cx, &atlas_tex, 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());
63 38
         check_gl_errors!(cx);
64 39
 
65 40
         program.add_attribute(
@@ -82,20 +57,14 @@ impl TileLayer {
82 57
         TileLayer {
83 58
             program,
84 59
             buffer,
85
-            cache: TileCache::new(update_func, use_network),
86
-            atlas: TileAtlas::new(cx, atlas_tex, tile_size, use_async),
87 60
         }
88 61
     }
89 62
 
90
-    pub fn double_atlas_size(&mut self, cx: &mut Context) -> Result<(), ()> {
91
-        self.atlas.double_texture_size(cx)
92
-    }
93
-
94 63
     // Has to be called once before one or multiple calls to `draw`.
95
-    pub fn prepare_draw(&mut self, cx: &mut Context) {
64
+    pub fn prepare_draw(&mut self, cx: &mut Context, atlas: &TileAtlas) {
96 65
         self.program.enable_vertex_attribs(cx);
97 66
         self.program.set_vertex_attribs(cx, &self.buffer);
98
-        cx.set_active_texture_unit(self.atlas.texture().unit());
67
+        cx.set_active_texture_unit(atlas.texture().unit());
99 68
     }
100 69
 
101 70
     pub fn draw(
@@ -103,10 +72,12 @@ impl TileLayer {
103 72
         cx: &mut Context,
104 73
         map_view: &MapView,
105 74
         source: &TileSource,
75
+        cache: &mut TileCache,
76
+        atlas: &mut TileAtlas,
106 77
         viewport_size: (u32, u32),
107 78
         snap_to_pixel: bool
108 79
     ) -> Result<usize, usize> {
109
-        self.cache.set_view_location(View {
80
+        cache.set_view_location(View {
110 81
             source_id: source.id(),
111 82
             zoom: map_view.tile_zoom(),
112 83
             center: map_view.center,
@@ -115,16 +86,16 @@ impl TileLayer {
115 86
         let visible_tiles = map_view.visible_tiles(snap_to_pixel);
116 87
         let mut remainder = visible_tiles.as_slice();
117 88
         let mut num_draws = 0;
118
-        let mut max_tiles_to_use = self.cache.max_tiles();
89
+        let mut max_tiles_to_use = cache.max_tiles();
119 90
 
120 91
         loop {
121 92
             let (textured_visible_tiles, remainder_opt, used_tiles) = {
122
-                self.atlas.textured_visible_tiles(
93
+                atlas.textured_visible_tiles(
123 94
                     cx,
124 95
                     remainder,
125 96
                     max_tiles_to_use,
126 97
                     source,
127
-                    &mut self.cache,
98
+                    cache,
128 99
                 )
129 100
             };
130 101