summaryrefslogtreecommitdiff
path: root/engine/src/renderer/opengl/graphics_mesh.rs
blob: dc839a895ebdc12155dd40561b83d028b97d2973 (plain)
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
130
use opengl_bindings::CurrentContextWithFns as GlCurrentContextWithFns;
use opengl_bindings::buffer::{Buffer as GlBuffer, Usage as GlBufferUsage};
use opengl_bindings::vertex_array::{
    DataType as GlVertexArrayDataType,
    VertexArray as GlVertexArray,
};

use crate::mesh::Mesh;
use crate::renderer::opengl::vertex::{
    AttributeComponentType as VertexAttributeComponentType,
    Vertex as RendererVertex,
};

#[derive(Debug)]
pub struct GraphicsMesh
{
    /// Vertex and index buffer has to live as long as the vertex array
    vertex_buffer: GlBuffer<RendererVertex>,
    pub index_buffer: Option<GlBuffer<u32>>,
    pub element_cnt: u32,
    pub vertex_arr: GlVertexArray,
}

impl GraphicsMesh
{
    #[tracing::instrument(skip_all)]
    pub fn new(
        current_context: &GlCurrentContextWithFns<'_>,
        mesh: &Mesh,
    ) -> Result<Self, Error>
    {
        tracing::trace!(
            "Creating vertex array, vertex buffer{}",
            if mesh.indices().is_some() {
                " and index buffer"
            } else {
                ""
            }
        );

        let vertex_arr = GlVertexArray::new(current_context);
        let vertex_buffer = GlBuffer::new(current_context);

        vertex_buffer
            .store_mapped(
                current_context,
                mesh.vertices(),
                GlBufferUsage::Static,
                |vertex| RendererVertex {
                    pos: vertex.pos.into(),
                    texture_coords: vertex.texture_coords.into(),
                    normal: vertex.normal.into(),
                },
            )
            .map_err(Error::StoreVerticesFailed)?;

        vertex_arr.bind_vertex_buffer(current_context, 0, &vertex_buffer, 0);

        let mut offset = 0u32;

        for attrib in RendererVertex::attrs() {
            vertex_arr.enable_attrib(current_context, attrib.index);

            vertex_arr.set_attrib_format(
                current_context,
                attrib.index,
                match attrib.component_type {
                    VertexAttributeComponentType::Float => GlVertexArrayDataType::Float,
                },
                false,
                offset,
            );

            vertex_arr.set_attrib_vertex_buf_binding(current_context, attrib.index, 0);

            offset += attrib.component_size * attrib.component_cnt as u32;
        }

        if let Some(indices) = mesh.indices() {
            let index_buffer = GlBuffer::new(current_context);

            index_buffer
                .store(current_context, indices, GlBufferUsage::Static)
                .map_err(Error::StoreIndicesFailed)?;

            vertex_arr.bind_element_buffer(current_context, &index_buffer);

            return Ok(Self {
                vertex_buffer: vertex_buffer,
                index_buffer: Some(index_buffer),
                element_cnt: indices
                    .len()
                    .try_into()
                    .expect("Mesh index count does not fit into a 32-bit unsigned int"),
                vertex_arr,
            });
        }

        Ok(Self {
            vertex_buffer: vertex_buffer,
            index_buffer: None,
            element_cnt: mesh
                .vertices()
                .len()
                .try_into()
                .expect("Mesh vertex count does not fit into a 32-bit unsigned int"),
            vertex_arr,
        })
    }

    pub fn destroy(&mut self, curr_gl_ctx: &GlCurrentContextWithFns<'_>)
    {
        self.vertex_arr.delete(curr_gl_ctx);
        self.vertex_buffer.delete(curr_gl_ctx);

        if let Some(index_buffer) = &self.index_buffer {
            index_buffer.delete(curr_gl_ctx);
        }
    }
}

#[derive(Debug, thiserror::Error)]
pub enum Error
{
    #[error("Failed to store vertices in vertex buffer")]
    StoreVerticesFailed(#[source] opengl_bindings::buffer::Error),

    #[error("Failed to store indices in index buffer")]
    StoreIndicesFailed(#[source] opengl_bindings::buffer::Error),
}