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