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
use std::cell::Cell;
use std::rc::Rc;
use web_sys::{WebGlBuffer, WebGlRenderingContext};
use crate::{BufferUsage, Gl, GlError};
use crate::settings::Settings;

#[derive(Debug, Clone)]
pub struct ElementBufferData {
    pub(self) gl: Gl,
    pub(self) handle: WebGlBuffer,
    pub(self) length: Cell<usize>,
}

impl Drop for ElementBufferData {
    fn drop(&mut self) {
        self.gl.context().delete_buffer(Some(&self.handle));
    }
}

#[derive(Debug, Clone)]
pub struct ElementBuffer {
    pub(self) data: Rc<ElementBufferData>,
}

impl PartialEq<ElementBuffer> for ElementBuffer {
    fn eq(&self, other: &ElementBuffer) -> bool {
        self.data.handle == other.data.handle
    }
}

impl Eq for ElementBuffer {}

impl ElementBuffer {
    pub fn new(
        gl: Gl,
        data: &[u32],
        usage: BufferUsage,
    ) -> Result<ElementBuffer, GlError> {
        let ref context: &WebGlRenderingContext = gl.context();
        let buffer = context
            .create_buffer()
            .ok_or(GlError::BufferAllocationError)?;

        let result = ElementBuffer {
            data: Rc::new(ElementBufferData {
                gl: gl.clone(),
                handle: buffer,
                length: Default::default(),
            }),
        };

        result.set_content(data, usage);

        return Ok(result);
    }

    pub(crate) fn handle(&self) -> WebGlBuffer {
        self.data.handle.clone()
    }

    pub fn set_content(&self, data: &[u32], usage: BufferUsage) {
        self.data
            .gl
            .apply(Gl::settings().element_buffer(self.clone()), || {
                let bytes = unsafe {
                    std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4)
                };
                self.data.gl.context().buffer_data_with_u8_array(
                    WebGlRenderingContext::ELEMENT_ARRAY_BUFFER,
                    &bytes,
                    usage.into(),
                );
            });

        self.data.length.set(data.len());
    }

    pub fn len(&self) -> usize {
        self.data.length.get()
    }
}