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