# mod.rs - source
Source of the Rust file `maplibre/src/tessellation/mod.rs`.
Keywords: rust, rustlang, rust-lang

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105

    //! Tessellation for lines and polygons is implemented here.

    use bytemuck::Pod;
    use std::ops::Add;

    use lyon::tessellation::{
        FillVertex, FillVertexConstructor, StrokeVertex, StrokeVertexConstructor, VertexBuffers,
    };

    use crate::error::Error;
    use crate::render::ShaderVertex;

    pub mod zero_tessellator;

    const DEFAULT_TOLERANCE: f32 = 0.02;

    /// Vertex buffers index data type.
    pub type IndexDataType = u32; // Must match INDEX_FORMAT

    /// An element that can be tessellated into vertex buffers.
    pub trait Tessellated<I: Add> {
        /// Returns a vertex buffer which represents some object like a layer. Each object can contain
        /// multiple features. For each feature also the amount of indices is returned.
        ///
        fn tessellate(&self) -> Result<(VertexBuffers<ShaderVertex, I>, Vec<u32>), Error>;
    }

    /// Constructor for Fill and Stroke vertices.
    pub struct VertexConstructor {}

    impl FillVertexConstructor<ShaderVertex> for VertexConstructor {
        fn new_vertex(&mut self, vertex: FillVertex) -> ShaderVertex {
            ShaderVertex::new(vertex.position().to_array(), [0.0, 0.0])
        }
    }

    impl StrokeVertexConstructor<ShaderVertex> for VertexConstructor {
        fn new_vertex(&mut self, vertex: StrokeVertex) -> ShaderVertex {
            ShaderVertex::new(
                vertex.position_on_path().to_array(),
                vertex.normal().to_array(),
            )
        }
    }

    /// Vertex buffer which includes additional padding to fulfill the `wgpu::COPY_BUFFER_ALIGNMENT`.
    #[derive(Clone)]
    pub struct OverAlignedVertexBuffer<V, I> {
        pub buffer: VertexBuffers<V, I>,
        pub usable_indices: u32,
    }

    impl<V, I> OverAlignedVertexBuffer<V, I> {
        pub fn empty() -> Self {
            Self {
                buffer: VertexBuffers::with_capacity(0, 0),
                usable_indices: 0,
            }
        }
    }

    impl<V: Pod, I: Pod> From<VertexBuffers<V, I>> for OverAlignedVertexBuffer<V, I> {
        fn from(mut buffer: VertexBuffers<V, I>) -> Self {
            let usable_indices = buffer.indices.len() as u32;
            buffer.align_vertices();
            buffer.align_indices();
            Self {
                buffer,
                usable_indices,
            }
        }
    }

    trait Align<V: Pod, I: Pod> {
        fn align_vertices(&mut self);
        fn align_indices(&mut self);
    }

    impl<V: Pod, I: Pod> Align<V, I> for VertexBuffers<V, I> {
        fn align_vertices(&mut self) {
            let align = wgpu::COPY_BUFFER_ALIGNMENT;
            let stride = std::mem::size_of::<ShaderVertex>() as wgpu::BufferAddress;
            let unpadded_bytes = self.vertices.len() as wgpu::BufferAddress * stride;
            let padding_bytes = (align - unpadded_bytes % align) % align;

            if padding_bytes != 0 {
                panic!(
                    "vertices are always aligned to wgpu::COPY_BUFFER_ALIGNMENT \
                        because GpuVertexUniform is aligned"
                )
            }
        }

        fn align_indices(&mut self) {
            let align = wgpu::COPY_BUFFER_ALIGNMENT;
            let stride = std::mem::size_of::<I>() as wgpu::BufferAddress;
            let unpadded_bytes = self.indices.len() as wgpu::BufferAddress * stride;
            let padding_bytes = (align - unpadded_bytes % align) % align;
            let overpad = (padding_bytes + stride - 1) / stride; // Divide by stride but round up

            for _ in 0..overpad {
                self.indices.push(I::zeroed());
            }
        }
    }