mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Add a stencil pattern which prepares the stencil buffer accordingly
This commit is contained in:
parent
c54f3ee84b
commit
e9ed013489
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 275 KiB |
@ -1,6 +1,7 @@
|
||||
use crate::render::shader_ffi::Vec3f32;
|
||||
use std::fmt;
|
||||
|
||||
use crate::render::shader_ffi::Vec3f32;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct TileCoords {
|
||||
pub x: u32,
|
||||
@ -42,21 +43,29 @@ pub struct WorldTileCoords {
|
||||
}
|
||||
|
||||
impl WorldTileCoords {
|
||||
pub fn into_world(self, extent: u16) -> WorldCoords {
|
||||
pub fn into_world(self, extent: f32) -> WorldCoords {
|
||||
WorldCoords {
|
||||
x: self.x as f32 * extent as f32,
|
||||
y: self.y as f32 * extent as f32 + extent as f32, // We add extent here as we want the upper left corner
|
||||
x: self.x as f32 * extent,
|
||||
y: self.y as f32 * extent + extent, // We add extent here as we want the upper left corner
|
||||
z: self.z as f32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_aligned(self) -> AlignedWorldTileCoords {
|
||||
return AlignedWorldTileCoords(WorldTileCoords {
|
||||
x: self.x / 2 * 2,
|
||||
y: self.y / 2 * 2 - 1,
|
||||
z: self.z,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn stencil_reference_value(&self) -> u8 {
|
||||
match (self.x, self.y) {
|
||||
(x, y) if x % 2 == 0 && y % 2 == 0 => 1,
|
||||
(x, y) if x % 2 == 0 && y % 2 != 0 => 2,
|
||||
(x, y) if x % 2 != 0 && y % 2 == 0 => 3,
|
||||
(x, y) if x % 2 != 0 && y % 2 != 0 => 4,
|
||||
_ => 0,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,6 +86,38 @@ impl From<(i32, i32, u8)> for WorldTileCoords {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AlignedWorldTileCoords(pub WorldTileCoords);
|
||||
|
||||
impl AlignedWorldTileCoords {
|
||||
pub fn into_upper_left(self) -> WorldTileCoords {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn to_upper_right(&self) -> WorldTileCoords {
|
||||
WorldTileCoords {
|
||||
x: self.0.x + 1,
|
||||
y: self.0.y + 1,
|
||||
z: self.0.z,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_lower_left(&self) -> WorldTileCoords {
|
||||
WorldTileCoords {
|
||||
x: self.0.x,
|
||||
y: self.0.y - 1,
|
||||
z: self.0.z,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_lower_right(&self) -> WorldTileCoords {
|
||||
WorldTileCoords {
|
||||
x: self.0.x - 1,
|
||||
y: self.0.y - 1,
|
||||
z: self.0.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct WorldCoords {
|
||||
pub x: f32,
|
||||
|
||||
@ -5,8 +5,8 @@ pub const MUNICH_Y: u32 = 11360;
|
||||
pub const MUNICH_Z: u8 = 15;
|
||||
|
||||
pub fn fetch_munich_tiles(cache: &Cache) {
|
||||
for x in 0..10 {
|
||||
for y in 0..10 {
|
||||
for x in 0..15 {
|
||||
for y in 0..15 {
|
||||
cache.fetch((MUNICH_X + x, MUNICH_Y + y, MUNICH_Z).into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
mod buffer_pool;
|
||||
mod piplines;
|
||||
mod shaders;
|
||||
mod stencil_pattern;
|
||||
mod texture;
|
||||
|
||||
mod shaders;
|
||||
|
||||
mod buffer_pool;
|
||||
pub mod camera;
|
||||
pub mod shader_ffi;
|
||||
pub mod state;
|
||||
|
||||
@ -26,13 +26,15 @@ fn main(
|
||||
[[builtin(vertex_index)]] vertex_idx: u32,
|
||||
[[builtin(instance_index)]] instance_idx: u32 // instance_index is used when we have multiple instances of the same "object"
|
||||
) -> VertexOutput {
|
||||
var VERTICES: array<vec2<f32>, 6> = array<vec2<f32>, 6>(
|
||||
vec2<f32>(0.0, 0.0),
|
||||
vec2<f32>(0.0, EXTENT),
|
||||
vec2<f32>(EXTENT, 0.0),
|
||||
vec2<f32>(EXTENT, 0.0),
|
||||
vec2<f32>(0.0, EXTENT),
|
||||
vec2<f32>(EXTENT, EXTENT)
|
||||
let z = 0.0;
|
||||
|
||||
var VERTICES: array<vec3<f32>, 6> = array<vec3<f32>, 6>(
|
||||
vec3<f32>(0.0, 0.0, z),
|
||||
vec3<f32>(0.0, EXTENT, z),
|
||||
vec3<f32>(EXTENT, 0.0, z),
|
||||
vec3<f32>(EXTENT, 0.0, z),
|
||||
vec3<f32>(0.0, EXTENT, z),
|
||||
vec3<f32>(EXTENT, EXTENT, z)
|
||||
);
|
||||
let a_position = VERTICES[vertex_idx];
|
||||
|
||||
@ -42,10 +44,7 @@ fn main(
|
||||
vec3<f32>(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
let z = 0.0;
|
||||
|
||||
let world_pos_3d = vec3<f32>(a_position + mask_offset, z);
|
||||
let world_pos = scaling * world_pos_3d;
|
||||
let world_pos = scaling * a_position + vec3<f32>(mask_offset, z);
|
||||
|
||||
let position = globals.camera.view_proj * vec4<f32>(world_pos, 1.0);
|
||||
|
||||
|
||||
@ -3,8 +3,6 @@ use std::default::Default;
|
||||
use std::io::Cursor;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::coords::{TileCoords, WorldTileCoords};
|
||||
use crate::example::{MUNICH_X, MUNICH_Y};
|
||||
use log::{trace, warn};
|
||||
use lyon::tessellation::VertexBuffers;
|
||||
use wgpu::util::DeviceExt;
|
||||
@ -15,11 +13,14 @@ use winit::event::{
|
||||
};
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::coords::{TileCoords, WorldTileCoords};
|
||||
use crate::example::{MUNICH_X, MUNICH_Y};
|
||||
use crate::fps_meter::FPSMeter;
|
||||
use crate::io::cache::Cache;
|
||||
use crate::io::static_database;
|
||||
use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE};
|
||||
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool};
|
||||
use crate::render::stencil_pattern::TileMaskPattern;
|
||||
use crate::render::{camera, shaders};
|
||||
use crate::tesselation::{IndexDataType, Tesselated};
|
||||
use crate::util::measure::Measure;
|
||||
@ -68,7 +69,8 @@ pub struct State {
|
||||
|
||||
buffer_pool: BufferPool<Queue, Buffer, GpuVertexUniform, IndexDataType>,
|
||||
|
||||
tile_mask_instances: wgpu::Buffer,
|
||||
tile_mask_pattern: TileMaskPattern,
|
||||
tile_mask_instances_buffer: wgpu::Buffer,
|
||||
|
||||
pub camera: camera::Camera,
|
||||
projection: camera::Projection,
|
||||
@ -161,24 +163,14 @@ impl State {
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let instances = [
|
||||
// Step 1
|
||||
MaskInstanceUniform::new([0.0, 0.0], 4.0, -4.0, [1.0, 0.0, 0.0, 1.0]), // horizontal
|
||||
// Step 2
|
||||
MaskInstanceUniform::new([1.0 * 4096.0, 0.0], 1.0, -4.0, [0.0, 1.0, 0.0, 1.0]), // vertical
|
||||
MaskInstanceUniform::new([3.0 * 4096.0, 0.0], 1.0, -4.0, [0.0, 1.0, 0.0, 1.0]), // vertical
|
||||
// Step 3
|
||||
MaskInstanceUniform::new([0.0, -1.0 * 4096.0], 4.0, 1.0, [0.0, 0.0, 1.0, 1.0]), // horizontal
|
||||
MaskInstanceUniform::new([0.0, -3.0 * 4096.0], 4.0, 1.0, [0.0, 0.0, 1.0, 1.0]), // horizontal
|
||||
// Step 4
|
||||
MaskInstanceUniform::new([1.0 * 4096.0, 0.0], 1.0, -4.0, [0.5, 0.25, 0.5, 1.0]), // vertical
|
||||
MaskInstanceUniform::new([3.0 * 4096.0, 0.0], 1.0, -4.0, [0.5, 0.25, 0.5, 1.0]), // vertical
|
||||
];
|
||||
let tile_masks_uniform_buffer_size =
|
||||
std::mem::size_of::<MaskInstanceUniform>() as u64 * 128; // FIXME: Tile count?
|
||||
|
||||
let tile_mask_instances = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
let tile_mask_instances = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&instances),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
size: tile_masks_uniform_buffer_size,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let globals_buffer_byte_size = cmp::max(
|
||||
@ -309,7 +301,7 @@ impl State {
|
||||
globals_uniform_buffer,
|
||||
tiles_uniform_buffer,
|
||||
fps_meter: FPSMeter::new(),
|
||||
tile_mask_instances,
|
||||
tile_mask_instances_buffer: tile_mask_instances,
|
||||
camera,
|
||||
projection,
|
||||
suspended: false, // Initially the app is not suspended
|
||||
@ -317,6 +309,7 @@ impl State {
|
||||
BackingBufferDescriptor(vertex_uniform_buffer, 1024 * 1024 * 16),
|
||||
BackingBufferDescriptor(indices_uniform_buffer, 1024 * 1024 * 16),
|
||||
),
|
||||
tile_mask_pattern: TileMaskPattern::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,28 +364,29 @@ impl State {
|
||||
let upload = cache.pop_all();
|
||||
|
||||
for tile in upload.iter() {
|
||||
let new_coords = TileCoords {
|
||||
x: tile.coords.x,
|
||||
y: tile.coords.y,
|
||||
z: tile.coords.z,
|
||||
};
|
||||
let world_coords = tile.coords.into_world_tile();
|
||||
self.tile_mask_pattern.update_bounds(&world_coords);
|
||||
|
||||
self.buffer_pool
|
||||
.allocate_geometry(&self.queue, tile.id, new_coords, &tile.geometry);
|
||||
.allocate_geometry(&self.queue, tile.id, tile.coords, &tile.geometry);
|
||||
|
||||
let uniform = TileUniform::new(
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
new_coords
|
||||
.into_world_tile()
|
||||
.into_world(4096)
|
||||
.into_shader_coords(),
|
||||
);
|
||||
self.queue.write_buffer(
|
||||
&self.tiles_uniform_buffer,
|
||||
std::mem::size_of::<TileUniform>() as u64 * tile.id as u64,
|
||||
bytemuck::cast_slice(&[uniform]),
|
||||
bytemuck::cast_slice(&[TileUniform::new(
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
world_coords.into_world(4096.0).into_shader_coords(),
|
||||
)]),
|
||||
);
|
||||
}
|
||||
|
||||
self.tile_mask_pattern.update_pattern(15u8, 4096.0);
|
||||
|
||||
self.queue.write_buffer(
|
||||
&self.tile_mask_instances_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(self.tile_mask_pattern.as_slice()),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
@ -460,9 +454,9 @@ impl State {
|
||||
{
|
||||
// Draw masks
|
||||
pass.set_pipeline(&self.mask_pipeline);
|
||||
pass.set_vertex_buffer(0, self.tile_mask_instances.slice(..));
|
||||
pass.set_vertex_buffer(0, self.tile_mask_instances_buffer.slice(..));
|
||||
// Draw 7 squares each out of 6 vertices
|
||||
pass.draw(0..6, 0..7);
|
||||
pass.draw(0..6, 0..self.tile_mask_pattern.instances());
|
||||
}
|
||||
{
|
||||
for entry in self.buffer_pool.available_vertices() {
|
||||
|
||||
134
src/render/stencil_pattern.rs
Normal file
134
src/render/stencil_pattern.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use std::num;
|
||||
|
||||
use crate::coords::{AlignedWorldTileCoords, WorldTileCoords};
|
||||
use crate::render::shader_ffi::MaskInstanceUniform;
|
||||
|
||||
struct MinMaxBoundingBox {
|
||||
min_x: i32,
|
||||
min_y: i32,
|
||||
max_x: i32,
|
||||
max_y: i32,
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl MinMaxBoundingBox {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
min_x: i32::MAX,
|
||||
min_y: i32::MAX,
|
||||
max_x: i32::MIN,
|
||||
max_y: i32::MIN,
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_initialized(&self) -> bool {
|
||||
self.initialized
|
||||
}
|
||||
|
||||
pub fn update(&mut self, world_coords: &WorldTileCoords) {
|
||||
self.initialized = true;
|
||||
|
||||
if world_coords.x < self.min_x {
|
||||
self.min_x = world_coords.x;
|
||||
}
|
||||
|
||||
if world_coords.y < self.min_y {
|
||||
self.min_y = world_coords.y;
|
||||
}
|
||||
|
||||
if world_coords.x > self.max_x {
|
||||
self.max_x = world_coords.x;
|
||||
}
|
||||
|
||||
if world_coords.y > self.max_y {
|
||||
self.max_y = world_coords.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TileMaskPattern {
|
||||
bounding_box: MinMaxBoundingBox,
|
||||
pattern: Vec<MaskInstanceUniform>,
|
||||
}
|
||||
|
||||
impl TileMaskPattern {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
bounding_box: MinMaxBoundingBox::new(),
|
||||
pattern: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_bounds(&mut self, world_coords: &WorldTileCoords) {
|
||||
self.bounding_box.update(world_coords)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[MaskInstanceUniform] {
|
||||
self.pattern.as_slice()
|
||||
}
|
||||
|
||||
pub fn instances(&self) -> u32 {
|
||||
self.pattern.len() as u32
|
||||
}
|
||||
|
||||
fn vertical(&mut self, dx: i32, dy: i32, anchor_x: f32, anchor_y: f32, extent: f32) {
|
||||
for i in 0..(dx.abs() / 2) {
|
||||
self.pattern.push(MaskInstanceUniform::new(
|
||||
[anchor_x + ((i * 2) + 1) as f32 * extent, anchor_y],
|
||||
1.0,
|
||||
dy as f32,
|
||||
[0.0, 1.0, 0.0, 1.0],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn horizontal(&mut self, dx: i32, dy: i32, anchor_x: f32, anchor_y: f32, extent: f32) {
|
||||
for i in 0..(dy.abs() / 2) {
|
||||
self.pattern.push(MaskInstanceUniform::new(
|
||||
[anchor_x, anchor_y - extent - (i * 2) as f32 * extent],
|
||||
dx as f32,
|
||||
1.0,
|
||||
[0.0, 0.0, 1.0, 1.0],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_pattern(&mut self, z: u8, extent: f32) {
|
||||
if !self.bounding_box.is_initialized() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.pattern.clear();
|
||||
|
||||
let start: WorldTileCoords = (self.bounding_box.min_x, self.bounding_box.max_y, z).into(); // upper left corner
|
||||
let end: WorldTileCoords = (self.bounding_box.max_x, self.bounding_box.min_y, z).into(); // lower right corner
|
||||
|
||||
let aligned_start = start.into_aligned();
|
||||
let aligned_end = end.into_aligned().to_lower_right();
|
||||
|
||||
let start_world = start.into_world(extent);
|
||||
|
||||
let dy = aligned_end.y - aligned_start.0.y;
|
||||
let dx = aligned_end.x - aligned_start.0.x;
|
||||
|
||||
let anchor_x = start_world.x;
|
||||
let anchor_y = start_world.y;
|
||||
// red step
|
||||
self.pattern.push(MaskInstanceUniform::new(
|
||||
[anchor_x, anchor_y],
|
||||
dx as f32,
|
||||
dy as f32,
|
||||
[1.0, 0.0, 0.0, 1.0],
|
||||
));
|
||||
|
||||
// green step
|
||||
self.vertical(dx, dy, anchor_x, anchor_y, extent);
|
||||
|
||||
// blue step
|
||||
self.horizontal(dx, dy, anchor_x, anchor_y, extent);
|
||||
|
||||
// violet step
|
||||
self.vertical(dx, dy, anchor_x, anchor_y, extent);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user