mod3d_gl/
buffer.rs

1//a Imports
2use std::marker::PhantomData;
3
4use mod3d_base::{BufferDataAccessor, BufferElementType, BufferIndexAccessor};
5
6use crate::{Gl, GlProgram};
7
8//a VertexBuffer
9//tp VertexBuffer
10///
11/// A subset of a data buffer for use with OpenGL vertex data.
12///
13/// A data buffer may contain a lot of data per vertex, such as
14/// position, normal, tangent, color etc.  A [VertexBuffer] is
15/// then a subset of this data - perhaps picking out just the
16/// position, for example, for a set of vertices
17///
18/// OpenGL will have one copy of the data for all the [VertexBuffer]
19#[derive(Debug)]
20pub struct VertexBuffer<G>
21where
22    G: Gl,
23{
24    /// Ref-counted buffer
25    gl_buffer: <G as Gl>::Buffer,
26    /// Number of elements per vertex (1 to 4, or 4, 9 or 16)
27    pub elements_per_data: u32,
28    /// The type of each element
29    pub ele_type: BufferElementType,
30    /// Offset from start of buffer to first byte of data
31    pub byte_offset: u32,
32    /// Stride of data in the buffer - 0 for elements_per_data*sizeof(ele_type)
33    pub stride: u32,
34}
35
36//ip VertexBuffer
37impl<G> VertexBuffer<G>
38where
39    G: Gl,
40{
41    //ap gl_buffer
42    /// Get the gl_buffer associated with the data, assuming its
43    /// `gl_create` method has been invoked at least once
44    pub fn gl_buffer(&self) -> &<G as Gl>::Buffer {
45        &self.gl_buffer
46    }
47
48    //mp of_view
49    /// Create the OpenGL ARRAY_BUFFER buffer using STATIC_DRAW - this copies the data in to OpenGL
50    fn of_view(&mut self, bda: &BufferDataAccessor<G>, render_context: &mut G) {
51        bda.desc().data().create_client(render_context);
52        self.elements_per_data = bda.count();
53        self.ele_type = bda.ele_type();
54        self.byte_offset = bda.desc().byte_offset();
55        self.stride = bda.desc().stride();
56        self.gl_buffer = bda.desc().data().borrow_client().clone();
57    }
58
59    //fp bind_to_vao_attr
60    /// Bind the buffer as a vertex attribute to the current VAO
61    pub fn bind_to_vao_attr(
62        &self,
63        context: &mut G,
64        attr_id: &<<G as Gl>::Program as GlProgram>::GlAttrId,
65    ) {
66        context.buffer_bind_to_vao_attr(
67            &self.gl_buffer,
68            attr_id,
69            self.elements_per_data,
70            self.ele_type,
71            self.byte_offset,
72            self.stride,
73        );
74    }
75
76    //zz All done
77}
78
79//ip Default for VertexBuffer
80impl<G> Default for VertexBuffer<G>
81where
82    G: Gl,
83{
84    fn default() -> Self {
85        let gl_buffer = <G as Gl>::Buffer::default();
86        let elements_per_data = 0;
87        let ele_type = BufferElementType::float32();
88        let byte_offset = 0;
89        let stride = 0;
90        Self {
91            gl_buffer,
92            elements_per_data,
93            ele_type,
94            byte_offset,
95            stride,
96        }
97    }
98}
99
100//ip Clone for VertexBuffer
101impl<G> Clone for VertexBuffer<G>
102where
103    G: Gl,
104{
105    fn clone(&self) -> Self {
106        let gl_buffer = self.gl_buffer.clone();
107        let elements_per_data = self.elements_per_data;
108        let ele_type = self.ele_type;
109        let byte_offset = self.byte_offset;
110        let stride = self.stride;
111        Self {
112            gl_buffer,
113            elements_per_data,
114            ele_type,
115            byte_offset,
116            stride,
117        }
118    }
119}
120
121//ip Display for VertexBuffer
122impl<G> std::fmt::Display for VertexBuffer<G>
123where
124    G: Gl,
125{
126    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
127        write!(
128            f,
129            "Vert({:?}+{}:#{} {:?} @{})",
130            self.gl_buffer, self.byte_offset, self.elements_per_data, self.ele_type, self.stride
131        )
132    }
133}
134
135//ip DefaultIndentedDisplay for VertexBuffer
136impl<G> indent_display::DefaultIndentedDisplay for VertexBuffer<G> where G: Gl {}
137
138//a IndexBuffer
139//tp IndexBuffer
140///
141/// A subset of a data buffer for use with OpenGL index data.
142///
143/// An IndexBuffer directly owns the OpenGL buffer which is an
144/// ElementArray rather than vertex data
145#[derive(Debug)]
146pub struct IndexBuffer<G>
147where
148    G: Gl,
149{
150    /// Ref-counted buffer
151    gl_buffer: <G as Gl>::Buffer,
152    /// Number of indices in the buffer
153    pub count: u32,
154    /// The type of each element
155    pub ele_type: BufferElementType,
156}
157
158//ip Default for IndexBuffer
159impl<G> Default for IndexBuffer<G>
160where
161    G: Gl,
162{
163    fn default() -> Self {
164        let gl_buffer = <G as Gl>::Buffer::default();
165        let count = 0;
166        let ele_type = BufferElementType::UInt8;
167        Self {
168            gl_buffer,
169            count,
170            ele_type,
171        }
172    }
173}
174
175//ip Clone for IndexBuffer
176impl<G> Clone for IndexBuffer<G>
177where
178    G: Gl,
179{
180    fn clone(&self) -> Self {
181        let gl_buffer = self.gl_buffer.clone();
182        let count = self.count;
183        let ele_type = self.ele_type;
184        Self {
185            gl_buffer,
186            count,
187            ele_type,
188        }
189    }
190}
191
192//ip IndexBuffer
193impl<G> IndexBuffer<G>
194where
195    G: Gl,
196{
197    //mp of_view
198    /// Create the OpenGL ARRAY_BUFFER buffer using STATIC_DRAW - this copies the data in to OpenGL
199    fn of_view(view: &BufferIndexAccessor<G>, render_context: &mut G) -> Self {
200        let mut gl_buffer = <G as Gl>::Buffer::default();
201        render_context.init_buffer_of_indices(&mut gl_buffer, view);
202        let count = view.number_indices();
203        let ele_type = view.ele_type();
204        // eprintln!("Create indices buffer {gl_buffer} of view {ele_type:?}#{count}");
205        Self {
206            gl_buffer,
207            count,
208            ele_type,
209        }
210    }
211    //ap gl_buffer
212    pub fn gl_buffer(&self) -> &<G as Gl>::Buffer {
213        &self.gl_buffer
214    }
215
216    //zz All done
217}
218
219//ip Display for IndexBuffer
220impl<G> std::fmt::Display for IndexBuffer<G>
221where
222    G: Gl,
223{
224    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
225        write!(
226            f,
227            "Ind({:?}#{} {:?})",
228            self.gl_buffer, self.count, self.ele_type,
229        )
230    }
231}
232
233//ip DefaultIndentedDisplay for IndexBuffer
234impl<G> indent_display::DefaultIndentedDisplay for IndexBuffer<G> where G: Gl {}
235
236//a BufferView
237//tp BufferView
238///
239/// A view of data with either vertices of indices
240#[derive(Debug)]
241pub enum BufferView<G>
242where
243    G: Gl,
244{
245    /// Vertex buffer
246    VertexBuffer(VertexBuffer<G>),
247    /// Index buffer
248    IndexBuffer(IndexBuffer<G>),
249}
250
251//ip Default for BufferView<G>
252impl<G> Default for BufferView<G>
253where
254    G: Gl,
255{
256    fn default() -> Self {
257        Self::VertexBuffer(VertexBuffer::default())
258    }
259}
260
261//ip Clone for BufferView<G>
262impl<G> Clone for BufferView<G>
263where
264    G: Gl,
265{
266    fn clone(&self) -> Self {
267        use BufferView::*;
268        match self {
269            VertexBuffer(b) => Self::VertexBuffer(b.clone()),
270            IndexBuffer(b) => Self::IndexBuffer(b.clone()),
271        }
272    }
273}
274
275//ip BufferView
276impl<G> BufferView<G>
277where
278    G: Gl,
279{
280    //fp as_index_buffer
281    /// Return the [IndexBuffer] that this [BufferView] is of - if it
282    /// is not a view of indices then panic
283    pub fn as_index_buffer(&self) -> &IndexBuffer<G> {
284        match self {
285            Self::IndexBuffer(index_buffer) => index_buffer,
286            _ => panic!("Attempt to borrow a VertexBuffer as an IndexBuffer"),
287        }
288    }
289
290    //fp as_vertex_buffer
291    /// Return the [VertexBuffer] that this [BufferView] is of - if it
292    /// is not a view of vertex attributess then panic
293    pub fn as_vertex_buffer(&self) -> &VertexBuffer<G> {
294        match self {
295            Self::VertexBuffer(vertex_buffer) => vertex_buffer,
296            _ => panic!("Attempt to borrow an IndexBuffer as an VertexBuffer"),
297        }
298    }
299
300    //mp init_index_accessor_client
301    /// Create the OpenGL ARRAY_BUFFER buffer using STATIC_DRAW - this copies the data in to OpenGL
302    pub fn init_index_accessor_client(
303        &mut self,
304        buffer_view: &BufferIndexAccessor<G>,
305        renderer: &mut G,
306    ) {
307        let index_buffer = IndexBuffer::of_view(buffer_view, renderer);
308        *self = BufferView::IndexBuffer(index_buffer);
309    }
310
311    //mp init_data_accessor_client
312    /// Create the OpenGL ARRAY_BUFFER buffer using STATIC_DRAW - this copies the data in to OpenGL
313    pub fn init_data_accessor_client(
314        &mut self,
315        buffer_data_accessor: &BufferDataAccessor<G>,
316        renderer: &mut G,
317    ) {
318        match self {
319            BufferView::IndexBuffer(_) => panic!("Vertex buffer is already an index buffer"),
320            BufferView::VertexBuffer(vb) => {
321                vb.of_view(buffer_data_accessor, renderer);
322            }
323        }
324    }
325}
326
327//ip AccessorClient for BufferView
328impl<G> mod3d_base::AccessorClient for BufferView<G> where G: Gl {}
329
330//ip Display for BufferView
331impl<G> std::fmt::Display for BufferView<G>
332where
333    G: Gl,
334{
335    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
336        match self {
337            Self::IndexBuffer(index_buffer) => index_buffer.fmt(f),
338            Self::VertexBuffer(vertex_buffer) => vertex_buffer.fmt(f),
339        }
340    }
341}
342
343//ip DefaultIndentedDisplay for BufferView
344impl<G> indent_display::DefaultIndentedDisplay for BufferView<G> where G: Gl {}
345
346//a UniformBuffer
347//tp UniformBuffer
348/// Creates a UniformBuffer that may contain the data for a number of program Uniforms
349///
350/// For simplicity in OpenGl/WebGl this also creates the backing GlBuffer
351///
352/// A program's uniform is bound to a *range* of one of these
353#[derive(Debug)]
354pub struct UniformBuffer<G>
355where
356    G: Gl,
357{
358    /// Ref-cotunted GPU gl buffer to use
359    gl_buffer: <G as Gl>::Buffer,
360    /// This is the size of the buffer (so that length=0 can map to the whole buffer)
361    byte_length: usize,
362    phantom: PhantomData<G>,
363}
364
365//ip UniformBuffer
366impl<G> UniformBuffer<G>
367where
368    G: Gl,
369{
370    //fp of_data
371    pub fn of_data<F: Sized>(context: &mut G, data: &[F], is_dynamic: bool) -> Result<Self, ()> {
372        G::uniform_buffer_create(context, data, is_dynamic)
373    }
374
375    //fp new
376    pub fn new(gl_buffer: <G as Gl>::Buffer, byte_length: usize) -> Self {
377        Self {
378            gl_buffer,
379            byte_length,
380            phantom: PhantomData,
381        }
382    }
383
384    //ap gl_buffer
385    /// Get the gl_buffer associated with the data, assuming its
386    /// `gl_create` method has been invoked at least once
387    pub fn gl_buffer(&self) -> &<G as Gl>::Buffer {
388        &self.gl_buffer
389    }
390
391    //ap byte_length
392    pub fn byte_length(&self) -> usize {
393        self.byte_length
394    }
395
396    //ap offset_and_length
397    pub fn offset_and_length(&self, byte_offset: usize, byte_length: usize) -> (usize, usize) {
398        if byte_length == 0 {
399            (0, self.byte_length)
400        } else {
401            (byte_offset, byte_length)
402        }
403    }
404}