UI improvements, text alignment, textures, etc.
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 color;
|
||||
uniform sampler2D texture;
|
||||
|
||||
varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
gl_FragColor = color;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
|
||||
+30
-26
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+119
-88
@@ -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);
|
||||
}
|
||||
|
||||
+67
-37
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user