소스 검색

Draw in multiple steps when texture atlas is too small

Johannes Hofmann 8 년 전
부모
커밋
489df246d4
3개의 변경된 파일76개의 추가작업 그리고 16개의 파일을 삭제
  1. 44
    11
      src/map_view_gl.rs
  2. 5
    0
      src/tile_cache.rs
  3. 27
    5
      src/tile_cache_gl.rs

+ 44
- 11
src/map_view_gl.rs 파일 보기

@@ -96,18 +96,29 @@ impl<'a> MapViewGl<'a> {
96 96
             center: self.map_view.center,
97 97
         });
98 98
 
99
-        {
100
-            let visible_tiles = self.map_view.visible_tiles(true);
101
-            let textured_visible_tiles = self.tile_cache_gl.textured_visible_tiles(
102
-                &visible_tiles,
103
-                source,
104
-                &mut self.tile_cache,
105
-            );
99
+        self.cx.clear_color((0.2, 0.2, 0.2, 1.0));
100
+
101
+        let visible_tiles = self.map_view.visible_tiles(true);
102
+        let mut remainder = visible_tiles.as_slice();
103
+        let mut num_draws = 0;
104
+        let mut max_tiles_to_use = self.tile_cache.max_tiles();
105
+
106
+        loop {
107
+            let (textured_visible_tiles, remainder_opt, used_tiles) = {
108
+                self.tile_cache_gl.textured_visible_tiles(
109
+                    remainder,
110
+                    max_tiles_to_use,
111
+                    source,
112
+                    &mut self.tile_cache,
113
+                )
114
+            };
115
+
116
+            max_tiles_to_use -= used_tiles;
106 117
 
107 118
             let mut vertex_data: Vec<f32> = Vec::with_capacity(textured_visible_tiles.len() * (6 * 8));
108 119
             let scale_x = 2.0 / f64::from(self.viewport_size.0);
109 120
             let scale_y = -2.0 / f64::from(self.viewport_size.1);
110
-            for tvt in textured_visible_tiles {
121
+            for tvt in &textured_visible_tiles {
111 122
                 let minmax = [
112 123
                     tvt.tex_minmax.x1 as f32,
113 124
                     tvt.tex_minmax.y1 as f32,
@@ -153,10 +164,32 @@ impl<'a> MapViewGl<'a> {
153 164
             }
154 165
 
155 166
             self.buf.set_data(&vertex_data, vertex_data.len() / 4);
156
-        }
167
+            self.buf.draw(DrawMode::Triangles);
168
+
169
+            num_draws += 1;
170
+            debug!("draw #{}: tvt.len() = {}, remainder = {:?}, max_tiles = {}",
171
+                num_draws,
172
+                textured_visible_tiles.len(),
173
+                remainder_opt.map(|r| r.len()),
174
+                max_tiles_to_use);
175
+
176
+            if max_tiles_to_use <= 0 {
177
+                warn!("tile cache is too small for this view.");
178
+                break;
179
+            }
157 180
 
158
-        self.cx.clear_color((0.9, 0.9, 0.9, 1.0));
159
-        self.buf.draw(DrawMode::Triangles);
181
+            match remainder_opt {
182
+                None => break,
183
+                Some(new_remainder) => {
184
+                    if new_remainder.len() >= remainder.len() {
185
+                        warn!("failed to draw all tiles. number of remaining tiles did not decrease.");
186
+                        break;
187
+                    } else {
188
+                        remainder = new_remainder;
189
+                    }
190
+                },
191
+            }
192
+        }
160 193
     }
161 194
 
162 195
     pub fn step_zoom(&mut self, steps: i32, step_size: f64) {

+ 5
- 0
src/tile_cache.rs 파일 보기

@@ -28,6 +28,11 @@ impl TileCache {
28 28
         }
29 29
     }
30 30
 
31
+    // Return the maximum number of tiles that this cache can hold at once.
32
+    pub fn max_tiles(&self) -> usize {
33
+        self.max_tiles
34
+    }
35
+
31 36
     pub fn get_sync(
32 37
         &mut self,
33 38
         tile_coord: TileCoord,

+ 27
- 5
src/tile_cache_gl.rs 파일 보기

@@ -95,21 +95,37 @@ impl<'a> TileCacheGl<'a> {
95 95
         slot
96 96
     }
97 97
 
98
-    pub fn textured_visible_tiles(
98
+    /// Finds textures from the cache for a given slice of visible tiles. The texture atlas may not
99
+    /// be big enough to hold all textures at once; a possible remainder of untextured visible tiles is
100
+    /// returned as an `Option`.
101
+    /// The function guarantees that no more than `max_tiles_to_use` tiles are used for texturing;
102
+    /// the number of used tiles is returned as an `usize`.
103
+    pub fn textured_visible_tiles<'b>(
99 104
         &mut self,
100
-        visible_tiles: &[VisibleTile],
105
+        visible_tiles: &'b [VisibleTile],
106
+        max_tiles_to_use: usize,
101 107
         source: &TileSource,
102 108
         cache: &mut TileCache,
103
-        ) -> Vec<TexturedVisibleTile>
109
+        ) -> (Vec<TexturedVisibleTile>, Option<&'b [VisibleTile]>, usize)
104 110
     {
105 111
         let mut tvt = Vec::with_capacity(visible_tiles.len());
106 112
 
107 113
         let inset_x = 0.5 / f64::from(self.texture.width());
108 114
         let inset_y = 0.5 / f64::from(self.texture.height());
109 115
 
110
-        for vt in visible_tiles {
116
+        let num_usable_slots = self.slots_lru.len();
117
+        // The number of actually used slots may be lower, because slots can be used multiple times
118
+        // in the same view (especially the default slot).
119
+        let mut used_slots = 0_usize;
120
+
121
+        for (i, vt) in visible_tiles.iter().enumerate() {
122
+            if used_slots >= num_usable_slots || used_slots >= max_tiles_to_use {
123
+                return (tvt, Some(&visible_tiles[i..]), used_slots);
124
+            }
125
+
111 126
             if let Some(slot) = self.store(vt.tile, source, cache, true) {
112 127
                 let tex_rect = self.slot_to_texture_rect(slot);
128
+                used_slots += 1;
113 129
                 tvt.push(
114 130
                     TexturedVisibleTile {
115 131
                         screen_rect: vt.rect,
@@ -120,6 +136,10 @@ impl<'a> TileCacheGl<'a> {
120 136
             } else {
121 137
                 // exact tile not found
122 138
 
139
+                if used_slots + 5 > num_usable_slots || used_slots + 5 > max_tiles_to_use {
140
+                    return (tvt, Some(&visible_tiles[i..]), used_slots);
141
+                }
142
+
123 143
                 // default tile
124 144
                 let mut tex_sub_rect = self.slot_to_texture_rect(Self::default_slot());
125 145
                 let mut tex_rect = tex_sub_rect;
@@ -128,6 +148,7 @@ impl<'a> TileCacheGl<'a> {
128 148
                 for dist in 1..31 {
129 149
                     if let Some((parent_tile, sub_coord)) = vt.tile.parent(dist) {
130 150
                         if let Some(slot) = self.store(parent_tile, source, cache, false) {
151
+                            used_slots += 1;
131 152
                             tex_sub_rect = self.subslot_to_texture_rect(slot, sub_coord);
132 153
                             tex_rect = self.slot_to_texture_rect(slot);
133 154
                             break;
@@ -140,6 +161,7 @@ impl<'a> TileCacheGl<'a> {
140 161
                 // look for cached tiles in higher zoom layers
141 162
                 for &(child_tile, child_sub_coord) in &vt.tile.children() {
142 163
                     if let Some(slot) = self.store(child_tile, source, cache, false) {
164
+                        used_slots += 1;
143 165
                         let tex_rect = self.slot_to_texture_rect(slot);
144 166
 
145 167
                         tvt.push(
@@ -162,7 +184,7 @@ impl<'a> TileCacheGl<'a> {
162 184
             };
163 185
         }
164 186
 
165
-        tvt
187
+        (tvt, None, used_slots)
166 188
     }
167 189
 
168 190
     fn slot_to_texture_rect(&self, slot: CacheSlot) -> TextureRect {