mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Tesselate layers instead of tiles
This commit is contained in:
parent
cb76b75eb0
commit
635df81f1c
@ -6,23 +6,24 @@ use log::{error, info};
|
||||
|
||||
use crate::coords::TileCoords;
|
||||
use vector_tile::parse_tile_bytes;
|
||||
use vector_tile::tile::{Feature, Layer, Tile};
|
||||
|
||||
use crate::io::web_tile_fetcher::WebTileFetcher;
|
||||
use crate::io::{HttpFetcherConfig, TileFetcher};
|
||||
use crate::render::ShaderVertex;
|
||||
use crate::tesselation::{IndexDataType, OverAlignedVertexBuffer, Tesselated};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TesselatedTile {
|
||||
pub id: u32,
|
||||
pub struct TesselatedLayer {
|
||||
pub coords: TileCoords,
|
||||
pub over_aligned: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||
pub buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||
pub feature_vertices: Vec<u32>,
|
||||
pub layer_data: Layer,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WorkerLoop {
|
||||
requests: Arc<WorkQueue<TileCoords>>,
|
||||
responses: Arc<WorkQueue<TesselatedTile>>,
|
||||
responses: Arc<WorkQueue<TesselatedLayer>>,
|
||||
}
|
||||
|
||||
impl Drop for WorkerLoop {
|
||||
@ -44,7 +45,7 @@ impl WorkerLoop {
|
||||
self.requests.push(coords);
|
||||
}
|
||||
|
||||
pub fn pop_all(&self) -> Vec<TesselatedTile> {
|
||||
pub fn pop_all(&self) -> Vec<TesselatedLayer> {
|
||||
self.responses.try_pop_all()
|
||||
}
|
||||
|
||||
@ -54,7 +55,6 @@ impl WorkerLoop {
|
||||
});
|
||||
// let fetcher = StaticTileFetcher::new();
|
||||
|
||||
let mut current_id = 0;
|
||||
loop {
|
||||
while let Some(coords) = self.requests.pop() {
|
||||
match fetcher.fetch_tile(&coords).await {
|
||||
@ -63,13 +63,20 @@ impl WorkerLoop {
|
||||
let tile = parse_tile_bytes(bytemuck::cast_slice(data.as_slice()))
|
||||
.expect("failed to load tile");
|
||||
|
||||
let buffer = tile.tesselate_stroke();
|
||||
self.responses.push(TesselatedTile {
|
||||
id: current_id,
|
||||
coords,
|
||||
over_aligned: buffer.into(),
|
||||
});
|
||||
current_id += 1;
|
||||
for layer in tile.layers() {
|
||||
if let Some((buffer, feature_vertices)) = layer.tesselate() {
|
||||
if buffer.indices.is_empty() {
|
||||
continue;
|
||||
}
|
||||
self.responses.push(TesselatedLayer {
|
||||
coords,
|
||||
buffer: buffer.into(),
|
||||
feature_vertices,
|
||||
layer_data: layer.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
info!("tile ready: {:?}", &coords);
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
101
src/tesselation/layer.rs
Normal file
101
src/tesselation/layer.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Add;
|
||||
|
||||
use bytemuck::Pod;
|
||||
use log::info;
|
||||
use lyon::lyon_tessellation::VertexBuffers;
|
||||
use lyon::tessellation::geometry_builder::MaxIndex;
|
||||
use lyon::tessellation::{
|
||||
BuffersBuilder, FillOptions, FillTessellator, StrokeOptions, StrokeTessellator,
|
||||
};
|
||||
use lyon_path::traits::SvgPathBuilder;
|
||||
use lyon_path::Path;
|
||||
|
||||
use vector_tile::geometry::{Command, Geometry};
|
||||
use vector_tile::tile::{Feature, Layer, Tile};
|
||||
|
||||
use crate::render::ShaderVertex;
|
||||
use crate::tesselation::{Tesselated, VertexConstructor, DEFAULT_TOLERANCE};
|
||||
|
||||
impl<I: Add + From<lyon::lyon_tessellation::VertexId> + MaxIndex + Pod> Tesselated<I> for Layer {
|
||||
fn tesselate(&self) -> Option<(VertexBuffers<ShaderVertex, I>, Vec<u32>)> {
|
||||
let mut buffer: VertexBuffers<ShaderVertex, I> = VertexBuffers::new();
|
||||
let mut feature_vertices: Vec<u32> = Vec::new();
|
||||
let mut last = 0;
|
||||
info!("features: {}", self.features().len());
|
||||
for feature in self.features() {
|
||||
match feature.geometry() {
|
||||
Geometry::GeometryPolygon(polygon) => {
|
||||
let mut tile_builder = Path::builder().with_svg();
|
||||
for command in &polygon.commands {
|
||||
match command {
|
||||
Command::MoveTo(cmd) => {
|
||||
tile_builder.relative_move_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
}
|
||||
Command::LineTo(cmd) => {
|
||||
tile_builder.relative_line_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
}
|
||||
Command::Close => {
|
||||
tile_builder.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut tesselator = FillTessellator::new();
|
||||
tesselator
|
||||
.tessellate_path(
|
||||
&tile_builder.build(),
|
||||
&FillOptions::tolerance(DEFAULT_TOLERANCE),
|
||||
&mut BuffersBuilder::new(&mut buffer, VertexConstructor {}),
|
||||
)
|
||||
.ok()?;
|
||||
}
|
||||
Geometry::GeometryLineString(polygon) => {
|
||||
let mut tile_builder = Path::builder().with_svg();
|
||||
for command in &polygon.commands {
|
||||
match command {
|
||||
Command::MoveTo(cmd) => {
|
||||
tile_builder.relative_move_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
}
|
||||
Command::LineTo(cmd) => {
|
||||
tile_builder.relative_line_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
}
|
||||
Command::Close => {
|
||||
panic!("error")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut tesselator = StrokeTessellator::new();
|
||||
|
||||
tesselator
|
||||
.tessellate_path(
|
||||
&tile_builder.build(),
|
||||
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
|
||||
&mut BuffersBuilder::new(&mut buffer, VertexConstructor {}),
|
||||
)
|
||||
.ok()?;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let new_length = buffer.indices.len();
|
||||
feature_vertices.push((new_length - last) as u32);
|
||||
last = new_length;
|
||||
}
|
||||
|
||||
Some((buffer, feature_vertices))
|
||||
}
|
||||
}
|
||||
@ -7,24 +7,20 @@ use crate::render::ShaderVertex;
|
||||
use lyon::tessellation::{
|
||||
FillVertex, FillVertexConstructor, StrokeVertex, StrokeVertexConstructor, VertexBuffers,
|
||||
};
|
||||
use lyon_path::Path;
|
||||
use wgpu::BufferAddress;
|
||||
|
||||
pub mod tile;
|
||||
mod layer;
|
||||
|
||||
const DEFAULT_TOLERANCE: f32 = 0.02;
|
||||
|
||||
pub type IndexDataType = u16; // Must match INDEX_FORMAT
|
||||
|
||||
pub trait Tesselated<I: Add> {
|
||||
fn tesselate_stroke(&self) -> VertexBuffers<ShaderVertex, I>;
|
||||
fn tesselate_fill(&self) -> VertexBuffers<ShaderVertex, I>;
|
||||
|
||||
fn empty_range(&self) -> VertexBuffers<ShaderVertex, I> {
|
||||
VertexBuffers::new()
|
||||
}
|
||||
fn tesselate(&self) -> Option<(VertexBuffers<ShaderVertex, I>, Vec<u32>)>;
|
||||
}
|
||||
|
||||
pub struct VertexConstructor();
|
||||
pub struct VertexConstructor {}
|
||||
|
||||
impl FillVertexConstructor<ShaderVertex> for VertexConstructor {
|
||||
fn new_vertex(&mut self, vertex: FillVertex) -> ShaderVertex {
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use bytemuck::Pod;
|
||||
|
||||
use lyon::tessellation::geometry_builder::MaxIndex;
|
||||
use lyon::tessellation::{
|
||||
BuffersBuilder, FillOptions, FillTessellator, StrokeOptions, StrokeTessellator, VertexBuffers,
|
||||
};
|
||||
use lyon_path::builder::SvgPathBuilder;
|
||||
use lyon_path::Path;
|
||||
|
||||
use crate::render::ShaderVertex;
|
||||
use vector_tile::geometry::{Command, Geometry};
|
||||
use vector_tile::tile::Tile;
|
||||
|
||||
use crate::tesselation::{Tesselated, VertexConstructor, DEFAULT_TOLERANCE};
|
||||
|
||||
fn build_path(tile: &Tile, fill: bool) -> Path {
|
||||
let mut tile_builder = Path::builder().with_svg();
|
||||
|
||||
for layer in tile.layers() {
|
||||
if layer.name() != "transportation" {
|
||||
continue;
|
||||
}
|
||||
|
||||
for feature in layer.features() {
|
||||
let geo = feature.geometry();
|
||||
|
||||
match geo {
|
||||
Geometry::GeometryPolygon(polygon) => {
|
||||
for command in &polygon.commands {
|
||||
match command {
|
||||
Command::MoveTo(cmd) => {
|
||||
tile_builder.relative_move_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
}
|
||||
Command::LineTo(cmd) => {
|
||||
tile_builder.relative_line_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
}
|
||||
Command::Close => {
|
||||
tile_builder.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Geometry::GeometryLineString(polygon) => {
|
||||
if !fill {
|
||||
for command in &polygon.commands {
|
||||
match command {
|
||||
Command::MoveTo(cmd) => {
|
||||
tile_builder.relative_move_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
|
||||
//print!("M{} {} ", cmd.x, cmd.y);
|
||||
}
|
||||
Command::LineTo(cmd) => {
|
||||
tile_builder.relative_line_to(lyon_path::math::vector(
|
||||
cmd.x as f32,
|
||||
cmd.y as f32,
|
||||
));
|
||||
|
||||
//print!("l{} {} ", cmd.x, cmd.y);
|
||||
}
|
||||
Command::Close => {
|
||||
panic!("error")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
tile_builder.move_to(lyon_path::math::point(0.0, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
tile_builder.build()
|
||||
}
|
||||
|
||||
impl<I: Add + From<lyon::lyon_tessellation::VertexId> + MaxIndex + Pod> Tesselated<I> for Tile {
|
||||
fn tesselate_stroke(&self) -> VertexBuffers<ShaderVertex, I> {
|
||||
let mut buffer: VertexBuffers<ShaderVertex, I> = VertexBuffers::new();
|
||||
let mut tesselator = StrokeTessellator::new();
|
||||
|
||||
let tile_path = build_path(self, false);
|
||||
|
||||
tesselator
|
||||
.tessellate_path(
|
||||
&tile_path,
|
||||
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
|
||||
&mut BuffersBuilder::new(&mut buffer, VertexConstructor()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
fn tesselate_fill(&self) -> VertexBuffers<ShaderVertex, I> {
|
||||
let mut buffer: VertexBuffers<ShaderVertex, I> = VertexBuffers::new();
|
||||
let mut tesselator = FillTessellator::new();
|
||||
|
||||
let tile_path = build_path(self, true);
|
||||
|
||||
tesselator
|
||||
.tessellate_path(
|
||||
&tile_path,
|
||||
&FillOptions::tolerance(DEFAULT_TOLERANCE),
|
||||
&mut BuffersBuilder::new(&mut buffer, VertexConstructor()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buffer
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user