three_d/core/buffer/
uniform_buffer.rs

1use crate::core::*;
2
3///
4/// A buffer for transferring a set of uniform variables to the shader program
5/// (see also [use_uniform_block](crate::core::Program::use_uniform_block)).
6///
7pub struct UniformBuffer {
8    context: Context,
9    id: crate::context::Buffer,
10    offsets: Vec<usize>,
11    data: Vec<f32>,
12}
13
14impl UniformBuffer {
15    ///
16    /// Creates a new uniform buffer with room for a set of variables of varying length defined by the `sizes` argument.
17    /// So for example if you create a uniform buffer with `&[3, 1, 4, 16]` as the `sizes` argument, you will have a uniform buffer that has four variables:
18    /// The first with 3 elements (a [Vec3]), the second with 1 element (a `f32`), the third with four elements (a [Vec4]) and the last with 16 elements (a [Mat4]).
19    /// The variables are initialized to 0.
20    ///
21    pub fn new(context: &Context, sizes: &[u32]) -> UniformBuffer {
22        let id = unsafe { context.create_buffer().expect("Failed creating buffer") };
23
24        let mut offsets = Vec::new();
25        let mut length = 0;
26        for size in sizes {
27            offsets.push(length);
28            length += *size as usize;
29        }
30        let buffer = UniformBuffer {
31            context: context.clone(),
32            id,
33            offsets,
34            data: vec![0.0; length],
35        };
36        buffer.send();
37        buffer
38    }
39
40    pub(crate) fn bind(&self, id: u32) {
41        unsafe {
42            self.context
43                .bind_buffer_base(crate::context::UNIFORM_BUFFER, id, Some(self.id))
44        };
45    }
46
47    ///
48    /// Update the values of the variable at the given index with the given data.
49    ///
50    /// # Panic
51    /// Will panic if the index is not in the range `[0-max]` where `max` is the length of the `sizes` argument given at construction.
52    /// Will panic if the data length does not match the element count of the variable (defined at construction) at the given index.
53    ///
54    pub fn update(&mut self, index: u32, data: &[f32]) {
55        if let Some((offset, length)) = self.offset_length(index as usize) {
56            if data.len() != length {
57                panic!(
58                    "data for element at index {0} has length {1} but a length of {2} was expected",
59                    index,
60                    data.len(),
61                    length,
62                );
63            }
64            self.data
65                .splice(offset..offset + length, data.iter().cloned());
66            self.send();
67        } else {
68            panic!(
69                "the index {} is outside the expected range [0, {}]",
70                index,
71                self.offsets.len() - 1
72            );
73        }
74        //TODO: Send to GPU (contextBufferSubData)
75    }
76
77    ///
78    /// Returns the values of the variable at the given index if inside the range of variables, otherwise `None`.
79    ///
80    pub fn get(&self, index: u32) -> Option<&[f32]> {
81        self.offset_length(index as usize)
82            .map(|(offset, length)| &self.data[offset..offset + length])
83    }
84
85    fn offset_length(&self, index: usize) -> Option<(usize, usize)> {
86        if index >= self.offsets.len() {
87            None
88        } else {
89            let offset = self.offsets[index];
90            let length = if index + 1 == self.offsets.len() {
91                self.data.len()
92            } else {
93                self.offsets[index + 1]
94            } - offset;
95            Some((offset, length))
96        }
97    }
98
99    fn send(&self) {
100        unsafe {
101            self.context
102                .bind_buffer(crate::context::UNIFORM_BUFFER, Some(self.id));
103            self.context.buffer_data_u8_slice(
104                crate::context::UNIFORM_BUFFER,
105                to_byte_slice(&self.data),
106                crate::context::STATIC_DRAW,
107            );
108            self.context
109                .bind_buffer(crate::context::UNIFORM_BUFFER, None);
110        }
111    }
112}
113
114impl Drop for UniformBuffer {
115    fn drop(&mut self) {
116        unsafe {
117            self.context.delete_buffer(self.id);
118        }
119    }
120}