Draw very first tile

This commit is contained in:
Maximilian Ammann 2021-12-01 17:55:36 +01:00
parent a788c14d7a
commit 4bca568f6e
5 changed files with 1370 additions and 202 deletions

1180
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -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"

View File

@ -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,
}
}
}

View 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
}
}

View 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;
}