From 6c81997b59dfeb563a5176834fd48aca78f92d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20H=C3=BCsser?= Date: Thu, 5 Sep 2019 20:08:12 +0200 Subject: [PATCH] Revamp program structure for better memory performance. While this is ok now, loading new tiles makes the renderer stutter ... --- config/default.toml | 2 +- src/bin/app_state.rs | 94 ++++++++++++++++++++ src/bin/drawing/painter.rs | 127 ++++----------------------- src/bin/main.rs | 2 +- src/lib/cache.rs | 11 +-- src/lib/drawing/drawable_tile.rs | 102 --------------------- src/lib/drawing/loaded_gpu_tile.rs | 24 +++++ src/lib/drawing/mod.rs | 4 +- src/lib/interaction/collider.rs | 11 +-- src/lib/interaction/tile_collider.rs | 34 +++++++ src/lib/vector_tile/mod.rs | 2 + src/lib/vector_tile/tile.rs | 38 ++++---- src/lib/vector_tile/visible_tile.rs | 92 +++++++++++++++++++ 13 files changed, 302 insertions(+), 241 deletions(-) delete mode 100644 src/lib/drawing/drawable_tile.rs create mode 100644 src/lib/drawing/loaded_gpu_tile.rs create mode 100644 src/lib/vector_tile/visible_tile.rs diff --git a/config/default.toml b/config/default.toml index 9b38be8..eaf1afc 100644 --- a/config/default.toml +++ b/config/default.toml @@ -10,7 +10,7 @@ ui_font = "config/Ruda-Bold.ttf" max_tiles = 200 max_features = 1000 tile_size = 384 -msaa_samples = 4 +msaa_samples = 1 selection_tags = [] [renderer.temperature] diff --git a/src/bin/app_state.rs b/src/bin/app_state.rs index a7ea78a..37cc34a 100644 --- a/src/bin/app_state.rs +++ b/src/bin/app_state.rs @@ -1,3 +1,8 @@ +use std::collections::BTreeMap; +use std::sync::{ + Arc, + RwLock, +}; use lyon::math::Point; use crate::*; use stats::Stats; @@ -11,6 +16,8 @@ pub struct AppState { pub hovered_objects: Vec, pub selected_objects: Vec, pub stats: Stats, + visible_tiles: BTreeMap, + feature_collection: Arc>, } impl AppState { @@ -31,6 +38,93 @@ impl AppState { hovered_objects: vec![], selected_objects: vec![], stats: Stats::new(), + visible_tiles: BTreeMap::new(), + feature_collection: Arc::new(RwLock::new(FeatureCollection::new(CONFIG.renderer.max_features as u32))), + } + } + + pub fn visible_tiles(&self) -> &BTreeMap { + &self.visible_tiles + } + + pub fn feature_collection(&self) -> Arc> { + self.feature_collection.clone() + } + + pub fn load_tiles(&mut self) { + let tile_field = self.screen.get_tile_boundaries_for_zoom_level(self.zoom, 1); + + // Remove old bigger tiles which are not in the FOV anymore. + let old_tile_field = self.screen.get_tile_boundaries_for_zoom_level(self.zoom - 1.0, 2); + let key_iter: Vec<_> = self.visible_tiles.keys().copied().collect(); + for key in key_iter { + if key.z == (self.zoom - 1.0) as u32 { + if !old_tile_field.contains(&key) { + self.visible_tiles.remove(&key); + } + } else { + if !tile_field.contains(&key) { + self.visible_tiles.remove(&key); + } + } + } + + self.tile_cache.finalize_loaded_tiles(); + for tile_id in tile_field.iter() { + if !self.visible_tiles.contains_key(&tile_id) { + self.tile_cache.request_tile(&tile_id, self.feature_collection.clone(), &CONFIG.renderer.selection_tags.clone()); + + let tile_cache = &mut self.tile_cache; + if let Some(tile) = tile_cache.try_get_tile(&tile_id) { + + let mut visible_tile = VisibleTile::new(tile); + + visible_tile.load_collider(); + + self.visible_tiles.insert( + tile_id.clone(), + visible_tile + ); + + // Remove old bigger tile when all 4 smaller tiles are loaded. + let mut count = 0; + let num_x = (tile_id.x / 2) * 2; + let num_y = (tile_id.y / 2) * 2; + for tile_id in &[ + TileId::new(tile_id.z, num_x, num_y), + TileId::new(tile_id.z, num_x + 1, num_y), + TileId::new(tile_id.z, num_x + 1, num_y + 1), + TileId::new(tile_id.z, num_x, num_y + 1), + ] { + if !tile_field.contains(tile_id) { + count += 1; + continue; + } + if self.visible_tiles.contains_key(tile_id) { + count += 1; + } + } + if count == 4 { + self.visible_tiles.remove(&TileId::new(tile_id.z - 1, num_x / 2, num_y / 2)); + } + + // Remove old smaller tiles when all 4 smaller tiles are loaded. + for tile_id in &[ + TileId::new(tile_id.z + 1, tile_id.x * 2, tile_id.y * 2), + TileId::new(tile_id.z + 1, tile_id.x * 2 + 1, tile_id.y * 2), + TileId::new(tile_id.z + 1, tile_id.x * 2 + 1, tile_id.y * 2 + 1), + TileId::new(tile_id.z + 1, tile_id.x * 2, tile_id.y * 2 + 1), + ] { + self.visible_tiles.remove(tile_id); + } + } else { + log::trace!("Could not read tile {} from cache.", tile_id); + } + } + } + + if let Ok(mut feature_collection) = self.feature_collection.try_write() { + feature_collection.load_styles(self.zoom, &mut self.css_cache); } } diff --git a/src/bin/drawing/painter.rs b/src/bin/drawing/painter.rs index 45fd263..a617372 100644 --- a/src/bin/drawing/painter.rs +++ b/src/bin/drawing/painter.rs @@ -68,12 +68,10 @@ pub struct Painter { stencil: TextureView, uniform_buffer: Buffer, tile_transform_buffer: (Buffer, u64), - loaded_tiles: BTreeMap, bind_group_layout: BindGroupLayout, bind_group: BindGroup, rx: crossbeam_channel::Receiver>, _watcher: RecommendedWatcher, - feature_collection: Arc>, temperature: crate::drawing::weather::Temperature, } @@ -161,8 +159,6 @@ impl Painter { ] }); - let feature_collection = Arc::new(RwLock::new(FeatureCollection::new(CONFIG.renderer.max_features as u32))); - let swap_chain_descriptor = wgpu::SwapChainDescriptor { usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, format: wgpu::TextureFormat::Bgra8Unorm, @@ -183,7 +179,7 @@ impl Painter { &device, &app_state.screen, app_state.zoom, - std::iter::empty::<&DrawableTile>() + std::iter::empty::<&VisibleTile>() ); let blend_pipeline = Self::create_layer_render_pipeline( @@ -249,12 +245,10 @@ impl Painter { uniform_buffer, stencil, tile_transform_buffer, - loaded_tiles: BTreeMap::new(), bind_group_layout, bind_group, _watcher: watcher, rx, - feature_collection, temperature, } } @@ -385,21 +379,22 @@ impl Painter { device: &Device, screen: &Screen, z: f32, - drawable_tiles: impl Iterator + visible_tiles: impl Iterator ) -> (Buffer, u64) { const TILE_DATA_SIZE: usize = 20; let tile_data_buffer_byte_size = TILE_DATA_SIZE * 4 * CONFIG.renderer.max_tiles; let mut data = vec![0f32; tile_data_buffer_byte_size]; let mut i = 0; - for dt in drawable_tiles { - let matrix = screen.tile_to_global_space(z, &dt.tile_id); + for vt in visible_tiles { + let extent = vt.extent() as f32; + let matrix = screen.tile_to_global_space(z, &vt.tile_id()); for float in matrix.as_slice() { data[i] = *float; i += 1; } for _ in 0..4 { - data[i] = dt.extent as f32; + data[i] = extent; i += 1; } } @@ -529,13 +524,6 @@ impl Painter { } } - pub fn update_styles(&mut self, zoom: f32, css_cache: &mut RulesCache) { - if css_cache.update() { - let mut feature_collection = self.feature_collection.write().unwrap(); - feature_collection.load_styles(zoom, css_cache); - } - } - pub fn get_hidpi_factor(&self) -> f64 { self.hidpi_factor } @@ -572,7 +560,7 @@ impl Painter { &self.device, &app_state.screen, app_state.zoom, - self.loaded_tiles.values() + app_state.visible_tiles().values() ); } @@ -618,92 +606,10 @@ impl Painter { device.create_texture(frame_descriptor).create_default_view() } - fn load_tiles(&mut self, app_state: &mut AppState) { - let tile_field = app_state.screen.get_tile_boundaries_for_zoom_level(app_state.zoom, 1); - - // Remove old bigger tiles which are not in the FOV anymore. - let old_tile_field = app_state.screen.get_tile_boundaries_for_zoom_level(app_state.zoom - 1.0, 2); - let key_iter: Vec<_> = self.loaded_tiles.keys().copied().collect(); - for key in key_iter { - if key.z == (app_state.zoom - 1.0) as u32 { - if !old_tile_field.contains(&key) { - self.loaded_tiles.remove(&key); - } - } else { - if !tile_field.contains(&key) { - self.loaded_tiles.remove(&key); - } - } - } - - app_state.tile_cache.finalize_loaded_tiles(); - for tile_id in tile_field.iter() { - if !self.loaded_tiles.contains_key(&tile_id) { - app_state.tile_cache.request_tile(&tile_id, self.feature_collection.clone(), &CONFIG.renderer.selection_tags.clone()); - - let tile_cache = &mut app_state.tile_cache; - if let Some(tile) = tile_cache.try_get_tile(&tile_id) { - - let drawable_tile = DrawableTile::load_from_tile_id( - &self.device, - tile_id, - &tile - ); - - self.loaded_tiles.insert( - tile_id.clone(), - drawable_tile - ); - - // Remove old bigger tile when all 4 smaller tiles are loaded. - let mut count = 0; - let num_x = (tile_id.x / 2) * 2; - let num_y = (tile_id.y / 2) * 2; - for tile_id in &[ - TileId::new(tile_id.z, num_x, num_y), - TileId::new(tile_id.z, num_x + 1, num_y), - TileId::new(tile_id.z, num_x + 1, num_y + 1), - TileId::new(tile_id.z, num_x, num_y + 1), - ] { - if !tile_field.contains(tile_id) { - count += 1; - continue; - } - if self.loaded_tiles.contains_key(tile_id) { - count += 1; - } - } - if count == 4 { - self.loaded_tiles.remove(&TileId::new(tile_id.z - 1, num_x / 2, num_y / 2)); - } - - // Remove old smaller tiles when all 4 smaller tiles are loaded. - for tile_id in &[ - TileId::new(tile_id.z + 1, tile_id.x * 2, tile_id.y * 2), - TileId::new(tile_id.z + 1, tile_id.x * 2 + 1, tile_id.y * 2), - TileId::new(tile_id.z + 1, tile_id.x * 2 + 1, tile_id.y * 2 + 1), - TileId::new(tile_id.z + 1, tile_id.x * 2, tile_id.y * 2 + 1), - ] { - self.loaded_tiles.remove(tile_id); - } - } else { - log::trace!("Could not read tile {} from cache.", tile_id); - } - } - } - - let mut feature_collection = self.feature_collection.write().unwrap(); - feature_collection.load_styles(app_state.zoom, &mut app_state.css_cache); - } - pub fn paint(&mut self, hud: &mut super::ui::HUD, app_state: &mut AppState) { let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); - self.load_tiles(app_state); - let feature_collection = { - let lock = self.feature_collection.clone(); - let feature_collection = lock.read().unwrap(); - (*feature_collection).clone() - }; + + let feature_collection = app_state.feature_collection().read().unwrap().clone(); self.update_uniforms(&mut encoder, &app_state, &feature_collection); self.bind_group = Self::create_blend_bind_group( &self.device, @@ -711,7 +617,7 @@ impl Painter { &self.uniform_buffer, &self.tile_transform_buffer ); - let num_tiles = self.loaded_tiles.len(); + let num_tiles = app_state.visible_tiles().len(); let features = feature_collection.get_features(); if features.len() > 0 && num_tiles > 0 { let frame = self.swap_chain.get_next_texture(); @@ -740,10 +646,14 @@ impl Painter { app_state.screen.width as f32, app_state.screen.height as f32 ) / 2.0; - for (i, dt) in self.loaded_tiles.values_mut().enumerate() { + for (i, vt) in app_state.visible_tiles().values().enumerate() { + if !vt.is_loaded_to_gpu() { + vt.load_to_gpu(&self.device); + } + let tile_id = vt.tile_id(); let matrix = app_state.screen.tile_to_global_space( app_state.zoom, - &dt.tile_id + &tile_id ); let start = (matrix * &vec).xy() + &vec2(1.0, 1.0); let s = vec2({ @@ -755,7 +665,7 @@ impl Painter { }); let matrix = app_state.screen.tile_to_global_space( app_state.zoom, - &(dt.tile_id + TileId::new(dt.tile_id.z, 1, 1)) + &(tile_id + TileId::new(tile_id.z, 1, 1)) ); let end = (matrix * &vec).xy() + &vec2(1.0, 1.0); let e = vec2({ @@ -772,7 +682,8 @@ impl Painter { (e.x - s.x) as u32, (e.y - s.y) as u32 ); - dt.paint(&mut render_pass, &self.blend_pipeline, &self.noblend_pipeline, &feature_collection, i as u32); + + vt.paint(&mut render_pass, &self.blend_pipeline, &feature_collection, i as u32); } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 91417ad..518e61c 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -134,7 +134,7 @@ fn main() { }, Event::EventsCleared => { painter.update_shader(); - painter.update_styles(app_state.zoom.max(14.0), &mut app_state.css_cache); + app_state.load_tiles(); painter.paint(&mut hud, &mut app_state); app_state.stats.capture_frame(); diff --git a/src/lib/cache.rs b/src/lib/cache.rs index 3e5f4a7..2aa2cb8 100644 --- a/src/lib/cache.rs +++ b/src/lib/cache.rs @@ -26,7 +26,7 @@ pub struct CacheStats { /// A cache structure to hold all loaded `Tile`s. pub struct TileCache { - cache: HashMap, + cache: HashMap>>, loaders: Vec<(u64, JoinHandle>, TileId)>, channel: (Sender, Receiver), id: u64, @@ -58,7 +58,7 @@ impl TileCache { match loader.1.join() { Ok(tile) => { if let Some(tile) = tile { - self.cache.insert(loader.2, tile); + self.cache.insert(loader.2, Arc::new(RwLock::new(tile))); } }, Err(e) => { @@ -119,14 +119,15 @@ impl TileCache { /// /// Returns `None` if the tile is not in the cache. /// The user has to request the loading of the `Tile` on their own. - pub fn try_get_tile(&self, tile_id: &TileId) -> Option<&Tile> { - self.cache.get(&tile_id) + pub fn try_get_tile(&self, tile_id: &TileId) -> Option>> { + self.cache.get(&tile_id).cloned() } pub fn get_stats(&self) -> CacheStats { let mut total_stats = TileStats::new(); for tile in &self.cache { - total_stats = total_stats + *tile.1.stats(); + let read_tile = tile.1.read().unwrap(); + total_stats = total_stats + *read_tile.stats(); } CacheStats { cached_tiles: self.cache.len(), diff --git a/src/lib/drawing/drawable_tile.rs b/src/lib/drawing/drawable_tile.rs deleted file mode 100644 index e182820..0000000 --- a/src/lib/drawing/drawable_tile.rs +++ /dev/null @@ -1,102 +0,0 @@ -use core::ops::Range; -use wgpu::{ - RenderPass, - Buffer, - Device, - RenderPipeline, -}; -use crate::*; - -pub struct DrawableTile { - pub tile_id: TileId, - pub vertex_buffer: Buffer, - pub index_buffer: Buffer, - pub index_count: u32, - pub features: Vec<(u32, Range)>, - pub extent: u16, -} - -impl DrawableTile { - pub fn load_from_tile_id( - device: &Device, - tile_id: TileId, - tile: &Tile, - ) -> DrawableTile { - - DrawableTile { - vertex_buffer: device - .create_buffer_mapped(tile.mesh().vertices.len(), wgpu::BufferUsage::VERTEX) - .fill_from_slice(&tile.mesh().vertices), - index_buffer: device - .create_buffer_mapped(tile.mesh().indices.len(), wgpu::BufferUsage::INDEX) - .fill_from_slice(&tile.mesh().indices), - index_count: tile.mesh().indices.len() as u32, - features: tile.features().clone(), - tile_id, - extent: tile.extent(), - } - } - - pub fn paint( - &mut self, - render_pass: &mut RenderPass, - blend_pipeline: &RenderPipeline, - noblend_pipeline: &RenderPipeline, - feature_collection: &FeatureCollection, - tile_id: u32 - ) { - render_pass.set_index_buffer(&self.index_buffer, 0); - render_pass.set_vertex_buffers(0, &[(&self.vertex_buffer, 0)]); - - let mut alpha_set = vec![]; - let mut opaque_set = vec![]; - - self.features.sort_by(|a, b| { - feature_collection - .get_zindex(a.0) - .partial_cmp(&feature_collection.get_zindex(b.0)).unwrap() - }); - - for (id, range) in &self.features { - if feature_collection.has_alpha(*id) { - alpha_set.push((id, range)); - } else { - opaque_set.push((id, range)); - } - } - - let mut i = 0; - render_pass.set_pipeline(noblend_pipeline); - for (id, range) in opaque_set { - if range.len() > 0 && feature_collection.is_visible(*id) { - render_pass.set_stencil_reference(i as u32); - i += 1; - - let range_start = (tile_id << 1) | 1; - render_pass.draw_indexed(range.clone(), 0, 0 + range_start .. 1 + range_start); - - if feature_collection.has_outline(*id) { - let range_start = tile_id << 1; - render_pass.draw_indexed(range.clone(), 0, 0 + range_start .. 1 + range_start); - } - } - } - - let mut i = 0; - render_pass.set_pipeline(blend_pipeline); - for (id, range) in alpha_set { - if range.len() > 0 && feature_collection.is_visible(*id) { - render_pass.set_stencil_reference(i as u32); - i += 1; - - let range_start = (tile_id << 1) | 1; - render_pass.draw_indexed(range.clone(), 0, 0 + range_start .. 1 + range_start); - - if feature_collection.has_outline(*id) { - let range_start = tile_id << 1; - render_pass.draw_indexed(range.clone(), 0, 0 + range_start .. 1 + range_start); - } - } - } - } -} \ No newline at end of file diff --git a/src/lib/drawing/loaded_gpu_tile.rs b/src/lib/drawing/loaded_gpu_tile.rs new file mode 100644 index 0000000..08fb5e2 --- /dev/null +++ b/src/lib/drawing/loaded_gpu_tile.rs @@ -0,0 +1,24 @@ +use wgpu::*; +use crate::*; + +pub struct LoadedGPUTile { + pub vertex_buffer: Buffer, + pub index_buffer: Buffer, +} + +impl LoadedGPUTile { + pub fn load( + device: &Device, + tile: &Tile, + ) -> Self { + + Self { + vertex_buffer: device + .create_buffer_mapped(tile.mesh().vertices.len(), wgpu::BufferUsage::VERTEX) + .fill_from_slice(&tile.mesh().vertices), + index_buffer: device + .create_buffer_mapped(tile.mesh().indices.len(), wgpu::BufferUsage::INDEX) + .fill_from_slice(&tile.mesh().indices), + } + } +} \ No newline at end of file diff --git a/src/lib/drawing/mod.rs b/src/lib/drawing/mod.rs index 1d2ca16..173c515 100644 --- a/src/lib/drawing/mod.rs +++ b/src/lib/drawing/mod.rs @@ -1,9 +1,9 @@ mod line_tesselator; mod mesh; mod vertex; -mod drawable_tile; +mod loaded_gpu_tile; pub use line_tesselator::*; pub use mesh::*; pub use vertex::*; -pub use drawable_tile::*; \ No newline at end of file +pub use loaded_gpu_tile::*; \ No newline at end of file diff --git a/src/lib/interaction/collider.rs b/src/lib/interaction/collider.rs index dd53108..9633457 100644 --- a/src/lib/interaction/collider.rs +++ b/src/lib/interaction/collider.rs @@ -13,6 +13,7 @@ impl Collider { for tile_id in tile_field.iter() { if let Some(tile) = cache.try_get_tile(&tile_id) { + let read_tile = tile.read().unwrap(); let matrix = screen.tile_to_global_space( zoom, &tile_id @@ -23,12 +24,12 @@ impl Collider { point.1 / (screen.height / 2) as f32 - 1.0 ); let global_point = matrix * Vector4::new(screen_point.x, screen_point.y, 0.0, 1.0); - let tile_point = Point::new(global_point.x, global_point.y) * tile.extent() as f32; + let tile_point = Point::new(global_point.x, global_point.y) * read_tile.extent() as f32; - if tile_point.x >= 0.0 && tile_point.x <= tile.extent() as f32 - && tile_point.y >= 0.0 && tile_point.y <= tile.extent() as f32 { - if let Ok(collider) = tile.collider().try_read() { - if let Ok(objects) = tile.objects().try_read() { + if tile_point.x >= 0.0 && tile_point.x <= read_tile.extent() as f32 + && tile_point.y >= 0.0 && tile_point.y <= read_tile.extent() as f32 { + if let Ok(collider) = read_tile.collider().try_read() { + if let Ok(objects) = read_tile.objects().try_read() { let object_ids = collider.get_hovered_objects(&tile_point); for object_id in object_ids { return_objects.push(objects[object_id].clone()) diff --git a/src/lib/interaction/tile_collider.rs b/src/lib/interaction/tile_collider.rs index 2ee79f7..e3f3c72 100644 --- a/src/lib/interaction/tile_collider.rs +++ b/src/lib/interaction/tile_collider.rs @@ -1,3 +1,10 @@ +use std::{ + sync::{ + Arc, + RwLock, + }, + thread::spawn, +}; use ncollide2d::{ world::{ CollisionWorld, @@ -88,4 +95,31 @@ impl TileCollider { object_ids } +} + +pub trait TileColliderLoader { + fn load(&mut self, tile: Arc>); +} + +impl TileColliderLoader for Arc> { + fn load(&mut self, tile: Arc>) { + let collider_clone = self.clone(); + spawn(move || { + if let Ok(tile) = tile.read() { + if let Ok(objects) = tile.objects().read() { + match collider_clone.write() { + Ok(mut collider) => { + for object_id in 0..objects.len() { + if objects[object_id].points().len() >= 2 { + collider.add_object(object_id, &objects[object_id]); + } + } + collider.update(); + }, + Err(_e) => log::error!("Could not aquire collider lock. Not loading the objects of this tile."), + } + } + } + }); + } } \ No newline at end of file diff --git a/src/lib/vector_tile/mod.rs b/src/lib/vector_tile/mod.rs index de5b419..a8563a8 100644 --- a/src/lib/vector_tile/mod.rs +++ b/src/lib/vector_tile/mod.rs @@ -1,10 +1,12 @@ mod vector_tile; mod tile; mod tile_id; +mod visible_tile; pub use vector_tile::*; pub use tile::*; pub use tile_id::*; +pub use visible_tile::*; use core::ops::Range; use lyon::{ diff --git a/src/lib/vector_tile/tile.rs b/src/lib/vector_tile/tile.rs index 5409711..5afb3ce 100644 --- a/src/lib/vector_tile/tile.rs +++ b/src/lib/vector_tile/tile.rs @@ -218,7 +218,7 @@ impl Tile { let vertex_size = std::mem::size_of::(); let index_size = std::mem::size_of::(); - dbg!(TileStats { + TileStats { objects: objects.len(), features: features.len(), vertices: mesh.vertices.len(), @@ -228,24 +228,24 @@ impl Tile { + features.capacity() * feature_size + mesh.vertices.capacity() * vertex_size + mesh.indices.capacity() * index_size, - }) + } }; - spawn(move|| { - if let Ok(objects) = objects_keep.read() { - match collider_keep.write() { - Ok(mut collider) => { - for object_id in 0..objects.len() { - if objects[object_id].points().len() >= 2 { - collider.add_object(object_id, &objects[object_id]); - } - } - collider.update(); - }, - Err(_e) => log::error!("Could not aquire collider lock. Not loading the objects of this tile."), - } - } - }); + // spawn(move|| { + // if let Ok(objects) = objects_keep.read() { + // match collider_keep.write() { + // Ok(mut collider) => { + // for object_id in 0..objects.len() { + // if objects[object_id].points().len() >= 2 { + // collider.add_object(object_id, &objects[object_id]); + // } + // } + // collider.update(); + // }, + // Err(_e) => log::error!("Could not aquire collider lock. Not loading the objects of this tile."), + // } + // } + // }); Self { tile_id: tile_id.clone(), @@ -282,6 +282,10 @@ impl Tile { &self.stats } + pub fn tile_id(&self) -> TileId { + self.tile_id + } + /// Creates a rectangle the size of a tile to be used as the background of a tile. /// /// Could also display a texture in the future (speak swisstopo). diff --git a/src/lib/vector_tile/visible_tile.rs b/src/lib/vector_tile/visible_tile.rs new file mode 100644 index 0000000..9bde252 --- /dev/null +++ b/src/lib/vector_tile/visible_tile.rs @@ -0,0 +1,92 @@ +use std::sync::{ + Arc, + RwLock, +}; + +use wgpu::*; + +use crate::*; + +pub struct VisibleTile { + tile: Arc>, + gpu_tile: Arc>>, + tile_collider: Arc>, +} + +impl VisibleTile { + pub fn new(tile: Arc>) -> Self { + Self { + tile: tile, + gpu_tile: Arc::new(RwLock::new(None)), + tile_collider: Arc::new(RwLock::new(TileCollider::new())), + } + } + + pub fn tile_id(&self) -> TileId { + self.tile.read().unwrap().tile_id() + } + + pub fn extent(&self) -> u16 { + self.tile.read().unwrap().extent() + } + + pub fn load_to_gpu(&self, device: &Device) { + let read_tile = self.tile.read().unwrap(); + let mut write_gpu_tile = self.gpu_tile.write().unwrap(); + *write_gpu_tile = Some(LoadedGPUTile::load(device, &read_tile)); + } + + pub fn unload_from_gpu(&self) { + let mut write_gpu_tile = self.gpu_tile.write().unwrap(); + *write_gpu_tile = None; + } + + pub fn is_loaded_to_gpu(&self) -> bool { + self.gpu_tile.read().unwrap().is_some() + } + + pub fn load_collider(&mut self) { + self.tile_collider.load(self.tile.clone()); + } + + pub fn paint( + &self, + render_pass: &mut RenderPass, + blend_pipeline: &RenderPipeline, + feature_collection: &FeatureCollection, + tile_id: u32 + ) { + if let Some(data) = self.gpu_tile.try_read().unwrap().as_ref() { + render_pass.set_index_buffer(&data.index_buffer, 0); + render_pass.set_vertex_buffers(0, &[(&data.vertex_buffer, 0)]); + + let features = { + let read_tile = self.tile.read().unwrap(); + let mut features = read_tile.features().clone(); + features.sort_by(|a, b| { + feature_collection + .get_zindex(a.0) + .partial_cmp(&feature_collection.get_zindex(b.0)).unwrap() + }); + features + }; + + let mut i = 0; + render_pass.set_pipeline(blend_pipeline); + for (id, range) in &features { + if range.len() > 0 && feature_collection.is_visible(*id) { + render_pass.set_stencil_reference(i as u32); + i += 1; + + let range_start = (tile_id << 1) | 1; + render_pass.draw_indexed(range.clone(), 0, 0 + range_start .. 1 + range_start); + + if feature_collection.has_outline(*id) { + let range_start = tile_id << 1; + render_pass.draw_indexed(range.clone(), 0, 0 + range_start .. 1 + range_start); + } + } + } + } + } +} \ No newline at end of file