]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/mesh.c
341789038291d933be249ce83b2ef8d1d2cbbc35
[dragonblocks_alpha.git] / src / mesh.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include "mesh.h"
5 #include "scene.h"
6
7 VertexBuffer vertexbuffer_create()
8 {
9         return (VertexBuffer) {
10                 .faces = array_create(sizeof(Face)),
11         };
12 }
13
14 void vertexbuffer_set_texture(VertexBuffer *buffer, GLuint texture)
15 {
16         if (buffer->current && buffer->current->texture == texture)
17                 return;
18         Face face = {
19                 .texture = texture,
20                 .vertices = array_create(sizeof(Vertex)),
21         };
22         array_append(&buffer->faces, &face);
23         buffer->current = &((Face *) buffer->faces.ptr)[buffer->faces.siz - 1];
24 }
25
26 void vertexbuffer_add_vertex(VertexBuffer *buffer, Vertex *vertex)
27 {
28         array_append(&buffer->current->vertices, vertex);
29 }
30
31 static int qsort_compare_faces(const void *f1, const void *f2)
32 {
33         return ((Face *) f1)->texture - ((Face *) f2)->texture;
34 }
35
36 static void add_mesh(Array *meshes, Array *vertices, GLuint texture)
37 {
38         if (vertices->siz > 0) {
39                 Mesh *mesh = malloc(sizeof(Mesh));
40                 mesh->VAO = mesh->VBO = 0;
41                 // the reason the vertices are not copied and then free'd like anything else is that the vertices will be deleted after the first render anyway
42                 mesh->vertices = vertices->ptr;
43                 mesh->vertices_count = vertices->siz;
44                 mesh->texture = texture;
45
46                 array_append(meshes, &mesh);
47         }
48
49         *vertices = array_create(sizeof(Vertex));
50 }
51
52 MeshObject *meshobject_create(VertexBuffer buffer, struct Scene *scene, v3f pos)
53 {
54         if (buffer.faces.siz == 0)
55                 return NULL;
56
57         MeshObject *obj = malloc(sizeof(MeshObject));
58         obj->remove = false;
59
60         obj->pos = pos;
61         obj->rot = (v3f) {0.0f, 0.0f, 0.0f};
62         obj->scale = (v3f) {1.0f, 1.0f, 1.0f};
63         obj->angle = 0.0f;
64         obj->visible = true;
65         meshobject_transform(obj);
66
67         qsort(buffer.faces.ptr, buffer.faces.siz, sizeof(Face), &qsort_compare_faces);
68
69         Array meshes = array_create(sizeof(Mesh *));
70         Array vertices = array_create(sizeof(Vertex));
71         GLuint texture = 0;
72
73         for (size_t f = 0; f < buffer.faces.siz; f++) {
74                 Face *face = &((Face *) buffer.faces.ptr)[f];
75
76                 if (face->texture != texture) {
77                         add_mesh(&meshes, &vertices, texture);
78                         texture = face->texture;
79                 }
80
81                 for (size_t v = 0; v < face->vertices.siz; v++)
82                         array_append(&vertices, &((Vertex *) face->vertices.ptr)[v]);
83                 free(face->vertices.ptr);
84         }
85         add_mesh(&meshes, &vertices, texture);
86         free(buffer.faces.ptr);
87
88         array_copy(&meshes, (void *) &obj->meshes, &obj->meshes_count);
89         free(meshes.ptr);
90
91         scene_add_object(scene, obj);
92
93         return obj;
94 }
95
96 #pragma GCC diagnostic push
97 #pragma GCC diagnostic ignored "-Wpedantic"
98
99 void meshobject_transform(MeshObject *obj)
100 {
101         mat4x4_translate(obj->transform, obj->pos.x, obj->pos.y, obj->pos.z);
102         mat4x4_rotate(obj->transform, obj->transform, obj->rot.x, obj->rot.y, obj->rot.z, obj->angle);
103         mat4x4_scale_aniso(obj->transform, obj->transform, obj->scale.x, obj->scale.y, obj->scale.z);
104 }
105
106 #pragma GCC diagnostic pop
107
108 void meshobject_delete(MeshObject *obj)
109 {
110         for (size_t i = 0; i < obj->meshes_count; i++) {
111                 Mesh *mesh = obj->meshes[i];
112
113                 if (mesh->vertices)
114                         free(mesh->vertices);
115                 if (mesh->VAO)
116                         glDeleteVertexArrays(1, &mesh->VAO);
117                 if (mesh->VBO)
118                         glDeleteBuffers(1, &mesh->VAO);
119                 free(mesh);
120         }
121         free(obj);
122 }
123
124 static void mesh_configure(Mesh *mesh)
125 {
126         glGenVertexArrays(1, &mesh->VAO);
127         glGenBuffers(1, &mesh->VBO);
128
129         glBindVertexArray(mesh->VAO);
130         glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
131
132         glBufferData(GL_ARRAY_BUFFER, mesh->vertices_count * sizeof(Vertex), mesh->vertices, GL_STATIC_DRAW);
133
134
135         glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, x));
136         glEnableVertexAttribArray(0);
137
138         glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(Vertex), (GLvoid *) offsetof(Vertex, s));
139         glEnableVertexAttribArray(1);
140
141
142         glBindBuffer(GL_ARRAY_BUFFER, 0);
143         glBindVertexArray(0);
144
145         free(mesh->vertices);
146         mesh->vertices = NULL;
147 }
148
149 void meshobject_render(MeshObject *obj, ShaderProgram *prog)
150 {
151         if (! obj->visible)
152                 return;
153
154         glUniformMatrix4fv(prog->loc_model, 1, GL_FALSE, obj->transform[0]);
155
156         glActiveTexture(GL_TEXTURE0);
157
158         for (size_t i = 0; i < obj->meshes_count; i++) {
159                 Mesh *mesh = obj->meshes[i];
160
161                 if (mesh->vertices)
162                         mesh_configure(mesh);
163
164                 glBindTexture(GL_TEXTURE_2D, mesh->texture);
165                 glBindVertexArray(mesh->VAO);
166
167                 glDrawArrays(GL_TRIANGLES, 0, mesh->vertices_count);
168         }
169
170         glBindTexture(GL_TEXTURE_2D, 0);
171         glBindVertexArray(0);
172 }