6 #include "client/client.h"
7 #include "client/cube.h"
8 #include "client/gl_debug.h"
9 #include "client/gui.h"
10 #include "client/mesh.h"
11 #include "client/shader.h"
12 #include "client/window.h"
14 static GUIElement root_element;
16 static GLuint background_prog;
17 static GLint background_loc_model;
18 static GLint background_loc_projection;
19 static GLint background_loc_color;
22 } __attribute__((packed)) BackgroundVertex;
23 static Mesh background_mesh = {
24 .layout = &(VertexLayout) {
25 .attributes = (VertexAttribute[]) {
26 {GL_FLOAT, 2, sizeof(v2f32)}, // position
29 .size = sizeof(BackgroundVertex),
33 .data = (BackgroundVertex[]) {
45 static GLuint image_prog;
46 static GLint image_loc_model;
47 static GLint image_loc_projection;
50 v2f32 textureCoordinates;
51 } __attribute__((packed)) ImageVertex;
52 static Mesh image_mesh = {
53 .layout = &(VertexLayout) {
54 .attributes = (VertexAttribute[]) {
55 {GL_FLOAT, 2, sizeof(v2f32)}, // position
56 {GL_FLOAT, 2, sizeof(v2f32)}, // textureCoordinates
59 .size = sizeof(ImageVertex),
63 .data = (ImageVertex[]) {
64 {{0.0, 0.0}, {0.0, 0.0}},
65 {{1.0, 0.0}, {1.0, 0.0}},
66 {{1.0, 1.0}, {1.0, 1.0}},
67 {{1.0, 1.0}, {1.0, 1.0}},
68 {{0.0, 1.0}, {0.0, 1.0}},
69 {{0.0, 0.0}, {0.0, 0.0}},
75 static GLuint font_prog;
76 static GLint font_loc_model;
77 static GLint font_loc_projection;
78 static GLint font_loc_color;
79 // font meshes are initialized in font.c
81 static mat4x4 projection;
85 static void delete_element(GUIElement *element);
86 static void render_element(GUIElement *element);
87 static void scale_element(GUIElement *element);
89 static int cmp_element(const GUIElement *ea, const GUIElement *eb)
91 return f32_cmp(&ea->def.z_index, &eb->def.z_index);
94 static void delete_elements(Array *elements)
96 for (size_t i = 0; i < elements->siz; i++)
97 delete_element(((GUIElement **) elements->ptr)[i]);
101 static void delete_element(GUIElement *element)
103 delete_elements(&element->children);
105 if (element->def.text)
106 free(element->def.text);
109 font_delete(element->text);
114 static void render_elements(Array *elements)
116 for (size_t i = 0; i < elements->siz; i++)
117 render_element(((GUIElement **) elements->ptr)[i]);
120 static void render_element(GUIElement *element)
122 if (element->visible) {
123 if (element->def.bg_color.w > 0.0f) {
124 glUseProgram(background_prog); GL_DEBUG
125 glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
126 glUniform4f(background_loc_color, element->def.bg_color.x, element->def.bg_color.y, element->def.bg_color.z, element->def.bg_color.w); GL_DEBUG
127 mesh_render(&background_mesh);
130 if (element->def.image) {
131 glUseProgram(image_prog); GL_DEBUG
132 glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
133 glBindTextureUnit(0, element->def.image->txo); GL_DEBUG
134 mesh_render(&image_mesh);
137 if (element->def.text && element->def.text_color.w > 0.0f) {
138 if (!element->text) {
139 element->text = font_create(element->def.text);
140 gui_transform(element);
143 glUseProgram(font_prog); GL_DEBUG
144 glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]); GL_DEBUG
145 glUniform4f(font_loc_color, element->def.text_color.x, element->def.text_color.y, element->def.text_color.z, element->def.text_color.w); GL_DEBUG
146 font_render(element->text);
149 render_elements(&element->children);
153 static void scale_elements(Array *elements, int mask, v3f32 *max)
155 for (size_t i = 0; i < elements->siz; i++) {
156 GUIElement *element = ((GUIElement **) elements->ptr)[i];
158 if ((1 << element->def.affect_parent_scale) & mask) {
159 scale_element(element);
162 if (element->scale.x > max->x)
163 max->x = element->scale.x;
165 if (element->scale.y > max->y)
166 max->y = element->scale.y;
172 static void scale_element(GUIElement *element)
174 element->scale = (v2f32) {
175 element->def.scale.x,
176 element->def.scale.y,
179 switch (element->def.scale_type) {
181 element->scale.x *= element->def.image->width;
182 element->scale.y *= element->def.image->height;
189 element->scale.x *= element->text->size.x;
190 element->scale.y *= element->text->size.y;
194 element->scale.x *= element->parent->scale.x;
195 element->scale.y *= element->parent->scale.y;
198 case SCALE_CHILDREN: {
199 v3f32 scale = {0.0f, 0.0f, 0.0f};
200 scale_elements(&element->children, 1 << true, &scale);
202 element->scale.x *= scale.x;
203 element->scale.y *= scale.y;
205 scale_elements(&element->children, 1 << false, NULL);
213 if (element->def.scale_type != SCALE_CHILDREN)
214 scale_elements(&element->children, (1 << true) | (1 << false), NULL);
217 static void transform_element(GUIElement *element)
219 element->pos = (v2f32) {
220 floor(element->parent->pos.x + element->def.offset.x + element->def.pos.x * element->parent->scale.x - element->def.align.x * element->scale.x),
221 floor(element->parent->pos.y + element->def.offset.y + element->def.pos.y * element->parent->scale.y - element->def.align.y * element->scale.y),
224 mat4x4_translate(element->transform, element->pos.x - element->def.margin.x, element->pos.y - element->def.margin.y, 0.0f);
225 mat4x4_translate(element->text_transform, element->pos.x, element->pos.y, 0.0f);
226 mat4x4_scale_aniso(element->transform, element->transform, element->scale.x + element->def.margin.x * 2.0f, element->scale.y + element->def.margin.y * 2.0f, 1.0f);
228 for (size_t i = 0; i < element->children.siz; i++)
229 transform_element(((GUIElement **) element->children.ptr)[i]);
236 // initialize background pipeline
238 if (!shader_program_create(RESSOURCE_PATH "shaders/gui/background", &background_prog, NULL)) {
239 fprintf(stderr, "[error] failed to create GUI background shader program\n");
243 background_loc_model = glGetUniformLocation(background_prog, "model"); GL_DEBUG
244 background_loc_projection = glGetUniformLocation(background_prog, "projection"); GL_DEBUG
245 background_loc_color = glGetUniformLocation(background_prog, "color"); GL_DEBUG
247 // initialize image pipeline
249 if (!shader_program_create(RESSOURCE_PATH "shaders/gui/image", &image_prog, NULL)) {
250 fprintf(stderr, "[error] failed to create GUI image shader program\n");
254 image_loc_model = glGetUniformLocation(image_prog, "model"); GL_DEBUG
255 image_loc_projection = glGetUniformLocation(image_prog, "projection"); GL_DEBUG
257 // initialize font pipeline
259 if (!shader_program_create(RESSOURCE_PATH "shaders/gui/font", &font_prog, NULL)) {
260 fprintf(stderr, "[error] failed to create GUI font shader program\n");
264 font_loc_model = glGetUniformLocation(font_prog, "model"); GL_DEBUG
265 font_loc_projection = glGetUniformLocation(font_prog, "projection"); GL_DEBUG
266 font_loc_color = glGetUniformLocation(font_prog, "color"); GL_DEBUG
268 // initialize GUI root element
270 root_element.def.pos = (v2f32) {0.0f, 0.0f};
271 root_element.def.z_index = 0.0f;
272 root_element.def.offset = (v2s32) {0, 0};
273 root_element.def.align = (v2f32) {0.0f, 0.0f};
274 root_element.def.scale = (v2f32) {0.0f, 0.0f};
275 root_element.def.scale_type = SCALE_NONE;
276 root_element.def.affect_parent_scale = false;
277 root_element.def.text = NULL;
278 root_element.def.image = NULL;
279 root_element.def.text_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f};
280 root_element.def.bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f};
281 root_element.visible = true;
282 root_element.pos = (v2f32) {0.0f, 0.0f};
283 root_element.scale = (v2f32) {0.0f, 0.0f};
284 root_element.text = NULL;
285 root_element.parent = &root_element;
286 array_ini(&root_element.children, sizeof(GUIElement *), 0);
288 gui_update_projection();
295 glDeleteProgram(background_prog); GL_DEBUG
296 mesh_destroy(&background_mesh);
298 glDeleteProgram(image_prog); GL_DEBUG
299 mesh_destroy(&image_mesh);
301 glDeleteProgram(font_prog); GL_DEBUG
303 delete_elements(&root_element.children);
306 void gui_update_projection()
308 mat4x4_ortho(projection, 0, window.width, window.height, 0, -1.0f, 1.0f);
309 glProgramUniformMatrix4fv(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
310 glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
311 glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
313 root_element.def.scale.x = window.width;
314 root_element.def.scale.y = window.height;
316 gui_transform(&root_element);
321 glDisable(GL_CULL_FACE); GL_DEBUG
322 glDisable(GL_DEPTH_TEST); GL_DEBUG
324 render_elements(&root_element.children);
326 glEnable(GL_DEPTH_TEST); GL_DEBUG
327 glEnable(GL_CULL_FACE); GL_DEBUG
330 GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def)
333 parent = &root_element;
335 GUIElement *element = malloc(sizeof *element);
337 element->visible = true;
338 element->parent = parent;
339 element->text = NULL;
341 if (element->def.text)
342 element->def.text = strdup(element->def.text);
344 array_ins(&parent->children, &element, &cmp_element);
345 array_ini(&element->children, sizeof(GUIElement), 0);
347 if (element->def.affect_parent_scale)
348 gui_transform(parent);
350 gui_transform(element);
355 void gui_text(GUIElement *element, const char *text)
357 if (element->def.text)
358 free(element->def.text);
361 font_delete(element->text);
363 element->def.text = strdup(text);
364 element->text = NULL;
367 void gui_transform(GUIElement *element)
369 scale_element(element);
370 transform_element(element);