fluffl 0.0.5

A cross-platform multimedia layer that exposes opengl,sockets,and audio utilities for desktop and browser
Documentation
use std::any::Any;

use super::*;
use crate::*;

#[derive(Copy, Clone)]
pub struct BufferInfo {
    pub target: u32,
    pub usage: u32,
    pub index: u32,
    pub num_comps: u32,
}

impl Default for BufferInfo {
    fn default() -> Self {
        Self {
            target: glow::ARRAY_BUFFER,
            usage: glow::DYNAMIC_DRAW,
            index: 0,
            num_comps: 1,
        }
    }
}

pub struct OglBuf<T> {
    data: T,
    gl_buf: Option<glow::Buffer>,
    gl: GlowGL,
    info: BufferInfo,
}

pub trait HasBufferObj: HasData + Bindable {
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
    fn info(&self) -> &BufferInfo;
    fn update(&self);
}

pub trait HasBufferBuilder {
    type InnerStruct;
    type VecItemType;
    fn with_target(self, target: u32) -> OglIncomplete<Self::InnerStruct>;
    fn with_usage(self, usage: u32) -> OglIncomplete<Self::InnerStruct>;
    fn with_index(self, index: u32) -> OglIncomplete<Self::InnerStruct>;
    fn with_num_comps(self, comps: u32) -> OglIncomplete<Self::InnerStruct>;
    fn with_data(self, data: Vec<Self::VecItemType>) -> OglIncomplete<Self::InnerStruct>;
    fn build(self) -> Self::InnerStruct;
}

impl<T> HasBufferBuilder for OglIncomplete<OglBuf<Vec<T>>>
where
    T: Copy + Default,
{
    type InnerStruct = OglBuf<Vec<T>>;
    type VecItemType = T;

    fn with_target(mut self, target: u32) -> Self {
        self.inner.info.target = target;
        self
    }

    fn with_usage(mut self, usage: u32) -> Self {
        self.inner.info.usage = usage;
        self
    }

    fn with_index(mut self, index: u32) -> Self {
        self.inner.info.index = index;
        self
    }
    fn with_num_comps(mut self, comps: u32) -> Self {
        self.inner.info.num_comps = comps;
        self
    }

    fn with_data(mut self, data: Vec<Self::VecItemType>) -> Self {
        self.inner.data = data;
        self
    }

    fn build(self) -> Self::InnerStruct {
        let mut new_self = self.inner;

        let gl = new_self.gl.clone();
        let target = new_self.info.target;
        unsafe {
            new_self.gl_buf = Some(gl.create_buffer().unwrap());
            gl.bind_buffer(target, new_self.gl_buf);
            gl.buffer_data_u8_slice(target, new_self.data.raw_bytes(), new_self.info.usage);
        }
        new_self
    }
}

impl<T> OglBuf<Vec<T>>
where
    T: Default + Copy + Sized,
    Vec<T>: HasData,
{
    pub fn new(gl: &GlowGL) -> OglIncomplete<Self> {
        OglIncomplete::new(Self {
            data: Vec::new(),
            gl_buf: None,
            gl: gl.clone(),
            info: BufferInfo::default(),
        })
    }
}

impl<T> Bindable for OglBuf<T> {
    fn bind(&self, ok: bool) {
        let gl = self.gl.clone();
        unsafe {
            gl.bind_buffer(self.info.target, ok.map(|| self.gl_buf).flatten());
        }
    }
}

impl<T> HasBufferObj for OglBuf<Vec<T>>
where
    Vec<T>: HasData,
    T: 'static,
{
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }

    fn info(&self) -> &BufferInfo {
        &self.info
    }

    fn update(&self) {
        let gl = &self.gl;
        self.bind(true);
        unsafe {
            gl.buffer_sub_data_u8_slice(self.info.target, 0, self.raw_bytes());
        }
    }
}

impl<T> HasData for OglBuf<Vec<T>>
where
    Vec<T>: HasData,
{
    fn raw_bytes(&self) -> &[u8] {
        self.data.raw_bytes()
    }
    fn raw_bytes_mut(&mut self) -> &mut [u8] {
        self.data.raw_bytes_mut()
    }
}

impl<T> Drop for OglBuf<T> {
    fn drop(&mut self) {
        unsafe {
            self.gl.delete_buffer(self.gl_buf.unwrap());
        }
    }
}

impl<T> From<OglBuf<Vec<T>>> for Box<dyn HasBufferObj>
where
    T: 'static,
    Vec<T>: HasData,
{
    fn from(bo: OglBuf<Vec<T>>) -> Self {
        Box::new(bo)
    }
}