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
125
126
127
128
129
130
131
132
133
134
135
136
137
use std::ops::{Deref, DerefMut};

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

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

#[derive(Debug, 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);
            }
        }
    }
}