lemna 0.4.0

A Reactive UI framework for Rust
use bytemuck::{Pod, Zeroable};

use super::buffer_cache::{BufferCache, BufferCacheId};
use super::raster_cache::{RasterCache, RasterCacheId, RasterData};
use crate::base_types::{Point, Pos, AABB};
use crate::PixelSize;

const INDEX_ENTRIES_PER_IMAGE: usize = 6;
const VERTEX_ENTRIES_PER_IMAGE: usize = 4;

#[repr(C)]
#[derive(Clone, Copy, Default, Debug, Pod, Zeroable)]
pub struct Vertex {
    pub pos: Point,
    pub tex_pos: Point,
}

impl crate::render::wgpu::VBDesc for Vertex {
    fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
        wgpu::VertexBufferLayout {
            array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
            step_mode: wgpu::VertexStepMode::Vertex,
            attributes: &[
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x2,
                    offset: 0,
                    shader_location: 0,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x2,
                    offset: 4 * 2,
                    shader_location: 1,
                },
            ],
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable, Default)]
pub(crate) struct Instance {
    pub pos: Pos,
}

impl crate::render::wgpu::VBDesc for Instance {
    fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
        wgpu::VertexBufferLayout {
            array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
            step_mode: wgpu::VertexStepMode::Instance,
            attributes: &[wgpu::VertexAttribute {
                format: wgpu::VertexFormat::Float32x3,
                offset: 0,
                shader_location: 2,
            }],
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Raster {
    pub buffer_id: BufferCacheId,
    pub raster_cache_id: RasterCacheId,
}

impl Raster {
    pub fn new(
        data: RasterData,
        size: PixelSize,
        buffer_cache: &mut BufferCache<Vertex, u16>,
        raster_cache: &mut RasterCache,
        prev_buffer: Option<BufferCacheId>,
        prev_raster: Option<RasterCacheId>,
    ) -> Self {
        let buffer_id = if let Some(c) = prev_buffer {
            buffer_cache.alloc_or_reuse_chunk(c, VERTEX_ENTRIES_PER_IMAGE, INDEX_ENTRIES_PER_IMAGE)
        } else {
            buffer_cache.alloc_chunk(VERTEX_ENTRIES_PER_IMAGE, INDEX_ENTRIES_PER_IMAGE)
        };
        let raster_cache_id = raster_cache.alloc_or_reuse_chunk(prev_raster);
        raster_cache.set_raster(raster_cache_id, data, size);

        Self {
            buffer_id,
            raster_cache_id,
        }
    }

    pub(crate) fn render(
        &self,
        aabb: &AABB,
        tex_coords: (Point, Point),
        buffer_cache: &mut BufferCache<Vertex, u16>,
        raster_cache: &mut RasterCache,
        instance_data: &mut Vec<Instance>,
        cache_invalid: bool,
    ) -> bool {
        let mut cache_changed = false;
        buffer_cache.register(self.buffer_id);
        raster_cache.register(self.raster_cache_id);
        let (vertex_chunk, index_chunk) = buffer_cache.get_chunks(self.buffer_id);

        if cache_invalid || !vertex_chunk.filled {
            cache_changed = true;
            let v = vertex_chunk.start;
            let i = index_chunk.start;
            let width = aabb.width();
            let height = aabb.height();

            buffer_cache.vertex_data[v] = Vertex {
                pos: Point { x: 0.0, y: 0.0 },
                tex_pos: Point {
                    x: tex_coords.0.x,
                    y: tex_coords.0.y,
                },
            };
            buffer_cache.vertex_data[v + 1] = Vertex {
                pos: Point { x: width, y: 0.0 },
                tex_pos: Point {
                    x: tex_coords.1.x,
                    y: tex_coords.0.y,
                },
            };
            buffer_cache.vertex_data[v + 2] = Vertex {
                pos: Point { x: 0.0, y: height },
                tex_pos: Point {
                    x: tex_coords.0.x,
                    y: tex_coords.1.y,
                },
            };
            buffer_cache.vertex_data[v + 3] = Vertex {
                pos: Point {
                    x: width,
                    y: height,
                },
                tex_pos: Point {
                    x: tex_coords.1.x,
                    y: tex_coords.1.y,
                },
            };

            buffer_cache.index_data[i] = 0;
            buffer_cache.index_data[i + 1] = 1;
            buffer_cache.index_data[i + 2] = 2;
            buffer_cache.index_data[i + 3] = 2;
            buffer_cache.index_data[i + 4] = 1;
            buffer_cache.index_data[i + 5] = 3;

            buffer_cache.fill_chunks(self.buffer_id);
        }

        instance_data.push(Instance { pos: aabb.pos });

        cache_changed
    }
}