maplibre/sdf/
mod.rs

1use std::{
2    marker::PhantomData,
3    ops::{Deref, Range},
4    rc::Rc,
5};
6
7use crate::{
8    coords::WorldTileCoords,
9    environment::Environment,
10    euclid::{Box2D, Point2D},
11    kernel::Kernel,
12    legacy::TileSpace,
13    plugin::Plugin,
14    render::{
15        eventually::Eventually,
16        graph::RenderGraph,
17        shaders::{
18            SDFShaderFeatureMetadata, ShaderLayerMetadata, ShaderSymbolVertex,
19            ShaderSymbolVertexNew,
20        },
21        RenderStageLabel,
22    },
23    schedule::Schedule,
24    sdf::resource::GlyphTexture,
25    tcs::{system::SystemContainer, tiles::TileComponent, world::World},
26    vector::{
27        resource::BufferPool,
28        tessellation::{IndexDataType, OverAlignedVertexBuffer},
29        VectorTransferables,
30    },
31};
32
33pub mod collision_system;
34mod populate_world_system;
35mod queue_system;
36mod render_commands;
37mod resource;
38mod resource_system;
39mod upload_system;
40
41pub mod tessellation;
42pub mod tessellation_new;
43pub mod text;
44
45struct SymbolPipeline(wgpu::RenderPipeline);
46
47impl Deref for SymbolPipeline {
48    type Target = wgpu::RenderPipeline;
49
50    fn deref(&self) -> &Self::Target {
51        &self.0
52    }
53}
54
55pub type SymbolBufferPool = BufferPool<
56    wgpu::Queue,
57    wgpu::Buffer,
58    ShaderSymbolVertexNew,
59    IndexDataType,
60    ShaderLayerMetadata,
61    SDFShaderFeatureMetadata,
62>;
63
64pub struct SdfPlugin<T>(PhantomData<T>);
65
66impl<T: VectorTransferables> Default for SdfPlugin<T> {
67    fn default() -> Self {
68        Self(Default::default())
69    }
70}
71
72impl<E: Environment, T: VectorTransferables> Plugin<E> for SdfPlugin<T> {
73    fn build(
74        &self,
75        schedule: &mut Schedule,
76        kernel: Rc<Kernel<E>>,
77        world: &mut World,
78        _graph: &mut RenderGraph,
79    ) {
80        let resources = &mut world.resources;
81
82        resources.insert(Eventually::<SymbolPipeline>::Uninitialized);
83        resources.insert(Eventually::<SymbolBufferPool>::Uninitialized);
84        resources.insert(Eventually::<GlyphTexture>::Uninitialized);
85        resources.insert(Eventually::<(wgpu::Texture, wgpu::Sampler)>::Uninitialized);
86
87        schedule.add_system_to_stage(
88            RenderStageLabel::Extract,
89            SystemContainer::new(populate_world_system::PopulateWorldSystem::<E, T>::new(
90                &kernel,
91            )),
92        );
93
94        schedule.add_system_to_stage(RenderStageLabel::Prepare, resource_system::resource_system);
95        schedule.add_system_to_stage(RenderStageLabel::Queue, upload_system::upload_system); // FIXME tcs: Upload updates the TileView in tileviewpattern -> upload most run before prepare
96        schedule.add_system_to_stage(RenderStageLabel::Queue, queue_system::queue_system);
97
98        schedule.add_system_to_stage(
99            RenderStageLabel::PhaseSort,
100            SystemContainer::new(collision_system::CollisionSystem::new()),
101        );
102    }
103}
104
105pub struct Feature {
106    pub bbox: Box2D<f32, TileSpace>,
107    pub indices: Range<usize>,
108    pub text_anchor: Point2D<f32, TileSpace>,
109    pub str: String,
110}
111
112pub struct SymbolLayerData {
113    pub coords: WorldTileCoords,
114    pub source_layer: String,
115    pub style_layer_id: String,
116    pub buffer: OverAlignedVertexBuffer<ShaderSymbolVertex, IndexDataType>,
117    pub new_buffer: OverAlignedVertexBuffer<ShaderSymbolVertexNew, IndexDataType>, // TODO
118    pub features: Vec<Feature>,
119}
120
121#[derive(Default)]
122pub struct SymbolLayersDataComponent {
123    pub layers: Vec<SymbolLayerData>,
124}
125
126impl TileComponent for SymbolLayersDataComponent {}
127
128#[cfg(test)]
129mod tests {
130    use std::collections::HashMap;
131
132    use crate::{
133        euclid::{Point2D, Rect, Size2D},
134        legacy::{
135            bidi::Char16,
136            font_stack::FontStackHasher,
137            geometry_tile_data::{GeometryCoordinates, SymbolGeometryTileLayer},
138            glyph::{Glyph, GlyphDependencies, GlyphMap, GlyphMetrics, Glyphs},
139            glyph_atlas::{GlyphPosition, GlyphPositionMap, GlyphPositions},
140            image::ImageMap,
141            image_atlas::ImagePositions,
142            layout::{
143                layout::{BucketParameters, LayerTypeInfo, LayoutParameters},
144                symbol_feature::{SymbolGeometryTileFeature, VectorGeometryTileFeature},
145                symbol_layout::{FeatureIndex, LayerProperties, SymbolLayer, SymbolLayout},
146            },
147            style_types::SymbolLayoutProperties_Unevaluated,
148            CanonicalTileID, MapMode, OverscaledTileID,
149        },
150    };
151
152    #[test]
153    fn test() {
154        let fontStack = vec![
155            "Open Sans Regular".to_string(),
156            "Arial Unicode MS Regular".to_string(),
157        ];
158
159        let mut glyphDependencies = GlyphDependencies::new();
160
161        let tile_id = OverscaledTileID {
162            canonical: CanonicalTileID { x: 0, y: 0, z: 0 },
163            overscaled_z: 0,
164        };
165        let mut parameters = BucketParameters {
166            tile_id: tile_id,
167            mode: MapMode::Continuous,
168            pixel_ratio: 1.0,
169            layer_type: LayerTypeInfo,
170        };
171        let mut layout = SymbolLayout::new(
172            &parameters,
173            &vec![LayerProperties {
174                id: "layer".to_string(),
175                layer: SymbolLayer {
176                    layout: SymbolLayoutProperties_Unevaluated,
177                },
178            }],
179            Box::new(SymbolGeometryTileLayer {
180                name: "layer".to_string(),
181                features: vec![SymbolGeometryTileFeature::new(Box::new(
182                    VectorGeometryTileFeature {
183                        geometry: vec![GeometryCoordinates(vec![Point2D::new(1024, 1024)])],
184                    },
185                ))],
186            }),
187            &mut LayoutParameters {
188                bucket_parameters: &mut parameters.clone(),
189                glyph_dependencies: &mut glyphDependencies,
190                image_dependencies: &mut Default::default(),
191                available_images: &mut Default::default(),
192            },
193        )
194        .unwrap();
195
196        assert_eq!(glyphDependencies.len(), 1);
197
198        // Now we prepare the data, when we have the glyphs available
199
200        let image_positions = ImagePositions::new();
201
202        let mut glyphPosition = GlyphPosition {
203            rect: Rect::new(Point2D::new(0, 0), Size2D::new(10, 10)),
204            metrics: GlyphMetrics {
205                width: 18,
206                height: 18,
207                left: 2,
208                top: -8,
209                advance: 21,
210            },
211        };
212        let glyphPositions: GlyphPositions = GlyphPositions::from([(
213            FontStackHasher::new(&fontStack),
214            GlyphPositionMap::from([('中' as Char16, glyphPosition)]),
215        )]);
216
217        let mut glyph = Glyph::default();
218        glyph.id = '中' as Char16;
219        glyph.metrics = glyphPosition.metrics;
220
221        let glyphs: GlyphMap = GlyphMap::from([(
222            FontStackHasher::new(&fontStack),
223            Glyphs::from([('中' as Char16, Some(glyph))]),
224        )]);
225
226        let empty_image_map = ImageMap::new();
227        layout.prepare_symbols(&glyphs, &glyphPositions, &empty_image_map, &image_positions);
228
229        let mut output = HashMap::new();
230        layout.create_bucket(
231            image_positions,
232            Box::new(FeatureIndex),
233            &mut output,
234            false,
235            false,
236            &tile_id.canonical,
237        );
238
239        println!("{:#?}", output)
240    }
241}