Browse Source

Render the map as a sphere

A work in progress...
Johannes Hofmann 7 years ago
parent
commit
d7a9681521
8 changed files with 347 additions and 48 deletions
  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 View File

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 View File

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 View File

1
-use std::f64::consts::PI;
1
+use std::f64::consts::{PI, FRAC_1_PI};
2
 use tile_source::TileSourceId;
2
 use tile_source::TileSourceId;
3
+use cgmath::{Point3};
3
 
4
 
4
 
5
 
5
 /// A position in latitude, longitude.
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
 #[derive(Copy, Debug, PartialEq, Clone)]
10
 #[derive(Copy, Debug, PartialEq, Clone)]
7
 pub struct LatLon {
11
 pub struct LatLon {
8
     pub lat: f64,
12
     pub lat: f64,
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
 /// A position in map coordinates.
69
 /// A position in map coordinates.
19
 /// Valid values for x and y lie in the interval [0.0, 1.0].
70
 /// Valid values for x and y lie in the interval [0.0, 1.0].
20
 #[derive(Copy, Debug, PartialEq, Clone)]
71
 #[derive(Copy, Debug, PartialEq, Clone)]
28
     fn from(pos: LatLon) -> MapCoord {
79
     fn from(pos: LatLon) -> MapCoord {
29
         let x = pos.lon * (1.0 / 360.0) + 0.5;
80
         let x = pos.lon * (1.0 / 360.0) + 0.5;
30
         let pi_lat = pos.lat * (PI / 180.0);
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
         MapCoord { x, y }
84
         MapCoord { x, y }
34
     }
85
     }
61
         self.y = 0.0f64.max(1.0f64.min(self.y));
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
 /// A position on the screen in pixels. Top-left corner is (0.0, 0.0).
123
 /// A position on the screen in pixels. Top-left corner is (0.0, 0.0).
195
         MapCoord::new(f64::from(self.x) * inv_zoom_factor, f64::from(self.y) * inv_zoom_factor)
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
     // Return the MapCoord of the center of the current tile.
269
     // Return the MapCoord of the center of the current tile.
199
     pub fn map_coord_center(&self) -> MapCoord {
270
     pub fn map_coord_center(&self) -> MapCoord {
200
         let inv_zoom_factor = f64::powi(2.0, -(self.zoom as i32));
271
         let inv_zoom_factor = f64::powi(2.0, -(self.zoom as i32));

+ 173
- 0
src/globe_tile_layer.rs View File

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 View File

23
 #[macro_use]
23
 #[macro_use]
24
 pub mod context;
24
 pub mod context;
25
 pub mod coord;
25
 pub mod coord;
26
+pub mod globe_tile_layer;
26
 pub mod map_view;
27
 pub mod map_view;
27
 pub mod map_view_gl;
28
 pub mod map_view_gl;
28
 pub mod marker_layer;
29
 pub mod marker_layer;

+ 67
- 5
src/map_view_gl.rs View File

1
 use context::Context;
1
 use context::Context;
2
 use coord::{MapCoord, ScreenCoord};
2
 use coord::{MapCoord, ScreenCoord};
3
+use globe_tile_layer::GlobeTileLayer;
3
 use map_view::MapView;
4
 use map_view::MapView;
4
 use marker_layer::MarkerLayer;
5
 use marker_layer::MarkerLayer;
5
 use session::Session;
6
 use session::Session;
7
+use texture::{Texture, TextureFormat};
8
+use tile_atlas::TileAtlas;
9
+use tile_cache::TileCache;
6
 use tile_layer::TileLayer;
10
 use tile_layer::TileLayer;
7
 use tile_source::TileSource;
11
 use tile_source::TileSource;
8
 
12
 
14
 pub struct MapViewGl {
18
 pub struct MapViewGl {
15
     map_view: MapView,
19
     map_view: MapView,
16
     viewport_size: (u32, u32),
20
     viewport_size: (u32, u32),
21
+    tile_cache: TileCache,
22
+    tile_atlas: TileAtlas,
17
     tile_layer: TileLayer,
23
     tile_layer: TileLayer,
18
     marker_layer: MarkerLayer,
24
     marker_layer: MarkerLayer,
25
+    globe_tile_layer: GlobeTileLayer,
19
     last_draw_type: DrawType,
26
     last_draw_type: DrawType,
20
 }
27
 }
21
 
28
 
23
 enum DrawType {
30
 enum DrawType {
24
     Null,
31
     Null,
25
     Tiles,
32
     Tiles,
26
-    Markers
33
+    Markers,
34
+    Globe,
27
 }
35
 }
28
 
36
 
29
 impl MapViewGl {
37
 impl MapViewGl {
44
             map_view.zoom = MIN_ZOOM_LEVEL;
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
         MapViewGl {
80
         MapViewGl {
48
             map_view,
81
             map_view,
49
             viewport_size: initial_size,
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
             marker_layer: MarkerLayer::new(cx),
86
             marker_layer: MarkerLayer::new(cx),
87
+            globe_tile_layer: GlobeTileLayer::new(cx),
52
             last_draw_type: DrawType::Null,
88
             last_draw_type: DrawType::Null,
53
         }
89
         }
54
     }
90
     }
68
     }
104
     }
69
 
105
 
70
     pub fn increase_atlas_size(&mut self, cx: &mut Context) -> Result<(), ()> {
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
     fn draw_tiles(&mut self, cx: &mut Context, source: &TileSource, snap_to_pixel: bool)
110
     fn draw_tiles(&mut self, cx: &mut Context, source: &TileSource, snap_to_pixel: bool)
76
     {
112
     {
77
         if self.last_draw_type != DrawType::Tiles {
113
         if self.last_draw_type != DrawType::Tiles {
78
             self.last_draw_type = DrawType::Tiles;
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
     fn draw_marker(&mut self, cx: &mut Context, snap_to_pixel: bool) {
129
     fn draw_marker(&mut self, cx: &mut Context, snap_to_pixel: bool) {
91
         self.marker_layer.draw(cx, &self.map_view, self.viewport_size, snap_to_pixel);
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
     /// Returns `Err` when tile cache is too small for this view.
154
     /// Returns `Err` when tile cache is too small for this view.
95
     /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
155
     /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
96
     /// size of the tile atlas.
156
     /// size of the tile atlas.
104
             self.draw_marker(cx, snap_to_pixel);
164
             self.draw_marker(cx, snap_to_pixel);
105
         }
165
         }
106
 
166
 
167
+        self.draw_globe(cx, source);
168
+
107
         ret
169
         ret
108
     }
170
     }
109
 
171
 

+ 1
- 1
src/tile_atlas.rs View File

233
         (tvt, None, used_slots)
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
         let scale_x = f64::from(self.tile_size) / f64::from(self.texture.width());
237
         let scale_x = f64::from(self.tile_size) / f64::from(self.texture.width());
238
         let scale_y = f64::from(self.tile_size) / f64::from(self.texture.height());
238
         let scale_y = f64::from(self.tile_size) / f64::from(self.texture.height());
239
 
239
 

+ 11
- 40
src/tile_layer.rs View File

4
 use coord::View;
4
 use coord::View;
5
 use map_view::MapView;
5
 use map_view::MapView;
6
 use program::Program;
6
 use program::Program;
7
-use texture::{Texture, TextureFormat};
8
-use tile::Tile;
9
 use tile_atlas::TileAtlas;
7
 use tile_atlas::TileAtlas;
10
 use tile_cache::TileCache;
8
 use tile_cache::TileCache;
11
 use tile_source::TileSource;
9
 use tile_source::TileSource;
16
 pub struct TileLayer {
14
 pub struct TileLayer {
17
     program: Program,
15
     program: Program,
18
     buffer: Buffer,
16
     buffer: Buffer,
19
-    cache: TileCache,
20
-    atlas: TileAtlas,
21
 }
17
 }
22
 
18
 
23
 
19
 
24
 impl TileLayer {
20
 impl TileLayer {
25
-    pub fn new<F>(
21
+    pub fn new(
26
         cx: &mut Context,
22
         cx: &mut Context,
27
-        update_func: F,
28
-        tile_size: u32,
29
-        use_network: bool,
30
-        use_async: bool,
23
+        atlas: &TileAtlas,
31
     ) -> TileLayer
24
     ) -> TileLayer
32
-        where F: Fn(Tile) + Sync + Send + 'static,
33
     {
25
     {
34
         let buffer = Buffer::new(cx, &[], 0);
26
         let buffer = Buffer::new(cx, &[], 0);
35
         check_gl_errors!(cx);
27
         check_gl_errors!(cx);
42
         ).unwrap();
34
         ).unwrap();
43
         check_gl_errors!(cx);
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
         check_gl_errors!(cx);
38
         check_gl_errors!(cx);
64
 
39
 
65
         program.add_attribute(
40
         program.add_attribute(
82
         TileLayer {
57
         TileLayer {
83
             program,
58
             program,
84
             buffer,
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
     // Has to be called once before one or multiple calls to `draw`.
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
         self.program.enable_vertex_attribs(cx);
65
         self.program.enable_vertex_attribs(cx);
97
         self.program.set_vertex_attribs(cx, &self.buffer);
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
     pub fn draw(
70
     pub fn draw(
103
         cx: &mut Context,
72
         cx: &mut Context,
104
         map_view: &MapView,
73
         map_view: &MapView,
105
         source: &TileSource,
74
         source: &TileSource,
75
+        cache: &mut TileCache,
76
+        atlas: &mut TileAtlas,
106
         viewport_size: (u32, u32),
77
         viewport_size: (u32, u32),
107
         snap_to_pixel: bool
78
         snap_to_pixel: bool
108
     ) -> Result<usize, usize> {
79
     ) -> Result<usize, usize> {
109
-        self.cache.set_view_location(View {
80
+        cache.set_view_location(View {
110
             source_id: source.id(),
81
             source_id: source.id(),
111
             zoom: map_view.tile_zoom(),
82
             zoom: map_view.tile_zoom(),
112
             center: map_view.center,
83
             center: map_view.center,
115
         let visible_tiles = map_view.visible_tiles(snap_to_pixel);
86
         let visible_tiles = map_view.visible_tiles(snap_to_pixel);
116
         let mut remainder = visible_tiles.as_slice();
87
         let mut remainder = visible_tiles.as_slice();
117
         let mut num_draws = 0;
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
         loop {
91
         loop {
121
             let (textured_visible_tiles, remainder_opt, used_tiles) = {
92
             let (textured_visible_tiles, remainder_opt, used_tiles) = {
122
-                self.atlas.textured_visible_tiles(
93
+                atlas.textured_visible_tiles(
123
                     cx,
94
                     cx,
124
                     remainder,
95
                     remainder,
125
                     max_tiles_to_use,
96
                     max_tiles_to_use,
126
                     source,
97
                     source,
127
-                    &mut self.cache,
98
+                    cache,
128
                 )
99
                 )
129
             };
100
             };
130
 
101