nightshade 0.13.3

A cross-platform data-oriented game engine.
Documentation
mod constructor;
mod execute;
mod prepare;

use crate::ecs::world::World;
use crate::render::wgpu::rendergraph::{PassExecutionContext, PassNode};
use nalgebra_glm::Mat4;

const INITIAL_RECT_CAPACITY: usize = 4096;
const INITIAL_TEXT_VERTEX_CAPACITY: usize = 64000;
const INITIAL_TEXT_INDEX_CAPACITY: usize = 96000;
const INITIAL_TEXT_INSTANCE_CAPACITY: usize = 1024;
const INITIAL_CHARACTER_COLOR_CAPACITY: usize = 10000;

#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct UiRectInstance {
    position_size: [f32; 4],
    color: [f32; 4],
    border_color: [f32; 4],
    clip_rect: [f32; 4],
    params: [f32; 4],
}

#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct TextInstanceData {
    color: [f32; 4],
    outline_color: [f32; 4],
    clip_rect: [f32; 4],
    params: [f32; 4],
}

#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct UiPassVertex {
    position: [f32; 2],
}

#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct UiTextVertex {
    position: [f32; 3],
    tex_coords: [f32; 2],
    character_index: u32,
    text_instance_index: u32,
    _padding: u32,
}

#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct GlobalUniforms {
    projection: Mat4,
}

struct TextDrawCall {
    font_index: usize,
    index_start: u32,
    index_count: u32,
    layer: super::UiLayer,
}

struct LayerDrawGroup {
    rect_start: u32,
    rect_count: u32,
    text_draw_start: usize,
    text_draw_count: usize,
}

struct TextBuildEntry {
    font_index: usize,
    index_offset: u32,
    index_count: u32,
    layer: super::UiLayer,
}

pub struct UiPass {
    rect_pipeline: wgpu::RenderPipeline,
    text_pipeline: wgpu::RenderPipeline,
    text_pipeline_subpixel: wgpu::RenderPipeline,
    use_subpixel: bool,

    global_uniform_buffer: wgpu::Buffer,
    global_uniform_bind_group: wgpu::BindGroup,

    rect_quad_vertex_buffer: wgpu::Buffer,
    rect_quad_index_buffer: wgpu::Buffer,
    rect_instance_buffer: wgpu::Buffer,
    rect_instance_bind_group_layout: wgpu::BindGroupLayout,
    rect_instance_bind_group: wgpu::BindGroup,
    rect_instance_capacity: usize,
    rect_count: u32,

    text_vertex_buffer: wgpu::Buffer,
    text_index_buffer: wgpu::Buffer,
    text_instance_buffer: wgpu::Buffer,
    character_color_buffer: wgpu::Buffer,
    character_bg_color_buffer: wgpu::Buffer,
    text_data_bind_group_layout: wgpu::BindGroupLayout,
    text_data_bind_group: wgpu::BindGroup,
    text_font_bind_group_layout: wgpu::BindGroupLayout,
    text_font_bind_groups: Vec<wgpu::BindGroup>,
    _text_global_bind_group_layout: wgpu::BindGroupLayout,
    text_global_bind_group: wgpu::BindGroup,
    text_vertex_capacity: usize,
    text_index_capacity: usize,
    text_instance_capacity: usize,
    character_color_capacity: usize,
    character_bg_color_capacity: usize,
    text_draw_calls: Vec<TextDrawCall>,
    layer_draw_groups: Vec<LayerDrawGroup>,

    cached_font_texture_views: Vec<wgpu::TextureView>,
    screen_width: f32,
    screen_height: f32,
}

impl PassNode<World> for UiPass {
    fn name(&self) -> &'static str {
        "ui_pass"
    }

    fn reads(&self) -> Vec<&str> {
        vec![]
    }

    fn writes(&self) -> Vec<&str> {
        vec![]
    }

    fn reads_writes(&self) -> Vec<&str> {
        vec!["color", "depth"]
    }

    fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, world: &World) {
        self.prepare_pass(device, queue, world);
    }

    fn execute<'r, 'e>(
        &mut self,
        context: PassExecutionContext<'r, 'e, World>,
    ) -> Result<
        Vec<crate::render::wgpu::rendergraph::SubGraphRunCommand<'r>>,
        crate::render::wgpu::rendergraph::RenderGraphError,
    > {
        self.execute_pass(context)
    }
}