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
use crate::context::{consts, DataType};
use crate::core::*;

/// The basic data type used for each index in an element buffer.
pub trait ElementBufferDataType:
    Default + std::fmt::Debug + Clone + internal::BufferDataTypeExtension
{
    ///
    /// Converts the index to `u32`.
    ///
    fn into_u32(&self) -> u32;
}
impl ElementBufferDataType for u8 {
    fn into_u32(&self) -> u32 {
        *self as u32
    }
}
impl ElementBufferDataType for u16 {
    fn into_u32(&self) -> u32 {
        *self as u32
    }
}
impl ElementBufferDataType for u32 {
    fn into_u32(&self) -> u32 {
        *self
    }
}

///
/// A buffer containing 3 indices for each triangle to be rendered, which is why it is also known as an index buffer.
/// The three indices refer to three places in a set of [VertexBuffer] where the data (position, normal etc.) is found for the three vertices of the triangle.
/// See for example [Program::draw_elements] to use this for drawing.
///
pub struct ElementBuffer {
    context: Context,
    id: crate::context::Buffer,
    count: usize,
    data_type: DataType,
}

impl ElementBuffer {
    ///
    /// Creates a new empty element buffer.
    ///
    pub fn new<T: ElementBufferDataType>(context: &Context) -> ThreeDResult<ElementBuffer> {
        let id = context.create_buffer().unwrap();
        Ok(ElementBuffer {
            context: context.clone(),
            id,
            count: 0,
            data_type: T::data_type(),
        })
    }

    ///
    /// Creates a new element buffer and fills it with the given indices which must be divisable by 3.
    ///
    pub fn new_with<T: ElementBufferDataType>(
        context: &Context,
        data: &[T],
    ) -> ThreeDResult<ElementBuffer> {
        let mut buffer = Self::new::<T>(context)?;
        if data.len() > 0 {
            buffer.fill_with(data)?;
        }
        Ok(buffer)
    }
    ///
    /// Fills the buffer with the given indices which must be divisable by 3.
    ///
    pub fn fill_with<T: ElementBufferDataType>(&mut self, data: &[T]) -> ThreeDResult<()> {
        if data.len() % 3 != 0 {
            Err(CoreError::InvalidBufferLength(
                "index".to_string(),
                data.len(),
            ))?;
        }

        self.bind();
        T::buffer_data(
            &self.context,
            consts::ELEMENT_ARRAY_BUFFER,
            data,
            consts::STATIC_DRAW,
        );
        self.data_type = T::data_type();
        self.context.unbind_buffer(consts::ELEMENT_ARRAY_BUFFER);
        self.count = data.len();
        Ok(())
    }

    ///
    /// The number of elements in the buffer.
    ///
    pub fn count(&self) -> usize {
        self.count
    }

    pub(crate) fn data_type(&self) -> DataType {
        self.data_type
    }

    pub(crate) fn bind(&self) {
        self.context
            .bind_buffer(consts::ELEMENT_ARRAY_BUFFER, &self.id);
    }
}

impl Drop for ElementBuffer {
    fn drop(&mut self) {
        self.context.delete_buffer(&self.id);
    }
}