1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use alloc::vec::Vec;

use core::ops::{Drop, Deref, DerefMut};

use gl;
use gl::types::*;

use super::{GLAttribute, GLBuffer, GLVertex, gl_major};


#[derive(Debug, Clone, Hash)]
pub struct GLVertexArray {
    id: GLuint,
    array: Vec<GLVertex>,
}

impl GLVertexArray {

    #[inline(always)]
    pub fn new() -> Self {
        GLVertexArray {
            id: {
                let mut id = 0;
                if gl_major() > 2 {
                    unsafe { gl::GenVertexArrays(1, &mut id); }
                }
                id
            },
            array: Vec::new(),
        }
    }

    #[inline]
    pub fn bind(&self) -> &Self {
        let gl_major = gl_major();

        if gl_major > 2 {
            unsafe { gl::BindVertexArray(self.id()); }
        }

        self.enable_attributes();

        if gl_major < 3 {
            for gl_vertex in &self.array {
                gl_vertex.bind();
            }
        }

        self
    }
    #[inline]
    pub fn unbind(&self) -> &Self {
        if gl_major() > 2 {
            unsafe { gl::BindVertexArray(0); }
        }
        self.disable_attributes();
        self
    }

    #[inline]
    pub fn enable_attributes(&self) -> &Self {
        for gl_vertex in &self.array {
            gl_vertex.enable();
        }
        self
    }
    #[inline]
    pub fn disable_attributes(&self) -> &Self {
        for gl_vertex in &self.array {
            gl_vertex.disable();
        }
        self
    }

    #[inline]
    pub fn add_attribute(
        &mut self,
        gl_buffer: &GLBuffer,
        gl_attribute: &GLAttribute,
        offset: usize
    ) -> &mut Self {
        let location = gl_attribute.location();
        let item_count = gl_attribute.item_count();
        let item_kind = gl_attribute.item_kind();
        let offset = offset * gl_buffer.kind_size();

        let gl_vertex = GLVertex::new(location, item_count, item_kind, gl_buffer.stride(), offset);
        gl_vertex.enable();
        gl_vertex.bind();
        self.array.push(gl_vertex);

        self
    }

    #[inline(always)]
    pub fn id(&self) -> GLuint { self.id }

    #[inline(always)]
    pub fn array(&self) -> &[GLVertex] { &*self.array }
    #[inline(always)]
    pub fn array_mut(&mut self) -> &mut [GLVertex] { &mut *self.array }
}

impl Deref for GLVertexArray {
    type Target = [GLVertex];

    #[inline(always)]
    fn deref(&self) -> &Self::Target { self.array() }
}

impl DerefMut for GLVertexArray {

    #[inline(always)]
    fn deref_mut(&mut self) -> &mut Self::Target { self.array_mut() }
}

impl Drop for GLVertexArray {
    #[inline]
    fn drop(&mut self) {
        if self.id != 0 {
            unsafe { gl::DeleteVertexArrays(1, &self.id); }
        }
    }
}