maplibre/vector/
upload_system.rs1use crate::{
4 context::MapContext,
5 coords::ViewRegion,
6 render::{
7 eventually::{Eventually, Eventually::Initialized},
8 shaders::{FillShaderFeatureMetadata, ShaderLayerMetadata, Vec4f32},
9 tile_view_pattern::DEFAULT_TILE_SIZE,
10 view_state::ViewStatePadding,
11 Renderer,
12 },
13 style::{layer::LayerPaint, Style},
14 tcs::{
15 system::{SystemError, SystemResult},
16 tiles::Tiles,
17 },
18 vector::{
19 AvailableVectorLayerBucket, VectorBufferPool, VectorLayerBucket, VectorLayerBucketComponent,
20 },
21};
22
23pub fn upload_system(
24 MapContext {
25 world,
26 style,
27 view_state,
28 renderer: Renderer { device, queue, .. },
29 ..
30 }: &mut MapContext,
31) -> SystemResult {
32 let Some(Initialized(buffer_pool)) = world
33 .resources
34 .query_mut::<&mut Eventually<VectorBufferPool>>()
35 else {
36 return Err(SystemError::Dependencies);
37 };
38
39 let view_region = view_state.create_view_region(
40 view_state.zoom().zoom_level(DEFAULT_TILE_SIZE),
41 ViewStatePadding::Loose,
42 );
43
44 let zoom = view_state.zoom().level();
45
46 if let Some(view_region) = &view_region {
47 upload_tessellated_layer(
48 buffer_pool,
49 device,
50 queue,
51 &mut world.tiles,
52 style,
53 view_region,
54 zoom,
55 );
56 }
57
58 Ok(())
59}
60
61fn upload_tessellated_layer(
62 buffer_pool: &mut VectorBufferPool,
63 _device: &wgpu::Device,
64 queue: &wgpu::Queue,
65 tiles: &mut Tiles,
66 style: &Style,
67 view_region: &ViewRegion,
68 zoom: f32,
69) {
70 for coords in view_region.iter() {
72 let Some(vector_layers) = tiles.query_mut::<&VectorLayerBucketComponent>(coords) else {
73 continue;
74 };
75
76 let loaded_layers = buffer_pool
77 .get_loaded_style_layers_at(coords)
78 .unwrap_or_default();
79
80 let available_layers = vector_layers
81 .layers
82 .iter()
83 .flat_map(|data| match data {
84 VectorLayerBucket::AvailableLayer(data) => Some(data),
85 VectorLayerBucket::Missing(_) => None,
86 })
87 .filter(|data| !loaded_layers.contains(data.style_layer_id.as_str()))
88 .collect::<Vec<_>>();
89
90 for style_layer in &style.layers {
91 let layer_id = &style_layer.id;
92 let source_layer = match style_layer.source_layer.as_ref() {
95 Some(layer) => layer.as_str(),
96 None => {
97 log::trace!("style layer {layer_id} has no source_layer, using id as virtual source layer");
98 style_layer.id.as_str()
99 }
100 };
101
102 let Some(AvailableVectorLayerBucket {
103 coords,
104 feature_indices,
105 feature_colors,
106 buffer,
107 ..
108 }) = available_layers
109 .iter()
110 .find(|layer| style_layer.id.as_str() == layer.style_layer_id.as_str())
111 else {
112 continue;
113 };
114
115 let color: Option<Vec4f32> = style_layer
116 .paint
117 .as_ref()
118 .and_then(|paint| paint.get_color())
119 .map(|color| color.into());
120
121 let fallback_color = color.unwrap_or([0.0, 0.0, 0.0, 1.0]);
123
124 let mut feature_metadata =
125 Vec::with_capacity(feature_indices.iter().sum::<u32>() as usize);
126 for (idx, &count) in feature_indices.iter().enumerate() {
127 let current_color = feature_colors.get(idx).copied().unwrap_or(fallback_color);
128 for _ in 0..count {
129 feature_metadata.push(FillShaderFeatureMetadata {
130 color: current_color,
131 });
132 }
133 }
134
135 if buffer.buffer.indices.is_empty() {
137 continue;
138 }
139
140 let line_width = match &style_layer.paint {
142 Some(LayerPaint::Line(paint)) => paint
143 .line_width
144 .as_ref()
145 .map(|w| w.evaluate_at_zoom(zoom))
146 .unwrap_or(1.0),
147 _ => 1.0,
148 };
149
150 log::debug!("Allocating geometry at {coords}");
151 buffer_pool.allocate_layer_geometry(
152 queue,
153 *coords,
154 style_layer.clone(),
155 buffer,
156 ShaderLayerMetadata {
157 z_index: style_layer.index as f32,
158 line_width,
159 },
160 &feature_metadata,
161 );
162 }
163 }
164}