tea_render 0.1.1

A lib for easier use of OpenGL functions
Documentation
use crate::{GlBind, GlObject, GlTarget, GlAttrib};
use std::ffi::c_void;

static mut CURRENT_VAO: u32 = 0;

pub trait VertexData {
    type Output;
    fn stride() -> usize {
        std::mem::size_of::<Self::Output>()
    }

    fn get_format() -> VertexFormat;
}

#[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct VertexFormat(Vec<AttribSlot>);

impl VertexFormat {
    pub fn attribs(&self) -> &Vec<AttribSlot> {
        &self.0
    }
}

#[derive(Default, Debug)]
pub struct VertexFormatBuilder {
    location: u32,
    offset: i32,
    format: VertexFormat,
}

impl VertexFormatBuilder {
    pub fn new() -> Self {
        VertexFormatBuilder::default()
    }

    pub fn push<T: GlAttrib>(&mut self, normalized: bool) -> &mut Self {
        let attrib = AttribSlot {
            location: self.location,
            type_: T::gl_enum(),
            size: T::size() as i32,
            normalized,
            offset: self.offset
        };
        self.location += 1;
        self.offset += T::stride() as i32;
        self.format.0.push(attrib);
        self
    }

    pub fn build(&self) -> VertexFormat {
        self.format.clone()
    }
}

#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
pub struct AttribSlot {
    pub location: u32,
    pub type_: u32,
    pub size: i32,
    pub normalized: bool,
    pub offset: i32
}

impl AttribSlot {
    pub fn new<T: GlAttrib>(location: u32, normalized: bool, offset: i32) -> AttribSlot {
        AttribSlot {
            location,
            type_: T::gl_enum(),
            size: T::size() as i32,
            normalized,
            offset
        }
    }
}

#[derive(Default, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub struct VertexArray(u32);

impl VertexArray {
    pub fn new() -> Result<VertexArray, String> {
        let mut handle: u32 = 0;
        unsafe { gl::GenVertexArrays(1, &mut handle) };
        Ok(VertexArray(handle))
    }

    pub fn check_bind(&self) {
        let cur_vao = Self::current_bind();
        assert_eq!(cur_vao, self.0);
    }

    pub fn setup_for<T: VertexData>(&self) {
        self.check_bind();
        let format = T::get_format();
        for a in format.0 {
            unsafe {
                gl::EnableVertexAttribArray(a.location);
                gl::VertexAttribPointer(a.location, a.size, a.type_, a.normalized as u8, T::stride() as i32, a.offset as *const c_void);
            }
            println!("{:?}", a);

        }
    }

    pub fn enable_attrib(&self, index: u32) {
        unsafe { gl::EnableVertexAttribArray(index) };
    }

    pub fn attrib_pointer<T: GlAttrib>(&self, index: u32, stride: i32, start: i32) {
        T::setup_attrib(index, false, stride, start);
    }
}

impl GlBind for VertexArray {
    fn bind(&self) {
        unsafe { CURRENT_VAO = self.0 };
        unsafe { gl::BindVertexArray(self.0) };
    }

    fn unbind(&self) {
        unsafe {
            gl::BindVertexArray(0);
            CURRENT_VAO = 0;
        }
    }
}

impl GlTarget for VertexArray {
    fn target() -> u32 { gl::NONE }
    fn binding() -> u32 { gl::VERTEX_ARRAY_BINDING }
    fn current_bind() -> u32 { unsafe { CURRENT_VAO } }
}

impl GlObject for VertexArray {
    fn get_id(&self) -> u32 {
        self.0
    }
}

impl Drop for VertexArray {
    fn drop(&mut self) {
        unsafe { gl::DeleteVertexArrays(1, &self.0) };
    }
}

#[macro_export]
macro_rules! impl_vertexdata {
    ($Name: ident, $($field: ident),+) => {
        #[repr(C)]
        #[derive(Debug, Copy, Clone)]
        pub struct $Name($($field),+);
        
        impl VertexData for $Name {
            type Output = $Name;
            fn get_format() -> VertexFormat {
                VertexFormatBuilder::new()
                    $(.push::<$field>(false))+
                    .build()
            }
        }
    };
}