]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/object.c
6dd487166ed9350a8ac1771d36957ebe8fac191f
[dragonblocks_alpha.git] / src / client / object.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "client/object.h"
4 #include "client/scene.h"
5 #define OBJECT_VERTEX_ATTRIBUTES 5
6
7 static VertexAttribute vertex_attributes[OBJECT_VERTEX_ATTRIBUTES] = {
8         // position
9         {
10                 .type = GL_FLOAT,
11                 .length = 3,
12                 .size = sizeof(Vertex3DPosition),
13         },
14         // normal
15         {
16                 .type = GL_FLOAT,
17                 .length = 3,
18                 .size = sizeof(Vertex3DNormal),
19         },
20         // textureIndex
21         {
22                 .type = GL_FLOAT,
23                 .length = 1,
24                 .size = sizeof(Vertex3DTextureIndex),
25         },
26         // textureCoordinates
27         {
28                 .type = GL_FLOAT,
29                 .length = 2,
30                 .size = sizeof(Vertex3DTextureCoordinates),
31
32         },
33         // color
34         {
35                 .type = GL_FLOAT,
36                 .length = 3,
37                 .size = sizeof(Vertex3DColor),
38         },
39 };
40
41 static VertexLayout vertex_layout = {
42         .attributes = vertex_attributes,
43         .count = OBJECT_VERTEX_ATTRIBUTES,
44         .size = sizeof(Vertex3D),
45 };
46
47 Object *object_create()
48 {
49         Object *obj = malloc(sizeof(Object));
50         obj->pos = (v3f32) {0.0f, 0.0f, 0.0f};
51         obj->rot = (v3f32) {0.0f, 0.0f, 0.0f};
52         obj->scale = (v3f32) {1.0f, 1.0f, 1.0f};
53         obj->angle = 0.0f;
54         obj->remove = false;
55         obj->meshes = NULL;
56         obj->meshes_count = 0;
57         obj->visible = true;
58         obj->wireframe = false;
59         obj->box = (aabb3f32) {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
60         obj->frustum_culling = false;
61         obj->current_face = NULL;
62         obj->faces = array_create(sizeof(ObjectFace));
63         obj->on_render = NULL;
64         obj->extra = NULL;
65
66         return obj;
67 }
68
69 void object_delete(Object *obj)
70 {
71         for (size_t i = 0; i < obj->meshes_count; i++)
72                 mesh_delete(obj->meshes[i]);
73
74         free(obj);
75 }
76
77 void object_set_texture(Object *obj, Texture *texture)
78 {
79         if (obj->current_face && obj->current_face->texture == texture->id)
80                 return;
81
82         ObjectFace face = {
83                 .texture = texture->id,
84                 .vertices = array_create(sizeof(Vertex3D)),
85         };
86
87         array_append(&obj->faces, &face);
88         obj->current_face = &((ObjectFace *) obj->faces.ptr)[obj->faces.siz - 1];
89 }
90
91 void object_add_vertex(Object *obj, Vertex3D *vertex)
92 {
93         array_append(&obj->current_face->vertices, vertex);
94 }
95
96 static int qsort_compare_faces(const void *f1, const void *f2)
97 {
98         return ((ObjectFace *) f1)->texture - ((ObjectFace *) f2)->texture;
99 }
100
101 static void add_mesh(Array *meshes, Array *vertices, Array *textures)
102 {
103         if (vertices->siz > 0) {
104                 Mesh *mesh = mesh_create();
105                 mesh->vertices = vertices->ptr;
106                 mesh->vertices_count = vertices->siz;
107                 mesh->free_vertices = true;
108                 mesh->free_textures = true;
109                 mesh->layout = &vertex_layout;
110                 size_t textures_count;
111                 array_copy(textures, (void *) &mesh->textures, &textures_count);
112                 mesh->textures_count = textures_count;
113
114                 free(textures->ptr);
115
116                 array_append(meshes, &mesh);
117         }
118
119         *vertices = array_create(sizeof(Vertex3D));
120         *textures = array_create(sizeof(GLuint));
121 }
122
123 bool object_add_to_scene(Object *obj)
124 {
125         if (obj->faces.siz == 0)
126                 return false;
127
128         object_transform(obj);
129
130         qsort(obj->faces.ptr, obj->faces.siz, sizeof(ObjectFace), &qsort_compare_faces);
131
132         GLuint max_texture_units = scene_get_max_texture_units();
133
134         Array meshes = array_create(sizeof(Mesh *));
135
136         Array vertices = array_create(sizeof(Vertex3D));
137         Array textures = array_create(sizeof(GLuint));
138
139         GLuint texture_id = 0;
140         GLuint texture_index = max_texture_units;
141
142         for (size_t f = 0; f < obj->faces.siz; f++) {
143                 ObjectFace *face = &((ObjectFace *) obj->faces.ptr)[f];
144
145                 if (face->texture != texture_id) {
146                         if (++texture_index >= max_texture_units) {
147                                 add_mesh(&meshes, &vertices, &textures);
148                                 texture_index = 0;
149                         }
150
151                         texture_id = face->texture;
152                         array_append(&textures, &texture_id);
153                 }
154
155                 for (size_t v = 0; v < face->vertices.siz; v++) {
156                         Vertex3D *vertex = &((Vertex3D *) face->vertices.ptr)[v];
157                         vertex->textureIndex = texture_index;
158                         array_append(&vertices, vertex);
159                 }
160
161                 free(face->vertices.ptr);
162         }
163         add_mesh(&meshes, &vertices, &textures);
164         free(obj->faces.ptr);
165
166         array_copy(&meshes, (void *) &obj->meshes, &obj->meshes_count);
167         free(meshes.ptr);
168
169         scene_add_object(obj);
170
171         return true;
172 }
173
174 void object_transform(Object *obj)
175 {
176         mat4x4_translate(obj->transform, obj->pos.x, obj->pos.y, obj->pos.z);
177 #pragma GCC diagnostic push
178 #pragma GCC diagnostic ignored "-Wpedantic"
179         mat4x4_rotate(obj->transform, obj->transform, obj->rot.x, obj->rot.y, obj->rot.z, obj->angle);
180         mat4x4_scale_aniso(obj->transform, obj->transform, obj->scale.x, obj->scale.y, obj->scale.z);
181 #pragma GCC diagnostic pop
182 }
183 #pragma GCC diagnostic push
184 #pragma GCC diagnostic ignored "-Wpedantic"
185 static bool inside_frustum(aabb3f32 box, mat4x4 MVP)
186 {
187         for (int x = 0; x <= 1; x++) {
188                 for (int y = 0; y <= 1; y++) {
189                         for (int z = 0; z <= 1; z++) {
190                                 vec4 point = {x ? box.min.x : box.max.x, y ? box.min.y : box.max.y, z ? box.min.z : box.max.z, 1.0};
191                                 vec4 point_NDC;
192                                 mat4x4_mul_vec4(point_NDC, MVP, point);
193
194                                 for (int j = 0; j < 3; j++) {
195                                         float f = point_NDC[j];
196
197                                         if (f > -1.0f && f > 1.0f)
198                                                 return true;
199                                 }
200                         }
201                 }
202         }
203
204         return false;
205 }
206 #pragma GCC diagnostic pop
207
208
209 void object_render(Object *obj, f64 dtime)
210 {
211         if (obj->on_render)
212                 obj->on_render(obj, dtime);
213
214         if (! obj->visible)
215                 return;
216
217         if (obj->frustum_culling) {
218                 mat4x4 MVP;
219
220 #pragma GCC diagnostic push
221 #pragma GCC diagnostic ignored "-Wpedantic"
222                 mat4x4_mul(MVP, scene.VP, obj->transform);
223 #pragma GCC diagnostic pop
224
225                  if (! inside_frustum(obj->box, MVP))
226                         return;
227         }
228
229         glUniformMatrix4fv(scene.loc_model, 1, GL_FALSE, obj->transform[0]);
230
231         if (obj->wireframe)
232                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
233
234         for (size_t i = 0; i < obj->meshes_count; i++)
235                 mesh_render(obj->meshes[i]);
236
237         if (obj->wireframe)
238                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
239 }