]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/mesh.c
75b0b10fc26f2269de91c9c686fec51c3eec419c
[dragonblocks_alpha.git] / src / client / mesh.c
1 #include <dragonstd/tree.h>
2 #include <getline.h>
3 #include <stddef.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include "client/cube.h"
7 #include "client/gl_debug.h"
8 #include "client/mesh.h"
9
10 typedef struct {
11         v3s32 pos;
12         v3f32 color;
13 } LoadedVoxel;
14
15 typedef struct {
16         Tree voxels;
17         Array vertices;
18 } LoadedRenderArgs;
19
20 static v3s32 face_dir[6] = {
21         {+0, +0, -1},
22         {+0, +0, +1},
23         {-1, +0, +0},
24         {+1, +0, +0},
25         {+0, -1, +0},
26         {+0, +1, +0},
27 };
28
29 typedef struct {
30         v3f32 pos;
31         v3f32 normal;
32         v3f32 color;
33 } __attribute__((packed)) LoadedVertex;
34 static VertexLayout loaded_layout = {
35         .attributes = (VertexAttribute[]) {
36                 {GL_FLOAT, 3, sizeof(v3f32)}, // position
37                 {GL_FLOAT, 3, sizeof(v3f32)}, // normal
38                 {GL_FLOAT, 3, sizeof(v3f32)}, // color
39         },
40         .count = 3,
41         .size = sizeof(LoadedVertex),
42 };
43
44 static int cmp_loaded_voxel(const LoadedVoxel *voxel, const v3s32 *pos)
45 {
46         return v3s32_cmp(&voxel->pos, pos);
47 }
48
49 static void render_loaded_voxel(LoadedVoxel *voxel, LoadedRenderArgs *args)
50 {
51         v3f32 pos = v3s32_to_f32(voxel->pos);
52         for (int f = 0; f < 6; f++) {
53                 v3s32 neigh_pos = v3s32_add(voxel->pos, face_dir[f]);
54                 if (tree_get(&args->voxels, &neigh_pos, &cmp_loaded_voxel, NULL))
55                         continue;
56
57                 for (int v = 0; v < 6; v++)
58                         array_apd(&args->vertices, &(LoadedVertex) {
59                                 v3f32_add(cube_vertices[f][v].position, pos),
60                                 cube_vertices[f][v].normal,
61                                 voxel->color,
62                         });
63         }
64 }
65
66 void mesh_load(Mesh *mesh, const char *path)
67 {
68         mesh->layout = &loaded_layout;
69         mesh->vao = mesh->vbo = 0;
70         mesh->data = NULL;
71         mesh->count = 0;
72         mesh->free_data = true;
73
74         LoadedRenderArgs args;
75         tree_ini(&args.voxels);
76         array_ini(&args.vertices, sizeof(LoadedVertex), 500);
77
78         FILE *file = fopen(path, "r");
79         if (!file) {
80                 fprintf(stderr, "[warning] failed to open mesh %s\n", path);
81                 return;
82         }
83
84         char *line = NULL;
85         size_t siz = 0;
86         ssize_t length;
87         int count = 0;
88
89         while ((length = getline(&line, &siz, file)) > 0) {
90                 count++;
91
92                 if (*line == '#')
93                         continue;
94
95                 LoadedVoxel *voxel = malloc(sizeof *voxel);
96
97                 v3s32 color;
98                 if (sscanf(line, "%d %d %d %2x%2x%2x",
99                                 &voxel->pos.x, &voxel->pos.z, &voxel->pos.y,
100                                 &color.x, &color.y, &color.z) != 6) {
101                         fprintf(stderr, "[warning] syntax error in mesh %s in line %d: %s\n",
102                                 path, count, line);
103                         free(voxel);
104                         continue;
105                 }
106
107                 voxel->color = (v3f32) {
108                         (f32) color.x / 0xFF,
109                         (f32) color.y / 0xFF,
110                         (f32) color.z / 0xFF,
111                 };
112
113                 if (!tree_add(&args.voxels, &voxel->pos, voxel, &cmp_loaded_voxel, NULL)) {
114                         fprintf(stderr, "[warning] more than one voxel at position (%d, %d, %d) in mesh %s in line %d\n",
115                                 voxel->pos.x, voxel->pos.y, voxel->pos.z, path, count);
116                         free(voxel);
117                 }
118         }
119
120         if (line)
121                 free(line);
122
123         fclose(file);
124
125         tree_trv(&args.voxels, &render_loaded_voxel, &args, NULL, 0);
126         tree_clr(&args.voxels, &free, NULL, NULL, 0);
127
128         mesh->data = args.vertices.ptr;
129         mesh->count = args.vertices.siz;
130 }
131
132 // upload data to GPU (only done once)
133 void mesh_upload(Mesh *mesh)
134 {
135         glGenVertexArrays(1, &mesh->vao); GL_DEBUG
136         glGenBuffers(1, &mesh->vbo); GL_DEBUG
137
138         glBindVertexArray(mesh->vao); GL_DEBUG
139         glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); GL_DEBUG
140
141         glBufferData(GL_ARRAY_BUFFER, mesh->count * mesh->layout->size,
142                 mesh->data, GL_STATIC_DRAW); GL_DEBUG
143
144         size_t offset = 0;
145         for (GLuint i = 0; i < mesh->layout->count; i++) {
146                 VertexAttribute *attrib = &mesh->layout->attributes[i];
147
148                 glVertexAttribPointer(i, attrib->length, attrib->type, GL_FALSE,
149                         mesh->layout->size, (GLvoid *) offset); GL_DEBUG
150                 glEnableVertexAttribArray(i); GL_DEBUG
151
152                 offset += attrib->size;
153         }
154
155         glBindBuffer(GL_ARRAY_BUFFER, 0); GL_DEBUG
156         glBindVertexArray(0); GL_DEBUG
157
158         if (mesh->free_data)
159                 free(mesh->data);
160
161         mesh->data = NULL;
162 }
163
164 void mesh_render(Mesh *mesh)
165 {
166         if (mesh->data)
167                 mesh_upload(mesh);
168
169         // render
170         glBindVertexArray(mesh->vao); GL_DEBUG
171         glDrawArrays(GL_TRIANGLES, 0, mesh->count); GL_DEBUG
172 }
173
174 void mesh_destroy(Mesh *mesh)
175 {
176         if (mesh->data && mesh->free_data)
177                 free(mesh->data);
178
179         if (mesh->vao) {
180                 glDeleteVertexArrays(1, &mesh->vao); GL_DEBUG
181         }
182
183         if (mesh->vbo) {
184                 glDeleteBuffers(1, &mesh->vbo); GL_DEBUG
185         }
186
187         mesh->vao = mesh->vbo = 0;
188 }