mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Draw very first tile
This commit is contained in:
parent
a788c14d7a
commit
4bca568f6e
1180
Cargo.lock
generated
1180
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
20
Cargo.toml
@ -9,21 +9,27 @@ resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Wanted by lyon experiment
|
||||
# Futures
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures = "0.3.5"
|
||||
bytemuck = "1.2.0"
|
||||
pollster = "0.2"
|
||||
|
||||
# Wanted by lyon experiment
|
||||
|
||||
|
||||
# Vector riles
|
||||
mvt = { path = "libs/mvt" }
|
||||
vector-tile = { path = "libs/vector_tile" }
|
||||
geo = "0.18.0"
|
||||
geo-types = "0.7"
|
||||
proj = "0.24"
|
||||
mbutiles = "0.1.1"
|
||||
|
||||
# Rendering
|
||||
winit = "0.25"
|
||||
wgpu = "0.11"
|
||||
pollster = "0.2"
|
||||
lyon = { version = "0.17", features = ["extra"] }
|
||||
lyon_path = "0.17"
|
||||
# https://docs.rs/euclid/0.22.6/euclid/index.html
|
||||
|
||||
# Logging
|
||||
@ -32,6 +38,10 @@ env_logger = "0.9"
|
||||
|
||||
# Utils
|
||||
hexdump = "0.1"
|
||||
bytemuck = "1.2.0"
|
||||
|
||||
# Network
|
||||
reqwest = { version = "0.11", features = ["gzip"] }
|
||||
|
||||
# Serialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
@ -52,3 +62,7 @@ path = "src/main.rs"
|
||||
[[bin]]
|
||||
name = "lyon_test"
|
||||
path = "src/lyon_test/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "download_tiles"
|
||||
path = "src/lyon_test/tile_downloader.rs"
|
||||
|
||||
@ -1,14 +1,8 @@
|
||||
use std::ops::Rem;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use futures::executor::block_on;
|
||||
use lyon::extra::rust_logo::build_logo_path;
|
||||
use lyon::math::*;
|
||||
use lyon::path::Path;
|
||||
use lyon::tessellation;
|
||||
use lyon::tessellation::geometry_builder::*;
|
||||
use lyon::tessellation::{FillOptions, FillTessellator};
|
||||
use lyon::tessellation::{StrokeOptions, StrokeTessellator};
|
||||
use lyon::tessellation::VertexBuffers;
|
||||
use vector_tile::parse_tile;
|
||||
use wgpu::util::DeviceExt;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::window::Window;
|
||||
@ -20,11 +14,14 @@ use crate::shader::{
|
||||
create_vertex_module_descriptor,
|
||||
};
|
||||
use crate::shader_ffi::*;
|
||||
use crate::tesselation::{RustLogo, Tesselated};
|
||||
|
||||
mod piplines;
|
||||
mod scene;
|
||||
mod shader;
|
||||
mod shader_ffi;
|
||||
mod tesselation;
|
||||
mod tile_downloader;
|
||||
|
||||
const PRIM_BUFFER_LEN: usize = 256;
|
||||
|
||||
@ -69,102 +66,50 @@ fn main() {
|
||||
let sample_count = 4;
|
||||
|
||||
let num_instances: u32 = 1;
|
||||
let tolerance = 0.02;
|
||||
|
||||
let stroke_prim_id = 0;
|
||||
let fill_prim_id = 1;
|
||||
let arrows_prim_id = num_instances + 1;
|
||||
|
||||
let mut geometry: VertexBuffers<GpuVertex, u16> = VertexBuffers::new();
|
||||
|
||||
let mut fill_tess = FillTessellator::new();
|
||||
let mut stroke_tess = StrokeTessellator::new();
|
||||
|
||||
// Build a Path for the rust logo.
|
||||
let mut builder = Path::builder().with_svg();
|
||||
build_logo_path(&mut builder);
|
||||
let path = builder.build();
|
||||
|
||||
// Build a Path for the arrow.
|
||||
let mut builder = Path::builder();
|
||||
builder.begin(point(-1.0, -0.3));
|
||||
builder.line_to(point(0.0, -0.3));
|
||||
builder.line_to(point(0.0, -1.0));
|
||||
builder.line_to(point(1.5, 0.0));
|
||||
builder.line_to(point(0.0, 1.0));
|
||||
builder.line_to(point(0.0, 0.3));
|
||||
builder.line_to(point(-1.0, 0.3));
|
||||
builder.close();
|
||||
let arrow_path = builder.build();
|
||||
|
||||
fill_tess
|
||||
.tessellate_path(
|
||||
&path,
|
||||
&FillOptions::tolerance(tolerance).with_fill_rule(tessellation::FillRule::NonZero),
|
||||
&mut BuffersBuilder::new(&mut geometry, WithId(fill_prim_id as u32)),
|
||||
let (stroke_range, fill_range) = if true {
|
||||
let tile =
|
||||
parse_tile("test-data/12-2176-1425.pbf").expect("failed loading tile");
|
||||
(
|
||||
0..tile.tesselate_stroke(&mut geometry, stroke_prim_id),
|
||||
0..0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let fill_range = 0..(geometry.indices.len() as u32);
|
||||
|
||||
stroke_tess
|
||||
.tessellate_path(
|
||||
&path,
|
||||
&StrokeOptions::tolerance(tolerance),
|
||||
&mut BuffersBuilder::new(&mut geometry, WithId(stroke_prim_id as u32)),
|
||||
} else {
|
||||
let logo = RustLogo();
|
||||
let max_index = logo.tesselate_stroke(&mut geometry, stroke_prim_id);
|
||||
(
|
||||
0..max_index,
|
||||
max_index..max_index + logo.tesselate_fill(&mut geometry, fill_prim_id),
|
||||
)
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
let stroke_range = fill_range.end..(geometry.indices.len() as u32);
|
||||
|
||||
fill_tess
|
||||
.tessellate_path(
|
||||
&arrow_path,
|
||||
&FillOptions::tolerance(tolerance),
|
||||
&mut BuffersBuilder::new(&mut geometry, WithId(arrows_prim_id as u32)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut cpu_primitives = Vec::with_capacity(PRIM_BUFFER_LEN);
|
||||
for _ in 0..PRIM_BUFFER_LEN {
|
||||
cpu_primitives.push(Primitive {
|
||||
color: [1.0, 0.0, 0.0, 1.0],
|
||||
z_index: 0,
|
||||
width: 0.0,
|
||||
translate: [0.0, 0.0],
|
||||
angle: 0.0,
|
||||
..Primitive::DEFAULT
|
||||
});
|
||||
}
|
||||
let mut cpu_primitives = [Primitive {
|
||||
color: [1.0, 0.0, 0.0, 1.0],
|
||||
z_index: 0,
|
||||
width: 0.0,
|
||||
translate: [0.0, 0.0],
|
||||
angle: 0.0,
|
||||
..Primitive::DEFAULT
|
||||
}; PRIM_BUFFER_LEN];
|
||||
|
||||
// Stroke primitive
|
||||
cpu_primitives[stroke_prim_id] = Primitive {
|
||||
cpu_primitives[stroke_prim_id as usize] = Primitive {
|
||||
color: [0.0, 0.0, 0.0, 1.0],
|
||||
z_index: num_instances as i32 + 2,
|
||||
width: 1.0,
|
||||
..Primitive::DEFAULT
|
||||
};
|
||||
// Main fill primitive
|
||||
cpu_primitives[fill_prim_id] = Primitive {
|
||||
cpu_primitives[fill_prim_id as usize] = Primitive {
|
||||
color: [1.0, 1.0, 1.0, 1.0],
|
||||
z_index: num_instances as i32 + 1,
|
||||
..Primitive::DEFAULT
|
||||
};
|
||||
// Instance primitives
|
||||
for (idx, cpu_prim) in cpu_primitives
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.skip(fill_prim_id + 1)
|
||||
.take(num_instances as usize - 1)
|
||||
{
|
||||
cpu_prim.z_index = (idx as u32 + 1) as i32;
|
||||
cpu_prim.color = [
|
||||
(0.1 * idx as f32).rem(1.0),
|
||||
(0.5 * idx as f32).rem(1.0),
|
||||
(0.9 * idx as f32).rem(1.0),
|
||||
1.0,
|
||||
];
|
||||
}
|
||||
|
||||
let mut scene = SceneParams::DEFAULT;
|
||||
|
||||
@ -195,13 +140,13 @@ fn main() {
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let vbo = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
let vertex_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&geometry.vertices),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
});
|
||||
|
||||
let ibo = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
let indices_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&geometry.indices),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
@ -210,14 +155,14 @@ fn main() {
|
||||
let prim_buffer_byte_size = (PRIM_BUFFER_LEN * std::mem::size_of::<Primitive>()) as u64;
|
||||
let globals_buffer_byte_size = std::mem::size_of::<Globals>() as u64;
|
||||
|
||||
let prims_ubo = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
let prims_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Prims ubo"),
|
||||
size: prim_buffer_byte_size,
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let globals_ubo = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
let globals_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Globals ubo"),
|
||||
size: globals_buffer_byte_size,
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
@ -255,11 +200,15 @@ fn main() {
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(globals_ubo.as_entire_buffer_binding()),
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
globals_uniform_buffer.as_entire_buffer_binding(),
|
||||
),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Buffer(prims_ubo.as_entire_buffer_binding()),
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
prims_uniform_buffer.as_entire_buffer_binding(),
|
||||
),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -371,6 +320,13 @@ fn main() {
|
||||
label: Some("Encoder"),
|
||||
});
|
||||
|
||||
/* cpu_primitives[fill_prim_id as usize].color = [
|
||||
(time_secs * 0.8 - 1.6).sin() * -0.1 + 0.1,
|
||||
(time_secs * 0.5 - 1.6).sin() * -0.1 + 0.1,
|
||||
(time_secs - 1.6).sin() * -0.1 + 0.1,
|
||||
1.0,
|
||||
];*/
|
||||
|
||||
cpu_primitives[stroke_prim_id as usize].width = scene.stroke_width;
|
||||
cpu_primitives[stroke_prim_id as usize].color = [
|
||||
(time_secs * 0.8 - 1.6).sin() * 0.1 + 0.1,
|
||||
@ -387,7 +343,7 @@ fn main() {
|
||||
}
|
||||
|
||||
queue.write_buffer(
|
||||
&globals_ubo,
|
||||
&globals_uniform_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&[Globals {
|
||||
resolution: [
|
||||
@ -400,7 +356,11 @@ fn main() {
|
||||
}]),
|
||||
);
|
||||
|
||||
queue.write_buffer(&prims_ubo, 0, bytemuck::cast_slice(&cpu_primitives));
|
||||
queue.write_buffer(
|
||||
&prims_uniform_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&cpu_primitives),
|
||||
);
|
||||
|
||||
{
|
||||
// A resolve target is only supported if the attachment actually uses anti-aliasing
|
||||
@ -443,8 +403,8 @@ fn main() {
|
||||
|
||||
pass.set_pipeline(&render_pipeline);
|
||||
pass.set_bind_group(0, &bind_group, &[]);
|
||||
pass.set_index_buffer(ibo.slice(..), wgpu::IndexFormat::Uint16);
|
||||
pass.set_vertex_buffer(0, vbo.slice(..));
|
||||
pass.set_index_buffer(indices_uniform_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||
pass.set_vertex_buffer(0, vertex_uniform_buffer.slice(..));
|
||||
|
||||
pass.draw_indexed(fill_range.clone(), 0, 0..(num_instances as u32));
|
||||
pass.draw_indexed(stroke_range.clone(), 0, 0..1);
|
||||
@ -463,27 +423,3 @@ fn main() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This vertex constructor forwards the positions and normals provided by the
|
||||
/// tessellators and add a shape id.
|
||||
pub struct WithId(pub u32);
|
||||
|
||||
impl FillVertexConstructor<GpuVertex> for WithId {
|
||||
fn new_vertex(&mut self, vertex: tessellation::FillVertex) -> GpuVertex {
|
||||
GpuVertex {
|
||||
position: vertex.position().to_array(),
|
||||
normal: [0.0, 0.0],
|
||||
prim_id: self.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StrokeVertexConstructor<GpuVertex> for WithId {
|
||||
fn new_vertex(&mut self, vertex: tessellation::StrokeVertex) -> GpuVertex {
|
||||
GpuVertex {
|
||||
position: vertex.position_on_path().to_array(),
|
||||
normal: vertex.normal().to_array(),
|
||||
prim_id: self.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
168
src/lyon_test/tesselation.rs
Normal file
168
src/lyon_test/tesselation.rs
Normal file
@ -0,0 +1,168 @@
|
||||
use lyon::extra::rust_logo::build_logo_path;
|
||||
use lyon::lyon_tessellation::{FillTessellator, StrokeTessellator};
|
||||
use lyon::tessellation;
|
||||
use lyon::tessellation::{
|
||||
BuffersBuilder, FillOptions, FillVertexConstructor, StrokeOptions, StrokeVertexConstructor,
|
||||
VertexBuffers,
|
||||
};
|
||||
use lyon_path::builder::SvgPathBuilder;
|
||||
use lyon_path::Path;
|
||||
use vector_tile::geometry::{Command, Geometry};
|
||||
use vector_tile::tile::Tile;
|
||||
|
||||
use crate::shader_ffi::GpuVertex;
|
||||
|
||||
const DEFAULT_TOLERANCE: f32 = 0.02;
|
||||
|
||||
pub trait Tesselated {
|
||||
fn tesselate_stroke(&self, buffer: &mut VertexBuffers<GpuVertex, u16>, prim_id: u32) -> u32;
|
||||
fn tesselate_fill(&self, buffer: &mut VertexBuffers<GpuVertex, u16>, prim_id: u32) -> u32;
|
||||
}
|
||||
|
||||
/// This vertex constructor forwards the positions and normals provided by the
|
||||
/// tessellators and add a shape id.
|
||||
pub struct WithId(pub u32);
|
||||
|
||||
impl FillVertexConstructor<GpuVertex> for WithId {
|
||||
fn new_vertex(&mut self, vertex: tessellation::FillVertex) -> GpuVertex {
|
||||
GpuVertex {
|
||||
position: vertex.position().to_array(),
|
||||
normal: [0.0, 0.0],
|
||||
prim_id: self.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StrokeVertexConstructor<GpuVertex> for WithId {
|
||||
fn new_vertex(&mut self, vertex: tessellation::StrokeVertex) -> GpuVertex {
|
||||
GpuVertex {
|
||||
position: vertex.position_on_path().to_array(),
|
||||
normal: vertex.normal().to_array(),
|
||||
prim_id: self.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Tesselated for Tile {
|
||||
fn tesselate_stroke(&self, buffer: &mut VertexBuffers<GpuVertex, u16>, prim_id: u32) -> u32 {
|
||||
let mut stroke_tess = StrokeTessellator::new();
|
||||
let mut tile_builder = Path::builder().with_svg();
|
||||
|
||||
for layer in self.layers() {
|
||||
if layer.name() != "water" {
|
||||
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 / 10.0,
|
||||
cmd.y as f32 / 10.0,
|
||||
));
|
||||
}
|
||||
Command::LineTo(cmd) => {
|
||||
tile_builder.relative_line_to(lyon_path::math::vector(
|
||||
cmd.x as f32 / 10.0,
|
||||
cmd.y as f32 / 10.0,
|
||||
));
|
||||
}
|
||||
Command::Close => {
|
||||
tile_builder.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Geometry::GeometryLineString(polygon) => {
|
||||
for command in &polygon.commands {
|
||||
match command {
|
||||
Command::MoveTo(cmd) => {
|
||||
tile_builder.relative_move_to(lyon_path::math::vector(
|
||||
cmd.x as f32 / 10.0,
|
||||
cmd.y as f32 / 10.0,
|
||||
));
|
||||
}
|
||||
Command::LineTo(cmd) => {
|
||||
tile_builder.relative_line_to(lyon_path::math::vector(
|
||||
cmd.x as f32 / 10.0,
|
||||
cmd.y as f32 / 10.0,
|
||||
));
|
||||
}
|
||||
Command::Close => {
|
||||
tile_builder.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
//tile_builder.close();
|
||||
tile_builder.move_to(lyon_path::math::point(0.0, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
let tile_path = tile_builder.build();
|
||||
|
||||
stroke_tess
|
||||
.tessellate_path(
|
||||
&tile_path,
|
||||
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
|
||||
&mut BuffersBuilder::new(buffer, WithId(prim_id)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buffer.indices.len() as u32
|
||||
}
|
||||
|
||||
fn tesselate_fill(&self, _buffer: &mut VertexBuffers<GpuVertex, u16>, _prim_id: u32) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RustLogo();
|
||||
|
||||
impl Tesselated for RustLogo {
|
||||
fn tesselate_stroke(&self, buffer: &mut VertexBuffers<GpuVertex, u16>, prim_id: u32) -> u32 {
|
||||
let mut stroke_tess = StrokeTessellator::new();
|
||||
|
||||
// Build a Path for the rust logo.
|
||||
let mut rust_logo_builder = Path::builder().with_svg();
|
||||
build_logo_path(&mut rust_logo_builder);
|
||||
let rust_logo = rust_logo_builder.build();
|
||||
|
||||
stroke_tess
|
||||
.tessellate_path(
|
||||
&rust_logo,
|
||||
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
|
||||
&mut BuffersBuilder::new(buffer, WithId(prim_id)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buffer.indices.len() as u32
|
||||
}
|
||||
|
||||
fn tesselate_fill(&self, buffer: &mut VertexBuffers<GpuVertex, u16>, prim_id: u32) -> u32 {
|
||||
let mut fill_tess = FillTessellator::new();
|
||||
|
||||
// Build a Path for the rust logo.
|
||||
let mut rust_logo_builder = Path::builder().with_svg();
|
||||
build_logo_path(&mut rust_logo_builder);
|
||||
let rust_logo = rust_logo_builder.build();
|
||||
|
||||
fill_tess
|
||||
.tessellate_path(
|
||||
&rust_logo,
|
||||
&FillOptions::tolerance(DEFAULT_TOLERANCE)
|
||||
.with_fill_rule(lyon_path::FillRule::NonZero),
|
||||
&mut BuffersBuilder::new(buffer, WithId(prim_id as u32)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buffer.indices.len() as u32
|
||||
}
|
||||
}
|
||||
34
src/lyon_test/tile_downloader.rs
Normal file
34
src/lyon_test/tile_downloader.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use std::fs::File;
|
||||
use std::io::copy;
|
||||
use std::path::Path;
|
||||
|
||||
use vector_tile::grid::*;
|
||||
|
||||
pub async fn download_tiles() {
|
||||
for (z, x, y) in get_tile_coordinates_tutzing() {
|
||||
let target = format!(
|
||||
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
|
||||
z = z,
|
||||
x = x,
|
||||
y = y,
|
||||
);
|
||||
println!("{}", target);
|
||||
let client = reqwest::Client::builder()
|
||||
.gzip(true)
|
||||
.build().unwrap();
|
||||
|
||||
let response = client.get(target).send().await.unwrap();
|
||||
if response.status().is_success() {
|
||||
let mut dest = {
|
||||
let fname =
|
||||
Path::new(".").join(format!("test-data/{z}-{x}-{y}.pbf", z = z, x = x, y = y,));
|
||||
File::create(fname).unwrap()
|
||||
};
|
||||
copy(&mut response.bytes().await.unwrap().as_ref(), &mut dest).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
download_tiles().await;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user