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 = {
19 .align = {0.0f, 0.0f},
20 .scale = {0.0f, 0.0f},
21 .scale_type = SCALE_NONE,
22 .affect_parent_scale = false,
25 .text_color = {0.0f, 0.0f, 0.0f, 0.0f},
26 .bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
29 .pos = (v2f32) {0.0f, 0.0f},
30 .scale = (v2f32) {0.0f, 0.0f},
32 .parent = &root_element,
35 static GLuint background_prog;
36 static GLint background_loc_model;
37 static GLint background_loc_projection;
38 static GLint background_loc_color;
41 } __attribute__((packed)) BackgroundVertex;
42 static Mesh background_mesh = {
43 .layout = &(VertexLayout) {
44 .attributes = (VertexAttribute[]) {
45 {GL_FLOAT, 2, sizeof(v2f32)}, // position
48 .size = sizeof(BackgroundVertex),
52 .data = (BackgroundVertex[]) {
64 static GLuint image_prog;
65 static GLint image_loc_model;
66 static GLint image_loc_projection;
69 v2f32 textureCoordinates;
70 } __attribute__((packed)) ImageVertex;
71 static Mesh image_mesh = {
72 .layout = &(VertexLayout) {
73 .attributes = (VertexAttribute[]) {
74 {GL_FLOAT, 2, sizeof(v2f32)}, // position
75 {GL_FLOAT, 2, sizeof(v2f32)}, // textureCoordinates
78 .size = sizeof(ImageVertex),
82 .data = (ImageVertex[]) {
83 {{0.0, 0.0}, {0.0, 0.0}},
84 {{1.0, 0.0}, {1.0, 0.0}},
85 {{1.0, 1.0}, {1.0, 1.0}},
86 {{1.0, 1.0}, {1.0, 1.0}},
87 {{0.0, 1.0}, {0.0, 1.0}},
88 {{0.0, 0.0}, {0.0, 0.0}},
94 static GLuint font_prog;
95 static GLint font_loc_model;
96 static GLint font_loc_projection;
97 static GLint font_loc_color;
98 // font meshes are initialized in font.c
100 static mat4x4 projection;
104 static void delete_element(GUIElement *element);
105 static void render_element(GUIElement *element);
106 static void scale_element(GUIElement *element);
108 static int cmp_element(const GUIElement *ea, const GUIElement *eb)
110 return -f32_cmp(&ea->def.z_index, &eb->def.z_index);
113 static void delete_elements(Array *elements)
115 for (size_t i = 0; i < elements->siz; i++)
116 delete_element(((GUIElement **) elements->ptr)[i]);
120 static void delete_element(GUIElement *element)
122 delete_elements(&element->children);
124 if (element->def.text)
125 free(element->def.text);
128 font_delete(element->text);
133 static void render_elements(Array *elements)
135 for (size_t i = 0; i < elements->siz; i++)
136 render_element(((GUIElement **) elements->ptr)[i]);
139 static void render_element(GUIElement *element)
141 if (element->visible) {
142 if (element->def.bg_color.w > 0.0f) {
143 glUseProgram(background_prog); GL_DEBUG
144 glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
145 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
146 mesh_render(&background_mesh);
149 if (element->def.image) {
150 glUseProgram(image_prog); GL_DEBUG
151 glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
152 glBindTextureUnit(0, element->def.image->txo); GL_DEBUG
153 mesh_render(&image_mesh);
156 if (element->def.text && element->def.text_color.w > 0.0f) {
157 if (!element->text) {
158 element->text = font_create(element->def.text);
159 gui_transform(element);
162 glUseProgram(font_prog); GL_DEBUG
163 glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]); GL_DEBUG
164 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
165 font_render(element->text);
168 render_elements(&element->children);
172 static void scale_elements(Array *elements, int mask, v3f32 *max)
174 for (size_t i = 0; i < elements->siz; i++) {
175 GUIElement *element = ((GUIElement **) elements->ptr)[i];
177 if ((1 << element->def.affect_parent_scale) & mask) {
178 scale_element(element);
181 if (element->scale.x > max->x)
182 max->x = element->scale.x;
184 if (element->scale.y > max->y)
185 max->y = element->scale.y;
191 static void scale_element(GUIElement *element)
193 element->scale = (v2f32) {
194 element->def.scale.x,
195 element->def.scale.y,
198 switch (element->def.scale_type) {
200 element->scale.x *= element->def.image->width;
201 element->scale.y *= element->def.image->height;
208 element->scale.x *= element->text->size.x;
209 element->scale.y *= element->text->size.y;
213 element->scale.x *= element->parent->scale.x;
214 element->scale.y *= element->parent->scale.y;
217 case SCALE_CHILDREN: {
218 v3f32 scale = {0.0f, 0.0f, 0.0f};
219 scale_elements(&element->children, 1 << true, &scale);
221 element->scale.x *= scale.x;
222 element->scale.y *= scale.y;
224 scale_elements(&element->children, 1 << false, NULL);
232 if (element->def.scale_type != SCALE_CHILDREN)
233 scale_elements(&element->children, (1 << true) | (1 << false), NULL);
236 static void transform_element(GUIElement *element)
238 element->pos = (v2f32) {
239 floor(element->parent->pos.x + element->def.offset.x + element->def.pos.x * element->parent->scale.x - element->def.align.x * element->scale.x),
240 floor(element->parent->pos.y + element->def.offset.y + element->def.pos.y * element->parent->scale.y - element->def.align.y * element->scale.y),
243 mat4x4_translate(element->transform, element->pos.x - element->def.margin.x, element->pos.y - element->def.margin.y, 0.0f);
244 mat4x4_translate(element->text_transform, element->pos.x, element->pos.y, 0.0f);
245 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);
247 for (size_t i = 0; i < element->children.siz; i++)
248 transform_element(((GUIElement **) element->children.ptr)[i]);
255 // initialize background pipeline
256 background_prog = shader_program_create(RESSOURCE_PATH "shaders/gui/background", NULL);
257 background_loc_model = glGetUniformLocation(background_prog, "model"); GL_DEBUG
258 background_loc_projection = glGetUniformLocation(background_prog, "projection"); GL_DEBUG
259 background_loc_color = glGetUniformLocation(background_prog, "color"); GL_DEBUG
261 // initialize image pipeline
262 image_prog = shader_program_create(RESSOURCE_PATH "shaders/gui/image", NULL);
263 image_loc_model = glGetUniformLocation(image_prog, "model"); GL_DEBUG
264 image_loc_projection = glGetUniformLocation(image_prog, "projection"); GL_DEBUG
266 // initialize font pipeline
267 font_prog = shader_program_create(RESSOURCE_PATH "shaders/gui/font", NULL);
268 font_loc_model = glGetUniformLocation(font_prog, "model"); GL_DEBUG
269 font_loc_projection = glGetUniformLocation(font_prog, "projection"); GL_DEBUG
270 font_loc_color = glGetUniformLocation(font_prog, "color"); GL_DEBUG
272 // initialize GUI root element
273 array_ini(&root_element.children, sizeof(GUIElement *), 0);
274 gui_update_projection();
279 glDeleteProgram(background_prog); GL_DEBUG
280 mesh_destroy(&background_mesh);
282 glDeleteProgram(image_prog); GL_DEBUG
283 mesh_destroy(&image_mesh);
285 glDeleteProgram(font_prog); GL_DEBUG
287 delete_elements(&root_element.children);
290 void gui_update_projection()
292 mat4x4_ortho(projection, 0, window.width, window.height, 0, -1.0f, 1.0f);
293 glProgramUniformMatrix4fv(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
294 glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
295 glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
297 root_element.def.scale.x = window.width;
298 root_element.def.scale.y = window.height;
300 gui_transform(&root_element);
305 glDisable(GL_CULL_FACE); GL_DEBUG
306 glDisable(GL_DEPTH_TEST); GL_DEBUG
308 render_elements(&root_element.children);
310 glEnable(GL_DEPTH_TEST); GL_DEBUG
311 glEnable(GL_CULL_FACE); GL_DEBUG
314 GUIElement *gui_add(GUIElement *parent, GUIElementDef def)
317 parent = &root_element;
319 GUIElement *element = malloc(sizeof *element);
321 element->visible = true;
322 element->parent = parent;
323 element->text = NULL;
325 if (element->def.text)
326 element->def.text = strdup(element->def.text);
328 array_ins(&parent->children, &element, &cmp_element);
329 array_ini(&element->children, sizeof(GUIElement), 0);
331 if (element->def.affect_parent_scale)
332 gui_transform(parent);
334 gui_transform(element);
339 void gui_text(GUIElement *element, const char *text)
341 if (element->def.text)
342 free(element->def.text);
345 font_delete(element->text);
347 element->def.text = strdup(text);
348 element->text = NULL;
351 void gui_transform(GUIElement *element)
353 scale_element(element);
354 transform_element(element);