summaryrefslogtreecommitdiff
path: root/src/mesh.rs
blob: 2f5490372bb6746c5e887da0c87423fadda9b7c3 (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
use std::io::BufRead;

use glow::HasContext;

use crate::context;

pub const ATTRIB_VERTEX: u32 = 0;
pub const ATTRIB_NORMAL: u32 = 1;
pub const ATTRIB_TEXCOORD: u32 = 2;

pub struct Mesh {
    pub vao: glow::VertexArray,
    pub index_count: usize,
}

impl Mesh {
    pub fn build(
        ctx: &context::Context,
        vertices: &Vec<f32>,
        indices: &Vec<u32>,
        snormals: &Option<Vec<f32>>,
        stexcoords: &Option<Vec<f32>>,
    ) -> Self {
        unsafe {
            let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao");
            ctx.gl.bind_vertex_array(Some(vao));

            let vertices_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo");
            ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertices_vbo));
            ctx.gl.buffer_data_u8_slice(
                glow::ARRAY_BUFFER,
                std::slice::from_raw_parts(
                    vertices.as_ptr() as _,
                    vertices.len() * std::mem::size_of::<f32>(),
                ),
                glow::STATIC_DRAW,
            );
            ctx.gl.vertex_attrib_pointer_f32(ATTRIB_VERTEX, 3, glow::FLOAT, false, 0, 0);
            ctx.gl.enable_vertex_attrib_array(ATTRIB_VERTEX);

            let indices_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo");
            ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(indices_vbo));
            ctx.gl.buffer_data_u8_slice(
                glow::ELEMENT_ARRAY_BUFFER,
                std::slice::from_raw_parts(
                    indices.as_ptr() as _,
                    indices.len() * std::mem::size_of::<f32>(),
                ),
                glow::STATIC_DRAW,
            );

            if let Some(normals) = snormals {
                let normals_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo");
                ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(normals_vbo));
                ctx.gl.buffer_data_u8_slice(
                    glow::ARRAY_BUFFER,
                    std::slice::from_raw_parts(
                        normals.as_ptr() as _,
                        normals.len() * std::mem::size_of::<f32>(),
                    ),
                    glow::STATIC_DRAW,
                );
                ctx.gl.vertex_attrib_pointer_f32(ATTRIB_NORMAL, 3, glow::FLOAT, false, 0, 0);
                ctx.gl.enable_vertex_attrib_array(ATTRIB_NORMAL);
            }

            if let Some(texcoords) = stexcoords {
                let texcoords_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo");
                ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(texcoords_vbo));
                ctx.gl.buffer_data_u8_slice(
                    glow::ARRAY_BUFFER,
                    std::slice::from_raw_parts(
                        texcoords.as_ptr() as _,
                        texcoords.len() * std::mem::size_of::<f32>(),
                    ),
                    glow::STATIC_DRAW,
                );
                ctx.gl.vertex_attrib_pointer_f32(ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0);
                ctx.gl.enable_vertex_attrib_array(ATTRIB_TEXCOORD);
            }

            Self {
                vao,
                index_count: indices.len(),
            }
        }
    }

    pub fn new(ctx: &context::Context, mut bytes: &[u8]) -> Self {
        let lopts = tobj::LoadOptions {
            triangulate: true,
            single_index: true,
            ..Default::default()
        };
        let (meshes, _materials) = tobj::load_obj_buf(
            &mut bytes,
            &lopts,
            |_| Err(tobj::LoadError::GenericFailure)
        ).expect("failed to load mesh");
        let mesh = meshes.into_iter().next()
            .expect("failed to load mesh")
            .mesh;
        Self::build(
            ctx,
            &mesh.positions,
            &mesh.indices,
            &Some(mesh.normals),
            &Some(mesh.texcoords),
        )
    }

    pub fn render(&self, ctx: &context::Context) {
        unsafe {
            ctx.gl.bind_vertex_array(Some(self.vao));
            ctx.gl.draw_elements(glow::TRIANGLES, self.index_count as _, glow::UNSIGNED_INT, 0);
        }
    }
}