mod3d_gl/
buffer.rs

1//a Imports
2use std::marker::PhantomData;
3
4use mod3d_base::{BufferDataAccessor, BufferElementType, BufferIndexAccessor, VertexAttr};
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, view: &BufferDataAccessor<G>, render_context: &mut G) {
51        view.data.create_client(render_context);
52        self.elements_per_data = view.elements_per_data;
53        self.ele_type = view.ele_type;
54        self.byte_offset = view.byte_offset;
55        self.stride = view.stride;
56        self.gl_buffer = view.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        println!(
205            "Create indices buffer {} of view {:?}#{}",
206            gl_buffer, ele_type, count
207        );
208        Self {
209            gl_buffer,
210            count,
211            ele_type,
212        }
213    }
214    //ap gl_buffer
215    pub fn gl_buffer(&self) -> &<G as Gl>::Buffer {
216        &self.gl_buffer
217    }
218
219    //zz All done
220}
221
222//ip Display for IndexBuffer
223impl<G> std::fmt::Display for IndexBuffer<G>
224where
225    G: Gl,
226{
227    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
228        write!(
229            f,
230            "Ind({:?}#{} {:?})",
231            self.gl_buffer, self.count, self.ele_type,
232        )
233    }
234}
235
236//ip DefaultIndentedDisplay for IndexBuffer
237impl<G> indent_display::DefaultIndentedDisplay for IndexBuffer<G> where G: Gl {}
238
239//a BufferView
240//tp BufferView
241///
242/// A view of data with either vertices of indices
243#[derive(Debug)]
244pub enum BufferView<G>
245where
246    G: Gl,
247{
248    /// Vertex buffer
249    VertexBuffer(VertexBuffer<G>),
250    /// Index buffer
251    IndexBuffer(IndexBuffer<G>),
252}
253
254//ip Default for BufferView<G>
255impl<G> Default for BufferView<G>
256where
257    G: Gl,
258{
259    fn default() -> Self {
260        Self::VertexBuffer(VertexBuffer::default())
261    }
262}
263
264//ip Clone for BufferView<G>
265impl<G> Clone for BufferView<G>
266where
267    G: Gl,
268{
269    fn clone(&self) -> Self {
270        use BufferView::*;
271        match self {
272            VertexBuffer(b) => Self::VertexBuffer(b.clone()),
273            IndexBuffer(b) => Self::IndexBuffer(b.clone()),
274        }
275    }
276}
277
278//ip BufferView
279impl<G> BufferView<G>
280where
281    G: Gl,
282{
283    //fp as_index_buffer
284    /// Return the [IndexBuffer] that this [BufferView] is of - if it
285    /// is not a view of indices then panic
286    pub fn as_index_buffer(&self) -> &IndexBuffer<G> {
287        match self {
288            Self::IndexBuffer(index_buffer) => index_buffer,
289            _ => panic!("Attempt to borrow a VertexBuffer as an IndexBuffer"),
290        }
291    }
292
293    //fp as_vertex_buffer
294    /// Return the [VertexBuffer] that this [BufferView] is of - if it
295    /// is not a view of vertex attributess then panic
296    pub fn as_vertex_buffer(&self) -> &VertexBuffer<G> {
297        match self {
298            Self::VertexBuffer(vertex_buffer) => vertex_buffer,
299            _ => panic!("Attempt to borrow an IndexBuffer as an VertexBuffer"),
300        }
301    }
302
303    //mp init_index_accessor_client
304    /// Create the OpenGL ARRAY_BUFFER buffer using STATIC_DRAW - this copies the data in to OpenGL
305    pub fn init_index_accessor_client(
306        &mut self,
307        buffer_view: &BufferIndexAccessor<G>,
308        renderer: &mut G,
309    ) {
310        let index_buffer = IndexBuffer::of_view(buffer_view, renderer);
311        *self = BufferView::IndexBuffer(index_buffer);
312    }
313
314    //mp init_buffer_view_client
315    /// Create the OpenGL ARRAY_BUFFER buffer using STATIC_DRAW - this copies the data in to OpenGL
316    pub fn init_buffer_view_client(
317        &mut self,
318        buffer_view: &BufferDataAccessor<G>,
319        attr: VertexAttr,
320        renderer: &mut G,
321    ) {
322        match self {
323            BufferView::IndexBuffer(_) => panic!("Vertex buffer is already an index buffer"),
324            BufferView::VertexBuffer(vb) => {
325                vb.of_view(buffer_view, renderer);
326            }
327        }
328    }
329}
330
331//ip AccessorClient for BufferView
332impl<G> mod3d_base::AccessorClient for BufferView<G> where G: Gl {}
333
334//ip Display for BufferView
335impl<G> std::fmt::Display for BufferView<G>
336where
337    G: Gl,
338{
339    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
340        match self {
341            Self::IndexBuffer(index_buffer) => index_buffer.fmt(f),
342            Self::VertexBuffer(vertex_buffer) => vertex_buffer.fmt(f),
343        }
344    }
345}
346
347//ip DefaultIndentedDisplay for BufferView
348impl<G> indent_display::DefaultIndentedDisplay for BufferView<G> where G: Gl {}
349
350//a UniformBuffer
351//tp UniformBuffer
352/// Creates a UniformBuffer that may contain the data for a number of program Uniforms
353///
354/// For simplicity in OpenGl/WebGl this also creates the backing GlBuffer
355///
356/// A program's uniform is bound to a *range* of one of these
357#[derive(Debug)]
358pub struct UniformBuffer<G>
359where
360    G: Gl,
361{
362    /// Ref-cotunted GPU gl buffer to use
363    gl_buffer: <G as Gl>::Buffer,
364    /// This is the size of the buffer (so that length=0 can map to the whole buffer)
365    byte_length: usize,
366    phantom: PhantomData<G>,
367}
368
369//ip UniformBuffer
370impl<G> UniformBuffer<G>
371where
372    G: Gl,
373{
374    //fp of_data
375    pub fn of_data<F: Sized>(context: &mut G, data: &[F], is_dynamic: bool) -> Result<Self, ()> {
376        G::uniform_buffer_create(context, data, is_dynamic)
377    }
378
379    //fp new
380    pub fn new(gl_buffer: <G as Gl>::Buffer, byte_length: usize) -> Self {
381        Self {
382            gl_buffer,
383            byte_length,
384            phantom: PhantomData,
385        }
386    }
387
388    //ap gl_buffer
389    /// Get the gl_buffer associated with the data, assuming its
390    /// `gl_create` method has been invoked at least once
391    pub fn gl_buffer(&self) -> &<G as Gl>::Buffer {
392        &self.gl_buffer
393    }
394
395    //ap byte_length
396    pub fn byte_length(&self) -> usize {
397        self.byte_length
398    }
399
400    //ap offset_and_length
401    pub fn offset_and_length(&self, byte_offset: usize, byte_length: usize) -> (usize, usize) {
402        if byte_length == 0 {
403            (0, self.byte_length)
404        } else {
405            (byte_offset, byte_length)
406        }
407    }
408}