ux-dx 0.2.0

3D Graphics Primitives for Angular Rust
Documentation
use super::opengl::{Buffer, BufferUsage, ElementBuffer, PrimitiveType, VertexArray, VertexBuffer};
use super::{vertex, Vertex};
use crate::ext::error::{GameError, GameResult};
// use std::rc::Rc;

pub struct Renderer {
    vertex_array: VertexArray,
    vertex_buffer: VertexBuffer,
    vertex_size: usize,
    element_buffer: ElementBuffer,
    element_size: usize,
}

impl Renderer {
    pub fn init_vertex_size(&mut self, usage: BufferUsage, size: usize) {
        self.vertex_buffer.bind();
        self.vertex_buffer
            .init_size(usage, vertex::ATTRIBUTE_STRIDE * size);
        init_vertex_attribute_pointer(&self.vertex_buffer);
        self.vertex_buffer.unbind();
        self.vertex_size = size;
    }

    pub fn init_with_vertices(&mut self, usage: BufferUsage, vertices: &[Vertex]) {
        self.vertex_buffer.bind();
        self.vertex_buffer
            .init_with_data(usage, &convert_vertices_to_data(vertices));
        init_vertex_attribute_pointer(&self.vertex_buffer);
        self.vertex_buffer.unbind();
        self.vertex_size = vertices.len();
    }

    pub fn update_vertices(&self, offset: usize, vertices: &[Vertex]) {
        self.vertex_buffer.bind();
        self.vertex_buffer
            .sub_data(offset, &convert_vertices_to_data(vertices));
        self.vertex_buffer.unbind();
    }

    pub fn vertex_size(&self) -> usize {
        self.vertex_size
    }

    pub fn init_element_size(&mut self, usage: BufferUsage, size: usize) {
        self.element_buffer.bind();
        self.element_buffer.init_size(usage, size);
        self.element_buffer.unbind();
        self.element_size = size;
    }

    pub fn init_with_elements(&mut self, usage: BufferUsage, elements: &[u16]) {
        self.element_buffer.bind();
        self.element_buffer.init_with_data(usage, elements);
        self.element_buffer.unbind();
        self.element_size = elements.len();
    }

    pub fn update_elements(&self, offset: usize, elements: &[u16]) {
        self.element_buffer.bind();
        self.element_buffer.sub_data(offset, elements);
        self.element_buffer.unbind();
    }

    pub fn element_size(&self) -> usize {
        self.element_size
    }

    pub fn draw_elements(&self, primitive: PrimitiveType, count: usize, offset: usize) {
        self.vertex_array.bind();
        self.vertex_array.draw_elements(primitive, count, offset);
        self.vertex_array.unbind();
    }
}

pub struct RendererBuilder {
    vertex_array: VertexArray,
    vertex_buffer: Option<VertexBuffer>,
    vertex_size: Option<usize>,
    element_buffer: Option<ElementBuffer>,
    element_size: Option<usize>,
}

impl RendererBuilder {
    pub fn new() -> GameResult<Self> {
        let vertex_array =
            VertexArray::new().map_err(|error| GameError::InitError(error.into()))?;
        vertex_array.bind();
        Ok(Self {
            vertex_array,
            vertex_buffer: None,
            vertex_size: None,
            element_buffer: None,
            element_size: None,
        })
    }

    fn assert_vertex_buffer_not_init(&self) {
        assert!(self.vertex_buffer.is_none(), "vertex buffer has been setup");
    }

    pub fn init_vertex_size(mut self, usage: BufferUsage, size: usize) -> Self {
        self.assert_vertex_buffer_not_init();
        let vertex_buffer = Buffer::new_vertex().unwrap();
        vertex_buffer.bind();
        vertex_buffer.init_size(usage, vertex::ATTRIBUTE_STRIDE * size);
        init_vertex_attribute_pointer(&vertex_buffer);
        self.vertex_buffer = Some(vertex_buffer);
        self.vertex_size = Some(size);
        self
    }

    pub fn init_with_vertices(mut self, usage: BufferUsage, vertices: &[Vertex]) -> Self {
        self.assert_vertex_buffer_not_init();
        let vertex_buffer = Buffer::new_vertex().unwrap();
        vertex_buffer.bind();
        vertex_buffer.init_with_data(usage, &convert_vertices_to_data(vertices));
        init_vertex_attribute_pointer(&vertex_buffer);
        self.vertex_buffer = Some(vertex_buffer);
        self.vertex_size = Some(vertices.len());
        self
    }

    fn assert_element_buffer_not_init(&self) {
        assert!(
            self.element_buffer.is_none(),
            "element buffer has been setup"
        );
    }

    pub fn init_element_size(mut self, usage: BufferUsage, size: usize) -> Self {
        self.assert_element_buffer_not_init();
        let element_buffer = Buffer::new_element().unwrap();
        element_buffer.bind();
        element_buffer.init_size(usage, size);
        self.element_buffer = Some(element_buffer);
        self.element_size = Some(size);
        self
    }

    pub fn init_with_elements(mut self, usage: BufferUsage, elements: &[u16]) -> Self {
        self.assert_element_buffer_not_init();
        let element_buffer = Buffer::new_element().unwrap();
        element_buffer.bind();
        element_buffer.init_with_data(usage, elements);
        self.element_buffer = Some(element_buffer);
        self.element_size = Some(elements.len());
        self
    }

    pub fn build(self) -> GameResult<Renderer> {
        let vertex_array = self.vertex_array;
        let vertex_buffer = self
            .vertex_buffer
            .ok_or_else(|| GameError::InitError("must setup vertex buffer".into()))?;
        let vertex_size = self
            .vertex_size
            .ok_or_else(|| GameError::InitError("must setup vertex buffer".into()))?;
        let element_buffer = self
            .element_buffer
            .ok_or_else(|| GameError::InitError("must setup element buffer".into()))?;
        let element_size = self
            .element_size
            .ok_or_else(|| GameError::InitError("must setup element buffer".into()))?;
        vertex_array.unbind();
        vertex_buffer.unbind();
        element_buffer.unbind();
        Ok(Renderer {
            vertex_array,
            vertex_buffer,
            vertex_size,
            element_buffer,
            element_size,
        })
    }
}

fn init_vertex_attribute_pointer(vertex_buffer: &VertexBuffer) {
    vertex_buffer.set_attrib_pointer_f32(
        0,
        vertex::ATTRIBUTE_POSITION_SIZE,
        vertex::ATTRIBUTE_STRIDE,
        vertex::ATTRIBUTE_OFFSET_0,
    );
    vertex_buffer.set_attrib_pointer_f32(
        1,
        vertex::ATTRIBUTE_UV_SIZE,
        vertex::ATTRIBUTE_STRIDE,
        vertex::ATTRIBUTE_OFFSET_1,
    );
    vertex_buffer.set_attrib_pointer_f32(
        2,
        vertex::ATTRIBUTE_COLOR_SIZE,
        vertex::ATTRIBUTE_STRIDE,
        vertex::ATTRIBUTE_OFFSET_2,
    );
}

fn convert_vertices_to_data(vertices: &[Vertex]) -> Vec<f32> {
    let mut data = Vec::with_capacity(vertex::ATTRIBUTE_STRIDE * vertices.len());
    for vertex in vertices {
        data.push(vertex.position.x);
        data.push(vertex.position.y);
        data.push(vertex.uv.x);
        data.push(vertex.uv.y);
        data.push(vertex.color.red);
        data.push(vertex.color.green);
        data.push(vertex.color.blue);
        data.push(vertex.color.alpha);
    }
    data
}