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
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::cell::Cell;
use std::marker::PhantomData;
use std::rc::Rc;
use web_sys::{WebGlBuffer, WebGlRenderingContext as Context, WebGlRenderingContext};
use crate::buffer_usage::BufferUsage;
use super::gl::{Gl, GlError};
use super::settings::Settings;
use super::types::DataType;
pub trait Writable: Copy {
fn write(&self, output: &mut Vec<f32>);
fn stride() -> usize;
}
#[derive(Debug, Clone)]
pub struct ArrayBufferData {
pub(self) gl: Gl,
pub(self) handle: WebGlBuffer,
pub(self) length: Cell<usize>,
}
impl Drop for ArrayBufferData {
fn drop(&mut self) {
self.gl.context().delete_buffer(Some(&self.handle));
}
}
#[derive(Debug, Clone)]
pub struct ArrayBuffer {
pub(self) data: Rc<ArrayBufferData>,
}
impl PartialEq<ArrayBuffer> for ArrayBuffer {
fn eq(&self, other: &ArrayBuffer) -> bool {
self.data.handle == other.data.handle
}
}
impl Eq for ArrayBuffer {}
impl ArrayBuffer {
pub fn new<T: Writable>(
gl: Gl,
data: &[T],
usage: BufferUsage,
) -> Result<ArrayBuffer, GlError> {
let ref context: &WebGlRenderingContext = gl.context();
let buffer = context
.create_buffer()
.ok_or(GlError::BufferAllocationError)?;
let result = ArrayBuffer {
data: Rc::new(ArrayBufferData {
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<T: Writable>(&self, items: &[T], usage: BufferUsage) {
let mut data: Vec<f32> = Vec::with_capacity(T::stride() * items.len());
for i in items {
i.write(&mut data);
}
self.data
.gl
.apply(Gl::settings().array_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(
Context::ARRAY_BUFFER,
&bytes,
usage.into(),
);
});
self.data.length.set(items.len());
}
pub fn len(&self) -> usize {
self.data.length.get()
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Layout {
pub name: &'static str,
pub data_type: DataType,
}
pub trait Item: Writable {
fn layout() -> Vec<Layout>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ItemsBuffer<T: Item> {
pub(self) phantom: PhantomData<T>,
pub(crate) buffer: ArrayBuffer,
}
impl<T: Item> ItemsBuffer<T> {
pub fn new(gl: Gl, data: &[T], usage: BufferUsage) -> Result<ItemsBuffer<T>, GlError> {
Ok(ItemsBuffer {
phantom: Default::default(),
buffer: ArrayBuffer::new(gl, data, usage)?,
})
}
pub fn set_content(&self, items: &[T], usage: BufferUsage) {
self.buffer.set_content(items, usage);
}
pub fn len(&self) -> usize {
self.buffer.len()
}
}