maplibre/render/tile_view_pattern/
mod.rs1mod pattern;
4
5use std::{marker::PhantomData, mem::size_of, ops::Range};
6
7use cgmath::Matrix4;
8pub use pattern::{TileViewPattern, DEFAULT_TILE_VIEW_PATTERN_SIZE};
9
10use crate::{
11 coords::{WorldTileCoords, Zoom},
12 render::shaders::ShaderTileMetadata,
13 tcs::{resources::ResourceQuery, world::World},
14};
15
16pub type WgpuTileViewPattern = TileViewPattern<wgpu::Queue, wgpu::Buffer>;
17
18pub const DEFAULT_TILE_SIZE: f64 = 512.0;
23
24#[derive(Debug, Clone)]
30pub enum SourceShapes {
31 Parent(TileShape),
33 Children(Vec<TileShape>),
35 SourceEqTarget(TileShape),
38 None,
40}
41
42#[derive(Debug, Clone)]
44pub struct ViewTile {
45 target: WorldTileCoords,
46 source: SourceShapes,
47}
48
49impl ViewTile {
50 pub fn coords(&self) -> WorldTileCoords {
51 self.target
52 }
53
54 pub fn render<F>(&self, mut callback: F)
55 where
56 F: FnMut(&TileShape),
57 {
58 match &self.source {
59 SourceShapes::Parent(source_shape) => callback(source_shape),
60 SourceShapes::Children(source_shapes) => {
61 for shape in source_shapes {
62 callback(shape)
63 }
64 }
65 SourceShapes::SourceEqTarget(source_shape) => callback(source_shape),
66 SourceShapes::None => {}
67 }
68 }
69}
70
71#[derive(Debug, Clone)]
74pub struct TileShape {
75 coords: WorldTileCoords,
76
77 zoom_factor: f64,
79 transform: Matrix4<f64>,
80
81 buffer_range: Option<Range<wgpu::BufferAddress>>,
82}
83
84impl TileShape {
85 fn new(coords: WorldTileCoords, zoom: Zoom) -> Self {
86 Self {
87 coords,
88 zoom_factor: zoom.scale_to_tile(&coords),
89 transform: coords.transform_for_zoom(zoom),
90 buffer_range: None,
91 }
92 }
93
94 fn set_buffer_range(&mut self, index: u64) {
95 const STRIDE: u64 = size_of::<ShaderTileMetadata>() as u64;
96 self.buffer_range = Some(index * STRIDE..(index + 1) * STRIDE);
97 }
98
99 pub fn buffer_range(&self) -> Option<Range<wgpu::BufferAddress>> {
100 self.buffer_range.clone()
101 }
102
103 pub fn coords(&self) -> WorldTileCoords {
104 self.coords
105 }
106}
107
108impl Default for TileShape {
109 fn default() -> Self {
110 Self::new(
111 crate::coords::WorldTileCoords::default(),
112 crate::coords::Zoom::default(),
113 )
114 }
115}
116
117pub trait HasTile {
118 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool;
119
120 fn get_available_parent(
121 &self,
122 coords: WorldTileCoords,
123 world: &World,
124 ) -> Option<WorldTileCoords> {
125 let mut current = coords;
126 loop {
127 if self.has_tile(current, world) {
128 return Some(current);
129 } else if let Some(parent) = current.get_parent() {
130 current = parent
131 } else {
132 return None;
133 }
134 }
135 }
136
137 fn get_available_children(
138 &self,
139 coords: WorldTileCoords,
140 world: &World,
141 search_depth: usize,
142 ) -> Option<Vec<WorldTileCoords>> {
143 let mut children = coords.get_children().to_vec();
144
145 let mut output = Vec::new();
146
147 for _ in 0..search_depth {
148 let mut new_children = Vec::with_capacity(children.len() * 4);
149
150 for child in children {
151 if self.has_tile(child, world) {
152 output.push(child);
153 } else {
154 new_children.extend(child.get_children())
155 }
156 }
157
158 children = new_children;
159 }
160
161 Some(output)
162 }
163}
164
165impl<A: HasTile> HasTile for &A {
166 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
167 A::has_tile(*self, coords, world)
168 }
169}
170
171impl<A: HasTile> HasTile for (A,) {
172 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
173 self.0.has_tile(coords, world)
174 }
175}
176
177impl<A: HasTile, B: HasTile> HasTile for (A, B) {
178 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
179 self.0.has_tile(coords, world) && self.1.has_tile(coords, world)
180 }
181}
182
183impl<A: HasTile, B: HasTile, C: HasTile> HasTile for (A, B, C) {
184 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
185 self.0.has_tile(coords, world)
186 && self.1.has_tile(coords, world)
187 && self.2.has_tile(coords, world)
188 }
189}
190
191pub struct QueryHasTile<Q> {
192 phantom_q: PhantomData<Q>,
193}
194
195impl<Q: ResourceQuery> Default for QueryHasTile<Q> {
196 fn default() -> Self {
197 Self {
198 phantom_q: Default::default(),
199 }
200 }
201}
202
203impl<Q: ResourceQuery> HasTile for QueryHasTile<Q>
204where
205 for<'a> Q::Item<'a>: HasTile,
206{
207 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
208 let resources = world
209 .resources
210 .query::<Q>()
211 .expect("resource not found for has_tile check");
212
213 resources.has_tile(coords, world)
214 }
215}
216
217#[derive(Default)]
218pub struct ViewTileSources {
219 items: Vec<Box<dyn HasTile>>,
220}
221
222impl ViewTileSources {
223 pub fn add<H: HasTile + 'static + Default>(&mut self) -> &mut Self {
224 self.items.push(Box::<H>::default());
225 self
226 }
227
228 pub fn add_resource_query<Q: ResourceQuery + 'static>(&mut self) -> &mut Self
229 where
230 for<'a> Q::Item<'a>: HasTile,
231 {
232 self.items.push(Box::new(QueryHasTile::<Q>::default()));
233 self
234 }
235
236 pub fn clear(&mut self) {
237 self.items.clear()
238 }
239}
240
241impl HasTile for ViewTileSources {
242 fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
243 self.items.iter().all(|item| item.has_tile(coords, world))
244 }
245}