diff --git a/game/res/shaders/uielement.frag b/game/res/shaders/uielement.frag deleted file mode 100644 index d63a2d3..0000000 --- a/game/res/shaders/uielement.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 100 - -precision mediump float; - -uniform vec4 color; -uniform sampler2D texture; - -varying vec2 f_uv; - -void main () -{ - gl_FragColor = color; -} diff --git a/game/res/shaders/uitext.frag b/game/res/shaders/uitext.frag index c2262a7..f867082 100644 --- a/game/res/shaders/uitext.frag +++ b/game/res/shaders/uitext.frag @@ -2,7 +2,7 @@ precision mediump float; -uniform vec4 color; +uniform vec4 text_color; uniform sampler2D texture; varying vec2 f_uv; @@ -10,5 +10,5 @@ varying vec2 f_uv; void main () { - gl_FragColor = texture2D (texture, f_uv) * vec4 (color.xyz, 1.0); + gl_FragColor = texture2D (texture, f_uv) * text_color; } diff --git a/game/res/shaders/uiwidget.frag b/game/res/shaders/uiwidget.frag new file mode 100644 index 0000000..9e0f9a5 --- /dev/null +++ b/game/res/shaders/uiwidget.frag @@ -0,0 +1,23 @@ +#version 100 + +precision mediump float; + +uniform vec4 background_color; +uniform sampler2D texture; +uniform bool has_texture; + +varying vec2 f_uv; + +void main () +{ + vec4 tex_color = texture2D (texture, f_uv); + + if (has_texture) + { + gl_FragColor = tex_color; + } + else + { + gl_FragColor = background_color; + } +} diff --git a/game/res/shaders/uielement.vert b/game/res/shaders/uiwidget.vert similarity index 100% rename from game/res/shaders/uielement.vert rename to game/res/shaders/uiwidget.vert diff --git a/game/res/textures/font.xcf b/game/res/textures/font.xcf index cbe42ab..4d9f9e7 100644 Binary files a/game/res/textures/font.xcf and b/game/res/textures/font.xcf differ diff --git a/game/src/gl/program.c b/game/src/gl/program.c index 043d522..0105855 100644 --- a/game/src/gl/program.c +++ b/game/src/gl/program.c @@ -96,6 +96,12 @@ program_set_vec3_ind (int program, const char *name, float x, float y, float z) glUniform3f (glGetUniformLocation (program, name), x, y, z); } +void +program_set_int (int program, const char *name, int value) +{ + glUniform1i (glGetUniformLocation (program, name), value); +} + void program_set_float (int program, const char *name, float value) { diff --git a/game/src/gl/program.h b/game/src/gl/program.h index 61f2c01..13432b9 100644 --- a/game/src/gl/program.h +++ b/game/src/gl/program.h @@ -8,6 +8,7 @@ unsigned int program_use (int program); void shader_fail (int shader); void program_fail (int program); unsigned int program_create (const char *v_src, const char *f_src); +void program_set_int (int program, const char *name, int value); void program_set_float (int program, const char *name, float value); void program_set_int_array (int program, const char *name, size_t count, int *value); void program_set_vec3 (int program, const char *name, vec3 value); diff --git a/game/src/resources.c b/game/src/resources.c index 0c46f76..8708215 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -149,7 +149,7 @@ resources_init () RAP ("default", RLP ("res/shaders/default.vert", "res/shaders/default.frag")); RAP ("chunk", RLP ("res/shaders/chunk.vert", "res/shaders/chunk.frag")); RAP ("clouds", RLP ("res/shaders/clouds.vert", "res/shaders/clouds.frag")); - RAP ("uielement", RLP ("res/shaders/uielement.vert", "res/shaders/uielement.frag")); + RAP ("uiwidget", RLP ("res/shaders/uiwidget.vert", "res/shaders/uiwidget.frag")); RAP ("uitext", RLP ("res/shaders/uitext.vert", "res/shaders/uitext.frag")); RAT ("terrain0", RLT ("res/textures/dirt.png")); diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index e614b23..ee16d0c 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -6,27 +6,28 @@ extern int n_frame_ents, n_frame_chunks; extern vec3 camera_position; static Widget *ui_root; -static Widget *hovered_element; +static Widget *hovered_widget; void uiman_init () { - ui_element_mesh_init (); + ui_widget_mesh_init (); ui_root = Widget_root_new (); Widget *container = Widget_container_new (false); Widget_set_position (container, -0.5, 0.75); Widget_set_scale (container, 0.4, 0.15); Widget_set_background_color (container, 0.0, 0.0, 0.0, 0.8); + Widget_set_texture (container, RESTEX ("terrain4")); - Widget *frame_time = Widget_label_new ("Frame time: "); - Widget_set_on_tick (frame_time, uicb_label_show_float, &delta_time); - - Widget *game_name = Widget_label_new (NULL); + Widget *game_name = Widget_label_new (NULL, TEXT_ALIGN_CENTER); Widget_label_printf (game_name, "%s %s", GAME_NAME, GAME_VERSION); - Widget *entities_rendered = Widget_label_new ("Entities rendered: "); - Widget *chunks_rendered = Widget_label_new ("Chunks rendered: "); + Widget *frame_time = Widget_label_new (NULL, TEXT_ALIGN_LEFT); + Widget_set_on_tick (frame_time, uicb_label_show_float, &delta_time); + + Widget *entities_rendered = Widget_label_new (NULL, TEXT_ALIGN_LEFT); + Widget *chunks_rendered = Widget_label_new (NULL, TEXT_ALIGN_LEFT); Widget_set_on_tick (entities_rendered, uicb_label_show_int, &n_frame_ents); Widget_set_on_tick (chunks_rendered, uicb_label_show_int, &n_frame_chunks); @@ -34,11 +35,14 @@ uiman_init () Widget_add_child (container2, entities_rendered); Widget_add_child (container2, chunks_rendered); - Widget *pos_x = Widget_label_new ("X: "); - Widget *pos_y = Widget_label_new ("Y: "); - Widget *pos_z = Widget_label_new ("Z: "); + Widget *pos_x = Widget_label_new (NULL, TEXT_ALIGN_RIGHT); + Widget *pos_y = Widget_label_new (NULL, TEXT_ALIGN_RIGHT); + Widget *pos_z = Widget_label_new (NULL, TEXT_ALIGN_RIGHT); + Widget_label_set_text_color (pos_x, 1.0, 0.0, 0.0, 1.0); Widget_set_on_tick (pos_x, uicb_label_show_float, &camera_position[0]); + Widget_label_set_text_color (pos_y, 0.0, 1.0, 0.0, 1.0); Widget_set_on_tick (pos_y, uicb_label_show_float, &camera_position[1]); + Widget_label_set_text_color (pos_z, 0.0, 1.0, 1.0, 1.0); Widget_set_on_tick (pos_z, uicb_label_show_float, &camera_position[2]); Widget *container3 = Widget_container_new (true); @@ -46,12 +50,12 @@ uiman_init () Widget_add_child (container3, pos_y); Widget_add_child (container3, pos_z); - Widget *wireframe_button = Widget_label_new ("Toggle wireframe"); + Widget *wireframe_button = Widget_label_new ("Toggle wireframe", TEXT_ALIGN_CENTER); Widget_set_background_color (wireframe_button, 1.0, 1.0, 1.0, 0.2); Widget_set_hover_background_color (wireframe_button, 1.0, 1.0, 1.0, 0.3); Widget_set_on_left_click (wireframe_button, uicb_flag_switch, "wireframe_enabled"); - Widget *flight_button = Widget_label_new ("Toggle flight"); + Widget *flight_button = Widget_label_new ("Toggle flight", TEXT_ALIGN_CENTER); Widget_set_background_color (flight_button, 1.0, 1.0, 1.0, 0.2); Widget_set_hover_background_color (flight_button, 1.0, 1.0, 1.0, 0.3); Widget_set_on_left_click (flight_button, uicb_flag_switch, "flight_enabled"); @@ -122,21 +126,21 @@ uiman_cb_mouse_motion (SDL_Event *event, void *data) vec2 ui_pos; screen_to_ui_coords (event->motion.x, event->motion.y, win_w, win_h, ui_pos); - Widget *element = Widget_find_xy (ui_root, GLM_MAT3_IDENTITY, ui_pos); + Widget *widget = Widget_find_xy (ui_root, GLM_MAT3_IDENTITY, ui_pos); - if (element != hovered_element) + if (widget != hovered_widget) { - if (hovered_element) + if (hovered_widget) { - hovered_element->hovered = false; + hovered_widget->hovered = false; } - if (element) + if (widget) { - element->hovered = true; + widget->hovered = true; } - hovered_element = element; + hovered_widget = widget; } /* This callback always eats the event, because why would the game @@ -155,19 +159,19 @@ uiman_cb_button_down (SDL_Event *event, void *data) vec2 ui_pos; screen_to_ui_coords (event->motion.x, event->motion.y, win_w, win_h, ui_pos); - Widget *element = Widget_find_xy (ui_root, GLM_MAT3_IDENTITY, ui_pos); + Widget *widget = Widget_find_xy (ui_root, GLM_MAT3_IDENTITY, ui_pos); - if (element) + if (widget) { - if (event->button.button == SDL_BUTTON_LEFT && element->on_left_click) + if (event->button.button == SDL_BUTTON_LEFT && widget->on_left_click) { - element->on_left_click (element, element->left_click_data); + widget->on_left_click (widget, widget->left_click_data); return true; } - if (event->button.button == SDL_BUTTON_RIGHT && element->on_right_click) + if (event->button.button == SDL_BUTTON_RIGHT && widget->on_right_click) { - element->on_right_click (element, element->right_click_data); + widget->on_right_click (widget, widget->right_click_data); return true; } } diff --git a/game/src/ui/widget.c b/game/src/ui/widget.c index a14f815..b9665d2 100644 --- a/game/src/ui/widget.c +++ b/game/src/ui/widget.c @@ -3,22 +3,20 @@ /* TODO: Layout container children scaling, so some children can be smaller, some bigger, etc. Perhaps android-esque LinearLayout weight? */ -/* TODO: Text alignment in labels. */ -/* TODO: Padding. */ +/* TODO: Label callback with format. */ /* TODO: Widget borders. */ -/* TODO: Texture support in the uielement shader. */ static SimpleMesh quad; static unsigned int last_program; void -ui_element_mesh_init () +ui_widget_mesh_init () { quad = SimpleMesh_make_quad1 (); } static inline Widget * -ui_el_new_internal (UIKind kind) +ui_el_new_internal (WidgetKind kind) { /* new0 instead of new is important, otherwise there's trash memory in the function pointers */ @@ -33,67 +31,75 @@ ui_el_new_internal (UIKind kind) Widget * Widget_root_new () { - Widget *e = ui_el_new_internal (UI_KIND_ROOT); + Widget *e = ui_el_new_internal (WIDGET_ROOT); return e; } Widget * Widget_container_new (gboolean horizontal) { - Widget *e = ui_el_new_internal (UI_KIND_CONTAINER); + Widget *e = ui_el_new_internal (WIDGET_CONTAINER); e->container.horizontal = horizontal; return e; } Widget * -Widget_label_new (const char *text) +Widget_label_new (const char *text, TextAlignment alignment) { - Widget *e = ui_el_new_internal (UI_KIND_LABEL); + Widget *e = ui_el_new_internal (WIDGET_LABEL); e->label.text = g_string_new (text); + e->label.alignment = alignment; glm_vec4_one (e->label.text_color); return e; } void -Widget_set_on_tick (Widget *element, +Widget_set_on_tick (Widget *widget, void (*on_tick) (struct Widget *self, void *userdata), void *userdata) { - element->on_tick = on_tick; - element->tick_data = userdata; + widget->on_tick = on_tick; + widget->tick_data = userdata; } void -Widget_set_on_left_click (Widget *element, +Widget_set_on_left_click (Widget *widget, void (*on_left_click) (struct Widget *, void *), void *userdata) { - element->on_left_click = on_left_click; - element->left_click_data = userdata; + widget->on_left_click = on_left_click; + widget->left_click_data = userdata; } void -Widget_set_background_color (Widget *element, float r, float g, float b, float a) +Widget_set_position (Widget *widget, float x, float y) { - glm_vec4_copy ((vec4) { r, g, b, a }, element->background_color); + glm_vec2_copy ((vec2) { x, y }, widget->position); } void -Widget_set_hover_background_color (Widget *element, float r, float g, float b, float a) +Widget_set_scale (Widget *widget, float x, float y) { - glm_vec4_copy ((vec4) { r, g, b, a }, element->hover_background_color); + glm_vec2_copy ((vec2) { x, y }, widget->scale); } void -Widget_set_position (Widget *element, float x, float y) +Widget_set_texture (Widget *widget, unsigned int texture) { - glm_vec2_copy ((vec2) { x, y }, element->position); + widget->texture = texture; + widget->has_texture = TRUE; } void -Widget_set_scale (Widget *element, float x, float y) +Widget_set_background_color (Widget *widget, float r, float g, float b, float a) { - glm_vec2_copy ((vec2) { x, y }, element->scale); + glm_vec4_copy ((vec4) { r, g, b, a }, widget->background_color); +} + +void +Widget_set_hover_background_color (Widget *widget, float r, float g, float b, float a) +{ + glm_vec4_copy ((vec4) { r, g, b, a }, widget->hover_background_color); } void @@ -104,19 +110,31 @@ Widget_add_child (Widget *parent, Widget *child) } void -Widget_label_render_text (Widget *element, mat3 parent_model) +Widget_label_render_text (Widget *widget, mat3 parent_model) { mat3 model; glm_mat3_copy (parent_model, model); - float abs_scale_x = glm_vec2_norm ((vec2) { model[0][0], model[1][0] }); - float abs_scale_y = glm_vec2_norm ((vec2) { model[0][1], model[1][1] }); - - /* I have no idea about all those calculations, but trial and error - shows they work. */ - glm_translate2d (model, (vec2) { -1.0 + abs_scale_y / abs_scale_x * 0.5, 0.0 }); - glm_scale2d (model, (vec2) { abs_scale_y / abs_scale_x * 0.5, 1.0 }); + /* Times 0.5 because the font is 8x16 */ + float char_width = wdg_real_height (model) / wdg_real_width (model) * 0.5; + /* * 1.5 because that's the step we use in the loop later on. */ + float total_width = (widget->label.text->len - 1) * char_width * 1.5; + switch (widget->label.alignment) + { + case TEXT_ALIGN_RIGHT: + glm_translate2d (model, (vec2) { 1.0 - total_width - char_width, 0.0 }); + break; + case TEXT_ALIGN_CENTER: + glm_translate2d (model, (vec2) { -total_width / 2.0, 0.0 }); + break; + default: + glm_translate2d (model, (vec2) { -1.0 + char_width, 0.0 }); + break; + } + + glm_scale2d (model, (vec2) { char_width, 1.0 }); + glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, RESTEX ("font0")); @@ -125,15 +143,17 @@ Widget_label_render_text (Widget *element, mat3 parent_model) last_program = program_use (RESPRG ("uitext")); } - const char *p = element->label.text->str; + const char *p = widget->label.text->str; while (*p) { gunichar ch = g_utf8_get_char (p); program_set_mat3 (RESPRG ("uitext"), "model", model); program_set_float (RESPRG ("uitext"), "character", ch); - program_set_vec4 (RESPRG ("uitext"), "color", element->label.text_color); + program_set_vec4 (RESPRG ("uitext"), "text_color", widget->label.text_color); SimpleMesh_render (&quad, false); /* UI always without wireframe. */ + /* 1.5 because we want to go forward half of this character and + one character more. */ glm_translate2d (model, (vec2) { 1.5f, 0.0f }); p = g_utf8_next_char (p); @@ -141,22 +161,22 @@ Widget_label_render_text (Widget *element, mat3 parent_model) } void -UIContainer_layout (Widget *element) +UIContainer_layout (Widget *widget) { - if (element->children->len == 0) + if (widget->children->len == 0) { return; } - float size = 1.0 / element->children->len; + float size = 1.0 / widget->children->len; float start_pos = 1.0 - size; float step = size * 2.0; - for (guint i = 0; i < element->children->len; ++i) + for (guint i = 0; i < widget->children->len; ++i) { - Widget *child = g_array_index (element->children, Widget *, i); + Widget *child = g_array_index (widget->children, Widget *, i); - if (element->container.horizontal) + if (widget->container.horizontal) { child->position[0] = -start_pos + (i * step); child->scale[0] = size; @@ -170,61 +190,66 @@ UIContainer_layout (Widget *element) } void -Widget_render_with_model (Widget *element, mat3 parent_model) +Widget_render_with_model (Widget *widget, mat3 parent_model) { - if (!element->visible) + if (!widget->visible) { return; } - if (last_program != RESPRG ("uielement")) + if (last_program != RESPRG ("uiwidget")) { - last_program = program_use (RESPRG ("uielement")); + last_program = program_use (RESPRG ("uiwidget")); } mat3 model; glm_mat3_copy (parent_model, model); - glm_translate2d (model, element->position); - glm_scale2d (model, element->scale); + glm_translate2d (model, widget->position); + vec2 padded; + float ratio = widget->scale[0] / widget->scale[1]; + padded[0] = widget->scale[0] - widget->padding * ratio; + padded[1] = widget->scale[1] - widget->padding; + glm_scale2d (model, padded); - if (element->kind == UI_KIND_CONTAINER) + if (widget->kind == WIDGET_CONTAINER) { - UIContainer_layout (element); + UIContainer_layout (widget); } - if (element->kind != UI_KIND_ROOT) + if (widget->kind != WIDGET_ROOT) { - program_set_mat3 (RESPRG ("uielement"), "model", model); - program_set_vec4 (RESPRG ("uielement"), "color", - element->hovered ? element->hover_background_color - : element->background_color); - + program_set_mat3 (RESPRG ("uiwidget"), "model", model); + program_set_vec4 (RESPRG ("uiwidget"), "background_color", + widget->hovered ? widget->hover_background_color + : widget->background_color); + program_set_int (RESPRG ("uiwidget"), "has_texture", widget->has_texture); + glActiveTexture (GL_TEXTURE0); - texture_use (element->texture); + texture_use (widget->texture); SimpleMesh_render (&quad, false); } - if (element->kind == UI_KIND_LABEL) + if (widget->kind == WIDGET_LABEL) { /* Here, we additionally render the text. */ - Widget_label_render_text (element, model); + Widget_label_render_text (widget, model); } - for (guint i = 0; i < element->children->len; ++i) + for (guint i = 0; i < widget->children->len; ++i) { - Widget *child = g_array_index (element->children, Widget *, i); + Widget *child = g_array_index (widget->children, Widget *, i); Widget_render_with_model (child, model); } } static gboolean -Widget_hit_test (Widget *element, mat3 parent_model, vec2 point) +Widget_hit_test (Widget *widget, mat3 parent_model, vec2 point) { mat3 model; glm_mat3_copy (parent_model, model); - glm_translate2d (model, element->position); - glm_scale2d (model, element->scale); + glm_translate2d (model, widget->position); + glm_scale2d (model, widget->scale); mat3 inv; glm_mat3_inv (model, inv); @@ -236,48 +261,48 @@ Widget_hit_test (Widget *element, mat3 parent_model, vec2 point) } Widget * -Widget_find_xy (Widget *element, mat3 parent_model, vec2 mouse_ui_pos) +Widget_find_xy (Widget *widget, mat3 parent_model, vec2 mouse_ui_pos) { mat3 model; glm_mat3_copy (parent_model, model); - glm_translate2d (model, element->position); - glm_scale2d (model, element->scale); + glm_translate2d (model, widget->position); + glm_scale2d (model, widget->scale); - for (int i = element->children->len - 1; i >= 0; --i) + for (int i = widget->children->len - 1; i >= 0; --i) { - Widget *child = g_array_index (element->children, Widget *, i); + Widget *child = g_array_index (widget->children, Widget *, i); Widget *hit = Widget_find_xy (child, model, mouse_ui_pos); if (hit) return hit; } - if (element->kind != UI_KIND_ROOT && Widget_hit_test (element, parent_model, mouse_ui_pos)) - return element; + if (widget->kind != WIDGET_ROOT && Widget_hit_test (widget, parent_model, mouse_ui_pos)) + return widget; return NULL; } void -Widget_tick (Widget *element) +Widget_tick (Widget *widget) { - if (element->on_tick) + if (widget->on_tick) { - element->on_tick (element, element->tick_data); + widget->on_tick (widget, widget->tick_data); } - for (guint i = 0; i < element->children->len; ++i) + for (guint i = 0; i < widget->children->len; ++i) { - Widget *child = g_array_index (element->children, Widget *, i); + Widget *child = g_array_index (widget->children, Widget *, i); Widget_tick (child); } } void -Widget_render (Widget *element) +Widget_render (Widget *widget) { last_program = -1; - if (element->kind == UI_KIND_ROOT && element->parent == NULL) + if (widget->kind == WIDGET_ROOT && widget->parent == NULL) { SimpleMesh_bind (&quad); @@ -285,51 +310,57 @@ Widget_render (Widget *element) glBindTexture (GL_TEXTURE_2D, 0); mat3 identity = GLM_MAT3_IDENTITY_INIT; - Widget_render_with_model (element, identity); + Widget_render_with_model (widget, identity); } } void -Widget_label_set_text (Widget *element, const char *text) +Widget_label_set_text (Widget *widget, const char *text) { - g_string_overwrite (element->label.text, 0, text); + g_string_overwrite (widget->label.text, 0, text); } void -Widget_label_printf (Widget *element, const char *format, ...) +Widget_label_printf (Widget *widget, const char *format, ...) { va_list args; va_start (args, format); - g_string_vprintf (element->label.text, format, args); + g_string_vprintf (widget->label.text, format, args); va_end (args); } void -uicb_label_show_int (Widget *element, void *userdata) +Widget_label_set_text_color (Widget *widget, float r, float g, float b, float a) +{ + glm_vec4_copy ((vec4) { r, g, b, a }, widget->label.text_color); +} + +void +uicb_label_show_int (Widget *widget, void *userdata) { int *value = userdata; - Widget_label_printf (element, "%d", *value); + Widget_label_printf (widget, "%d", *value); } void -uicb_label_show_float (Widget *element, void *userdata) +uicb_label_show_float (Widget *widget, void *userdata) { float *value = userdata; - Widget_label_printf (element, "%3.2f", *value); + Widget_label_printf (widget, "%3.2f", *value); } void -uicb_flag_switch (Widget *element, void *userdata) +uicb_flag_switch (Widget *widget, void *userdata) { - UNUSED (element); + UNUSED (widget); char *flag = userdata; flags_switch (flag); } void -uicb_debug (Widget *element, void *userdata) +uicb_debug (Widget *widget, void *userdata) { - UNUSED (element); + UNUSED (widget); char *text = userdata; g_debug ("%s", text); } diff --git a/game/src/ui/widget.h b/game/src/ui/widget.h index 699c3f1..89bd576 100644 --- a/game/src/ui/widget.h +++ b/game/src/ui/widget.h @@ -9,37 +9,58 @@ #include "../gl/mesh.h" #include "../gl/program.h" -typedef enum UIKind +typedef enum WidgetKind { - UI_KIND_ROOT, - UI_KIND_CONTAINER, - UI_KIND_LABEL - } UIKind; + WIDGET_ROOT, + WIDGET_CONTAINER, + WIDGET_LABEL + } WidgetKind; -typedef struct UIContainer +typedef struct WidgetContainer { gboolean horizontal; -} UIContainer; +} WidgetContainer; -typedef struct UILabel +typedef enum TextAlignment + { + TEXT_ALIGN_LEFT, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT + } TextAlignment; + +typedef struct WidgetLabel { vec4 text_color; GString *text; - enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } alignment; -} UILabel; + TextAlignment alignment; +} WidgetLabel; typedef struct Widget { - UIKind kind; struct Widget *parent; GArray *children; - vec2 position; - vec2 scale; - vec4 background_color, hover_background_color; - unsigned int texture; + WidgetKind kind; + union { + WidgetContainer container; + WidgetLabel label; + }; + gboolean visible; gboolean hovered; + + /* Remember that the coordinate system is -1 to 1. Both for the root + element and all it's children. For the root it's relative to the + screen, for the children it's relative to the parent. */ + vec2 position; + vec2 scale; + /* This is in uh... some units. OpenGL -1 to 1, but relative to the + parent widget. But it is the same on all sides VISUALLY. */ + float padding; + + vec4 background_color, hover_background_color; + gboolean has_texture; + unsigned int texture; void (*on_left_click) (struct Widget *, void *); void *left_click_data; @@ -47,38 +68,47 @@ typedef struct Widget void *right_click_data; void (*on_tick) (struct Widget *, void *); void *tick_data; - - union { - UIContainer container; - UILabel label; - }; } Widget; -void ui_element_mesh_init (); +static inline float +wdg_real_width (mat3 model) +{ + return glm_vec2_norm ((vec2) { model[0][0], model[1][0] }); +} + +static inline float +wdg_real_height (mat3 model) +{ + return glm_vec2_norm ((vec2) { model[0][1], model[1][1] }); +} + +void ui_widget_mesh_init (); Widget *Widget_root_new (); Widget *Widget_container_new (gboolean horizontal); -Widget *Widget_label_new (const char *text); +Widget *Widget_label_new (const char *text, TextAlignment alignment); void Widget_add_child (Widget *parent, Widget *child); -void Widget_set_on_left_click (Widget *element, void (*on_left_click) (struct Widget *, void *), void *userdata); -void Widget_set_on_tick (Widget *element, void (*on_tick) (struct Widget *, void *), void *userdata); +void Widget_set_on_left_click (Widget *widget, void (*on_left_click) (struct Widget *, void *), void *userdata); +void Widget_set_on_tick (Widget *widget, void (*on_tick) (struct Widget *, void *), void *userdata); -void Widget_set_background_color (Widget *element, float r, float g, float b, float a); -void Widget_set_hover_background_color (Widget *element, float r, float g, float b, float a); -void Widget_set_position (Widget *element, float x, float y); -void Widget_set_scale (Widget *element, float x, float y); +void Widget_set_position (Widget *widget, float x, float y); +void Widget_set_scale (Widget *widget, float x, float y); +void Widget_set_background_color (Widget *widget, float r, float g, float b, float a); +void Widget_set_hover_background_color (Widget *widget, float r, float g, float b, float a); +void Widget_set_texture (Widget *widget, unsigned int texture); -Widget *Widget_find_xy (Widget *element, mat3 parent_model, vec2 mouse_ui_pos); -void Widget_tick (Widget *element); -void Widget_render (Widget *element); +Widget *Widget_find_xy (Widget *widget, mat3 parent_model, vec2 mouse_ui_pos); +void Widget_tick (Widget *widget); +void Widget_render (Widget *widget); -void Widget_label_set_text (Widget *element, const char *text); -void Widget_label_printf (Widget *element, const char *format, ...); +void Widget_label_set_text (Widget *widget, const char *text); +void Widget_label_printf (Widget *widget, const char *format, ...); +void Widget_label_set_text_color (Widget *widget, float r, float g, float b, float a); -void uicb_label_show_int (Widget *element, void *userdata); -void uicb_label_show_float (Widget *element, void *userdata); +void uicb_label_show_int (Widget *widget, void *userdata); +void uicb_label_show_float (Widget *widget, void *userdata); -void uicb_flag_switch (Widget *element, void *userdata); -void uicb_debug (Widget *element, void *userdata); +void uicb_flag_switch (Widget *widget, void *userdata); +void uicb_debug (Widget *widget, void *userdata);