UI system revamp
This commit is contained in:
@@ -2,12 +2,12 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform vec3 color;
|
||||
uniform vec4 color;
|
||||
uniform sampler2D texture;
|
||||
|
||||
varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
gl_FragColor = texture2D (texture, f_uv) * vec4 (color, 1.0);
|
||||
gl_FragColor = vec4 (color.xyz, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,31 +1,14 @@
|
||||
#version 100
|
||||
|
||||
attribute vec4 position;
|
||||
attribute vec3 position;
|
||||
attribute vec2 uv;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform float time;
|
||||
uniform float character;
|
||||
uniform mat3 model;
|
||||
|
||||
varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
float tex_w = 128.0;
|
||||
float tex_h = 128.0;
|
||||
|
||||
float char_w = 8.0;
|
||||
float char_h = 16.0;
|
||||
|
||||
float chars_per_row = tex_w / char_w;
|
||||
|
||||
float x = mod (character, chars_per_row);
|
||||
float y = floor (character / chars_per_row);
|
||||
|
||||
vec2 char_offset = vec2 (x * char_w / tex_w, y * char_h / tex_h);
|
||||
vec2 char_size = vec2 (char_w / tex_w, char_h / tex_h);
|
||||
|
||||
f_uv = char_offset + uv * char_size;
|
||||
|
||||
gl_Position = model * position;
|
||||
f_uv = uv;
|
||||
gl_Position = vec4 (model * vec3 (position.xy, 1.0), 1.0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 color;
|
||||
uniform sampler2D texture;
|
||||
|
||||
varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
|
||||
gl_FragColor = texture2D (texture, f_uv) * vec4 (color.xyz, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#version 100
|
||||
|
||||
attribute vec3 position;
|
||||
attribute vec2 uv;
|
||||
|
||||
uniform mat3 model;
|
||||
uniform float character;
|
||||
|
||||
varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
float tex_w = 128.0;
|
||||
float tex_h = 128.0;
|
||||
|
||||
float char_w = 8.0;
|
||||
float char_h = 16.0;
|
||||
|
||||
float chars_per_row = tex_w / char_w;
|
||||
|
||||
float x = mod (character, chars_per_row);
|
||||
float y = floor (character / chars_per_row);
|
||||
|
||||
vec2 char_offset = vec2 (x * char_w / tex_w, y * char_h / tex_h);
|
||||
vec2 char_size = vec2 (char_w / tex_w, char_h / tex_h);
|
||||
|
||||
f_uv = char_offset + uv * char_size;
|
||||
|
||||
gl_Position = vec4 (model * vec3 (position.xy, 1.0), 1.0);
|
||||
}
|
||||
+19
-25
@@ -120,19 +120,16 @@ chunkman_tick (vec3 position)
|
||||
{
|
||||
for (int x = cx - RENDER_DISTANCE - 1; x <= cx + RENDER_DISTANCE + 1; ++x)
|
||||
{
|
||||
if ((x - cx) * (x - cx) + (z - cz) * (z - cz) <= (RENDER_DISTANCE + 1) * (RENDER_DISTANCE + 1))
|
||||
{
|
||||
if (chunkman_get_Chunk_at (x, z) == NULL)
|
||||
{
|
||||
chunkman_generate_Chunk_at (x, z);
|
||||
++frame_chunks;
|
||||
}
|
||||
if (chunkman_get_Chunk_at (x, z) == NULL)
|
||||
{
|
||||
chunkman_generate_Chunk_at (x, z);
|
||||
++frame_chunks;
|
||||
}
|
||||
|
||||
if (frame_chunks > CHUNKS_PER_FRAME || SDL_GetTicks () - frame_time > FRAME_BUDGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (frame_chunks > CHUNKS_PER_FRAME || SDL_GetTicks () - frame_time > FRAME_BUDGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,20 +137,17 @@ chunkman_tick (vec3 position)
|
||||
{
|
||||
for (int x = cx - RENDER_DISTANCE; x <= cx + RENDER_DISTANCE; ++x)
|
||||
{
|
||||
if ((x - cx) * (x - cx) + (z - cz) * (z - cz) <= RENDER_SQR)
|
||||
{
|
||||
if (chunkman_get_ChunkMesh_at (x, z) == NULL)
|
||||
{
|
||||
chunkman_generate_ChunkMesh_at (x, z);
|
||||
++frame_chunks;
|
||||
}
|
||||
if (chunkman_get_ChunkMesh_at (x, z) == NULL)
|
||||
{
|
||||
chunkman_generate_ChunkMesh_at (x, z);
|
||||
++frame_chunks;
|
||||
}
|
||||
|
||||
if (frame_chunks > CHUNKS_PER_FRAME || SDL_GetTicks () - frame_time > FRAME_BUDGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frame_chunks > CHUNKS_PER_FRAME || SDL_GetTicks () - frame_time > FRAME_BUDGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,9 +97,6 @@ entman_render_entity (Entity *entity, void *userdata)
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Fix this up. It still isn't perfect, when you look up,
|
||||
sometimes the entities get culled. */
|
||||
|
||||
#if FRUSTUM_CULL
|
||||
vec3 aabb[2];
|
||||
entity_compute_aabb (entity, aabb[0], aabb[1]);
|
||||
|
||||
+52
-29
@@ -5,7 +5,29 @@ extern vec3 camera_rotation;
|
||||
static GList *handlers = NULL;
|
||||
|
||||
bool
|
||||
rotate_camera (SDL_Event *event, void *userdata)
|
||||
evt_pred_key (SDL_Event *event, void *data)
|
||||
{
|
||||
unsigned int expected_key = GPOINTER_TO_INT (data);
|
||||
return event->key.key == expected_key;
|
||||
}
|
||||
|
||||
bool
|
||||
evt_pred_mouse (SDL_Event *event, void *data)
|
||||
{
|
||||
unsigned int expected_button = GPOINTER_TO_INT (data);
|
||||
return event->button.button == expected_button;
|
||||
}
|
||||
|
||||
bool
|
||||
evt_pred_flag (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event);
|
||||
char *flag = data;
|
||||
return flags_get (flag);
|
||||
}
|
||||
|
||||
bool
|
||||
evt_cb_rotate_camera (SDL_Event *event, void *userdata)
|
||||
{
|
||||
UNUSED (userdata);
|
||||
camera_rotation[0] -= event->motion.xrel / 100.f;
|
||||
@@ -16,19 +38,7 @@ rotate_camera (SDL_Event *event, void *userdata)
|
||||
}
|
||||
|
||||
bool
|
||||
key_predicate (SDL_Event *event, void *data)
|
||||
{
|
||||
if (event->type != SDL_EVENT_KEY_DOWN && event->type != SDL_EVENT_KEY_UP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int expected_key = GPOINTER_TO_INT (data);
|
||||
return event->key.key == expected_key;
|
||||
}
|
||||
|
||||
bool
|
||||
flag_off (SDL_Event *event, void *data)
|
||||
evt_cb_flag_off (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event);
|
||||
char *flag = data;
|
||||
@@ -37,7 +47,7 @@ flag_off (SDL_Event *event, void *data)
|
||||
}
|
||||
|
||||
bool
|
||||
flag_on (SDL_Event *event, void *data)
|
||||
evt_cb_flag_on (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event);
|
||||
char *flag = data;
|
||||
@@ -46,29 +56,42 @@ flag_on (SDL_Event *event, void *data)
|
||||
}
|
||||
|
||||
bool
|
||||
flag_switch (SDL_Event *event, void *data)
|
||||
evt_cb_flag_switch (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event);
|
||||
char *flag = data;
|
||||
flags_set (flag, !flags_get (flag));
|
||||
flags_switch (flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
evtman_init ()
|
||||
{
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, key_predicate, GINT_TO_POINTER(SDLK_W), flag_on, "moving_forward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, key_predicate, GINT_TO_POINTER(SDLK_W), flag_off, "moving_forward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, key_predicate, GINT_TO_POINTER(SDLK_S), flag_on, "moving_backward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, key_predicate, GINT_TO_POINTER(SDLK_S), flag_off, "moving_backward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, key_predicate, GINT_TO_POINTER(SDLK_A), flag_on, "moving_left");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, key_predicate, GINT_TO_POINTER(SDLK_A), flag_off, "moving_left");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, key_predicate, GINT_TO_POINTER(SDLK_D), flag_on, "moving_right");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, key_predicate, GINT_TO_POINTER(SDLK_D), flag_off, "moving_right");
|
||||
#define KEY(k) GINT_TO_POINTER(k)
|
||||
|
||||
evtman_add_handler (2, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY(SDLK_F1), evt_cb_flag_switch, "wireframe_enabled");
|
||||
/* The UI effectively eats most SDL events, as it needs it for it's
|
||||
own calculations. */
|
||||
evtman_add_handler (1, SDL_EVENT_KEY_DOWN, evt_pred_flag, "ui_has_focus", uiman_cb_key_down, NULL);
|
||||
evtman_add_handler (1, SDL_EVENT_KEY_UP, evt_pred_flag, "ui_has_focus", uiman_cb_key_up, NULL);
|
||||
evtman_add_handler (1, SDL_EVENT_MOUSE_MOTION, evt_pred_flag, "ui_has_focus", uiman_cb_mouse_motion, NULL);
|
||||
evtman_add_handler (1, SDL_EVENT_MOUSE_BUTTON_DOWN, evt_pred_flag, "ui_has_focus", uiman_cb_button_down, NULL);
|
||||
evtman_add_handler (1, SDL_EVENT_MOUSE_BUTTON_UP, evt_pred_flag, "ui_has_focus", uiman_cb_button_up, NULL);
|
||||
evtman_add_handler (1, SDL_EVENT_MOUSE_WHEEL, evt_pred_flag, "ui_has_focus", uiman_cb_mouse_wheel, NULL);
|
||||
evtman_add_handler (1, SDL_EVENT_TEXT_INPUT, evt_pred_flag, "ui_has_focus", uiman_cb_text_input, NULL);
|
||||
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_W), evt_cb_flag_on, "moving_forward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_W), evt_cb_flag_off, "moving_forward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_S), evt_cb_flag_on, "moving_backward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_S), evt_cb_flag_off, "moving_backward");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_A), evt_cb_flag_on, "moving_left");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_A), evt_cb_flag_off, "moving_left");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_D), evt_cb_flag_on, "moving_right");
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_D), evt_cb_flag_off, "moving_right");
|
||||
evtman_add_handler (0, SDL_EVENT_MOUSE_MOTION, NULL, NULL, evt_cb_rotate_camera, NULL);
|
||||
evtman_add_handler (0, SDL_EVENT_MOUSE_BUTTON_DOWN, evt_pred_mouse, KEY (3), uiman_cb_switch_focus, NULL);
|
||||
|
||||
evtman_add_handler (0, SDL_EVENT_KEY_DOWN, key_predicate, GINT_TO_POINTER(SDLK_F1), flag_switch, "wireframe_enabled");
|
||||
|
||||
evtman_add_handler (0, SDL_EVENT_MOUSE_MOTION, NULL, NULL, rotate_camera, NULL);
|
||||
#undef KEY
|
||||
}
|
||||
|
||||
void
|
||||
@@ -105,7 +128,7 @@ evtman_handle_SDL_Event (SDL_Event *event)
|
||||
if ((h->filter == 0 || h->filter == event->type)
|
||||
&& (!h->predicate || h->predicate (event, h->predicate_data)))
|
||||
{
|
||||
if (h->callback (event, h->callback_data))
|
||||
if (h->callback && h->callback (event, h->callback_data))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "handler.h"
|
||||
#include "../flags.h"
|
||||
#include "../util.h"
|
||||
#include "../ui/uiman.h"
|
||||
|
||||
void evtman_init ();
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@ flags_init ()
|
||||
flags = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
void
|
||||
flags_switch (char *flag)
|
||||
{
|
||||
flags_set (flag, !flags_get (flag));
|
||||
}
|
||||
|
||||
void
|
||||
flags_set (char *flag, bool value)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,22 @@
|
||||
|
||||
#include <glib-2.0/glib.h>
|
||||
|
||||
/*
|
||||
|
||||
A short list of most flags used in the game:
|
||||
|
||||
wireframe_enabled
|
||||
|
||||
moving_forward
|
||||
moving_backward
|
||||
moving_left
|
||||
moving_right
|
||||
|
||||
ui_has_focus
|
||||
|
||||
*/
|
||||
|
||||
void flags_init ();
|
||||
void flags_switch (char *flag);
|
||||
void flags_set (char *flag, bool value);
|
||||
bool flags_get (char *flag);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
#include "program.h"
|
||||
|
||||
void
|
||||
@@ -78,6 +79,12 @@ program_set_vec3 (int program, const char *name, vec3 value)
|
||||
glUniform3f (glGetUniformLocation (program, name), value[0], value[1], value[2]);
|
||||
}
|
||||
|
||||
void
|
||||
program_set_vec4 (int program, const char *name, vec4 value)
|
||||
{
|
||||
glUniform4f (glGetUniformLocation (program, name), value[0], value[1], value[2], value[3]);
|
||||
}
|
||||
|
||||
void
|
||||
program_set_vec3_ind (int program, const char *name, float x, float y, float z)
|
||||
{
|
||||
@@ -96,6 +103,12 @@ program_set_int_array (int program, const char *name, size_t count, int *value)
|
||||
glUniform1iv (glGetUniformLocation (program, name), count, value);
|
||||
}
|
||||
|
||||
void
|
||||
program_set_mat3 (int program, const char *name, mat3 value)
|
||||
{
|
||||
glUniformMatrix3fv (glGetUniformLocation (program, name), 1, GL_FALSE, (float *) value);
|
||||
}
|
||||
|
||||
void
|
||||
program_set_mat4 (int program, const char *name, mat4 value)
|
||||
{
|
||||
|
||||
@@ -15,5 +15,7 @@ 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);
|
||||
void program_set_vec3_ind (int program, const char *name, float x, float y, float z);
|
||||
void program_set_vec4 (int program, const char *name, vec4 value);
|
||||
void program_set_mat3 (int program, const char *name, mat3 value);
|
||||
void program_set_mat4 (int program, const char *name, mat4 value);
|
||||
void program_print (int program);
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
extern vec3 camera_position;
|
||||
extern int last_time;
|
||||
|
||||
static SDL_Window *sdl_window;
|
||||
SDL_Window *sdl_window;
|
||||
static SDL_GLContext gl_context;
|
||||
|
||||
#define WINDOW_WIDTH 800
|
||||
|
||||
@@ -54,6 +54,7 @@ SDL_AppIterate (void *appstate)
|
||||
game_state_tick (SDL_GetTicks ());
|
||||
entman_tick ();
|
||||
chunkman_tick (camera_position);
|
||||
uiman_tick ();
|
||||
graphics_render ();
|
||||
|
||||
return SDL_APP_CONTINUE;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "resources.h"
|
||||
|
||||
/* TODO: Warn if program doesn't exist, make program_use and
|
||||
texture_use return the textures/ */
|
||||
|
||||
static GHashTable *programs;
|
||||
static GHashTable *textures;
|
||||
|
||||
@@ -152,6 +155,7 @@ resources_init ()
|
||||
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 ("uitext", RLP ("res/shaders/uitext.vert", "res/shaders/uitext.frag"));
|
||||
|
||||
RAT ("terrain0", RLT ("res/textures/dirt.png"));
|
||||
RAT ("terrain1", RLT ("res/textures/drygrass.png"));
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
extern vec3 camera_position;
|
||||
extern vec3 camera_rotation;
|
||||
extern Entity *player_entity, *sky_entity;
|
||||
extern UIElement *player_pos, *n_ents, *n_chunks, *frame_time;
|
||||
extern int n_frame_ents, n_frame_chunks;
|
||||
|
||||
float delta_time;
|
||||
int last_time;
|
||||
@@ -32,13 +30,6 @@ game_state_tick (int ticks)
|
||||
sky. */
|
||||
sky_entity->position[0] = camera_position[0];
|
||||
sky_entity->position[2] = camera_position[2];
|
||||
|
||||
g_string_printf (player_pos->text, "Position (X:%2.1f, Y:%2.1f, Z:%2.1f)",
|
||||
player_entity->position[0], player_entity->position[1],
|
||||
player_entity->position[2]);
|
||||
g_string_printf (n_ents->text, "Entities rendered: %d", n_frame_ents);
|
||||
g_string_printf (n_chunks->text, "Chunks rendered: %d", n_frame_chunks);
|
||||
g_string_printf (frame_time->text, "Frame time: %.3f", delta_time);
|
||||
|
||||
if (flags_get ("moving_forward"))
|
||||
{
|
||||
|
||||
+194
-47
@@ -1,8 +1,10 @@
|
||||
#include "uielement.h"
|
||||
|
||||
/* TODO: Convert to mat3's and 2D affine transformations. */
|
||||
/* TODO: Alpha blending. */
|
||||
|
||||
static SimpleMesh quad;
|
||||
static unsigned int last_program;
|
||||
|
||||
void
|
||||
ui_element_mesh_init ()
|
||||
@@ -10,68 +12,213 @@ ui_element_mesh_init ()
|
||||
quad = SimpleMesh_make_quad1 ();
|
||||
}
|
||||
|
||||
void
|
||||
UIElement_add_child (UIElement *parent, UIElement *child)
|
||||
static inline UIElement *
|
||||
ui_el_new_internal (UIKind kind)
|
||||
{
|
||||
g_sequence_append (parent->children, child);
|
||||
/* new0 instead of new is important, otherwise there's trash memory
|
||||
in the function pointers */
|
||||
UIElement *e = g_new0 (UIElement, 1);
|
||||
e->kind = kind;
|
||||
e->visible = true;
|
||||
glm_vec4_zero (e->background_color);
|
||||
glm_vec2_zero (e->position);
|
||||
glm_vec2_one (e->scale);
|
||||
e->children = g_array_new (false, false, sizeof (UIElement *));
|
||||
return e;
|
||||
}
|
||||
|
||||
UIElement *
|
||||
UIElement_root_new ()
|
||||
{
|
||||
UIElement *e = ui_el_new_internal (UI_KIND_ROOT);
|
||||
return e;
|
||||
}
|
||||
|
||||
UIElement *
|
||||
UIElement_container_new (bool horizontal)
|
||||
{
|
||||
UIElement *e = ui_el_new_internal (UI_KIND_CONTAINER);
|
||||
e->container.horizontal = horizontal;
|
||||
return e;
|
||||
}
|
||||
|
||||
UIElement *
|
||||
UIElement_label_new (const char *text)
|
||||
{
|
||||
UIElement *e = ui_el_new_internal (UI_KIND_LABEL);
|
||||
e->label.text = g_string_new (text);
|
||||
glm_vec4_one (e->label.color);
|
||||
return e;
|
||||
}
|
||||
|
||||
void
|
||||
uiel_render_internal (gpointer data, gpointer userdata)
|
||||
UIElement_set_on_tick (UIElement *element,
|
||||
void (*on_tick) (struct UIElement *self, void *userdata),
|
||||
void *userdata)
|
||||
{
|
||||
UNUSED (userdata);
|
||||
UIElement *element = data;
|
||||
UIElement_render (element);
|
||||
element->on_tick = on_tick;
|
||||
element->userdata = userdata;
|
||||
}
|
||||
|
||||
void
|
||||
UIElement_add_child (UIElement *parent, UIElement *child)
|
||||
{
|
||||
child->parent = parent;
|
||||
g_array_append_val (parent->children, child);
|
||||
}
|
||||
|
||||
void
|
||||
UILabel_render_text (UIElement *element, 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 });
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, RESTEX ("font0"));
|
||||
|
||||
if (last_program != RESPRG ("uitext"))
|
||||
{
|
||||
program_use (RESPRG ("uitext"));
|
||||
last_program = RESPRG ("uitext");
|
||||
}
|
||||
|
||||
for (guint i = 0; i < element->label.text->len; ++i)
|
||||
{
|
||||
program_set_mat3 (RESPRG ("uitext"), "model", model);
|
||||
program_set_float (RESPRG ("uitext"), "character", element->label.text->str[i]);
|
||||
program_set_vec4 (RESPRG ("uitext"), "color", element->label.color);
|
||||
SimpleMesh_render (&quad);
|
||||
glm_translate2d (model, (vec2) { 1.5f, 0.0f });
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIContainer_layout (UIElement *element)
|
||||
{
|
||||
if (element->children->len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float size = 1.0 / element->children->len;
|
||||
float start_pos = 1.0 - size;
|
||||
float step = size * 2.0;
|
||||
|
||||
for (guint i = 0; i < element->children->len; ++i)
|
||||
{
|
||||
UIElement *child = g_array_index (element->children, UIElement *, i);
|
||||
|
||||
if (element->container.horizontal)
|
||||
{
|
||||
child->position[0] = -start_pos + (i * step);
|
||||
child->scale[0] = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
child->position[1] = start_pos - (i * step);
|
||||
child->scale[1] = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIElement_render_with_model (UIElement *element, mat3 parent_model)
|
||||
{
|
||||
if (!element->visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_program != RESPRG ("uielement"))
|
||||
{
|
||||
program_use (RESPRG ("uielement"));
|
||||
last_program = RESPRG ("uielement");
|
||||
}
|
||||
|
||||
mat3 model;
|
||||
glm_mat3_copy (parent_model, model);
|
||||
glm_translate2d (model, element->position);
|
||||
glm_scale2d (model, element->scale);
|
||||
|
||||
if (element->kind == UI_KIND_CONTAINER)
|
||||
{
|
||||
UIContainer_layout (element);
|
||||
}
|
||||
|
||||
if (element->kind != UI_KIND_ROOT)
|
||||
{
|
||||
program_set_mat3 (RESPRG ("uielement"), "model", model);
|
||||
program_set_vec4 (RESPRG ("uielement"), "color", element->background_color);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, element->image);
|
||||
|
||||
SimpleMesh_render (&quad);
|
||||
}
|
||||
|
||||
if (element->kind == UI_KIND_LABEL)
|
||||
{
|
||||
/* Here, we additionally render the text. */
|
||||
UILabel_render_text (element, model);
|
||||
}
|
||||
|
||||
for (guint i = 0; i < element->children->len; ++i)
|
||||
{
|
||||
UIElement *child = g_array_index (element->children, UIElement *, i);
|
||||
UIElement_render_with_model (child, model);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIElement_tick (UIElement *element)
|
||||
{
|
||||
if (element->on_tick)
|
||||
{
|
||||
element->on_tick (element, element->userdata);
|
||||
}
|
||||
|
||||
for (guint i = 0; i < element->children->len; ++i)
|
||||
{
|
||||
UIElement *child = g_array_index (element->children, UIElement *, i);
|
||||
UIElement_tick (child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIElement_render (UIElement *element)
|
||||
{
|
||||
if (element->parent == NULL)
|
||||
if (element->kind == UI_KIND_ROOT && element->parent == NULL)
|
||||
{
|
||||
SimpleMesh_bind (&quad);
|
||||
program_use (RESPRG ("uielement"));
|
||||
}
|
||||
|
||||
if (element->visible)
|
||||
{
|
||||
/* First, we render the background as a quad of
|
||||
`background_color'. */
|
||||
last_program = RESPRG ("uielement");
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
|
||||
mat4 model = GLM_MAT4_IDENTITY_INIT;
|
||||
glm_translate (model, element->position);
|
||||
glm_scale (model, element->scale);
|
||||
|
||||
program_set_mat4 (RESPRG ("uielement"), "model", model);
|
||||
program_set_vec3 (RESPRG ("uielement"), "color", element->background_color);
|
||||
SimpleMesh_render (&quad);
|
||||
|
||||
/* Now, the tedious, boring, and so on task of rendering the
|
||||
text, the worst fate of an OpenGL programmer. */
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, RESTEX ("font0"));
|
||||
program_set_vec3 (RESPRG ("uielement"), "color", element->text_color);
|
||||
|
||||
for (size_t i = 0; i < element->text->len; ++i)
|
||||
{
|
||||
vec3 pos;
|
||||
float x = -element->scale[0] + (element->scale[1] / 2) + (element->scale[1] * i);
|
||||
glm_vec3_add (element->position, (vec3) { x, 0.0, 0.0 }, pos);
|
||||
|
||||
glm_mat4_copy (GLM_MAT4_IDENTITY, model);
|
||||
glm_translate (model, pos);
|
||||
glm_scale (model, (vec3) { element->scale[1] / 2, element->scale[1], 1.0 });
|
||||
|
||||
program_set_mat4 (RESPRG ("uielement"), "model", model);
|
||||
program_set_float (RESPRG ("uielement"), "character", element->text->str[i]);
|
||||
SimpleMesh_render (&quad);
|
||||
}
|
||||
}
|
||||
|
||||
if (element->children != NULL)
|
||||
{
|
||||
g_sequence_foreach (element->children, uiel_render_internal, NULL);
|
||||
mat3 identity = GLM_MAT3_IDENTITY_INIT;
|
||||
UIElement_render_with_model (element, identity);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UILabel_on_tick_show_int (UIElement *element, void *userdata)
|
||||
{
|
||||
int *value = userdata;
|
||||
g_string_printf (element->label.text, "%d", *value);
|
||||
}
|
||||
|
||||
void
|
||||
UILabel_on_tick_show_float (UIElement *element, void *userdata)
|
||||
{
|
||||
float *value = userdata;
|
||||
g_string_printf (element->label.text, "%3.2f", *value);
|
||||
}
|
||||
|
||||
+45
-12
@@ -10,25 +10,58 @@
|
||||
#include "../gl/mesh.h"
|
||||
#include "../gl/program.h"
|
||||
|
||||
typedef enum UIKind
|
||||
{
|
||||
UI_KIND_ROOT,
|
||||
UI_KIND_CONTAINER,
|
||||
UI_KIND_LABEL,
|
||||
} UIKind;
|
||||
|
||||
typedef struct UIContainer
|
||||
{
|
||||
bool horizontal;
|
||||
} UIContainer;
|
||||
|
||||
typedef struct UILabel
|
||||
{
|
||||
vec4 color;
|
||||
GString *text;
|
||||
} UILabel;
|
||||
|
||||
typedef struct UIElement
|
||||
{
|
||||
UIKind kind;
|
||||
struct UIElement *parent;
|
||||
GSequence *children;
|
||||
|
||||
void (*on_left_click) (struct UIElement *self);
|
||||
void (*on_right_click) (struct UIElement *self);
|
||||
void (*on_tick) (struct UIElement *self);
|
||||
void *userdata;
|
||||
GArray *children;
|
||||
|
||||
vec2 position;
|
||||
vec2 scale;
|
||||
vec4 background_color;
|
||||
unsigned int image;
|
||||
bool visible;
|
||||
vec3 text_color;
|
||||
vec3 background_color;
|
||||
|
||||
vec3 position;
|
||||
vec3 scale;
|
||||
GString *text;
|
||||
void *userdata;
|
||||
|
||||
void (*on_left_click) (struct UIElement *self, void *userdata);
|
||||
void (*on_right_click) (struct UIElement *self, void *userdata);
|
||||
void (*on_tick) (struct UIElement *self, void *userdata);
|
||||
|
||||
union {
|
||||
UIContainer container;
|
||||
UILabel label;
|
||||
};
|
||||
} UIElement;
|
||||
|
||||
void ui_element_mesh_init ();
|
||||
void UIElement_render (UIElement *element);
|
||||
|
||||
UIElement *UIElement_root_new ();
|
||||
UIElement *UIElement_container_new (bool horizontal);
|
||||
UIElement *UIElement_label_new (const char *text);
|
||||
|
||||
void UIElement_add_child (UIElement *parent, UIElement *child);
|
||||
void UIElement_set_on_tick (UIElement *element, void (*on_tick) (struct UIElement *self, void *userdata), void *userdata);
|
||||
void UIElement_tick (UIElement *element);
|
||||
void UIElement_render (UIElement *element);
|
||||
|
||||
void UILabel_on_tick_show_int (UIElement *element, void *userdata);
|
||||
void UILabel_on_tick_show_float (UIElement *element, void *userdata);
|
||||
|
||||
+85
-31
@@ -1,54 +1,108 @@
|
||||
#include "uiman.h"
|
||||
|
||||
UIElement *player_pos, *n_ents, *n_chunks, *frame_time;
|
||||
extern SDL_Window *sdl_window;
|
||||
extern float delta_time;
|
||||
extern int n_frame_ents, n_frame_chunks;
|
||||
|
||||
static UIElement ui_root;
|
||||
|
||||
#define UINEWROOT() ((UIElement) { .parent = NULL, .children = g_sequence_new (NULL), .visible = false })
|
||||
#define UINEW(pare) ((UIElement) { .parent = pare, .text_color = { 1.0, 1.0, 1.0 }, .visible = true, .text = g_string_new (NULL) })
|
||||
#define UIADD(pare, child) (UIElement_add_child (pare, child))
|
||||
static UIElement *ui_root;
|
||||
|
||||
void
|
||||
uiman_init ()
|
||||
{
|
||||
ui_element_mesh_init ();
|
||||
ui_root = UINEWROOT ();
|
||||
|
||||
player_pos = malloc (sizeof (UIElement));
|
||||
*player_pos = UINEW (&ui_root);
|
||||
glm_vec3_copy ((vec3) { -0.65, 0.92, 0.0 }, player_pos->position);
|
||||
glm_vec3_copy ((vec3) { 0.3, 0.03, 1.0 }, player_pos->scale);
|
||||
UIADD (&ui_root, player_pos);
|
||||
ui_root = UIElement_root_new ();
|
||||
|
||||
n_ents = malloc (sizeof (UIElement));
|
||||
*n_ents = UINEW (&ui_root);
|
||||
glm_vec3_copy ((vec3) { -0.65, 0.81, 0.0 }, n_ents->position);
|
||||
glm_vec3_copy ((vec3) { 0.3, 0.03, 1.0 }, n_ents->scale);
|
||||
glm_vec3_copy ((vec3) { 0.7, 1.0, 0.7 }, n_ents->text_color);
|
||||
UIADD (&ui_root, n_ents);
|
||||
UIElement *container = UIElement_container_new (false);
|
||||
container->scale[0] = 0.4;
|
||||
container->scale[1] = 0.07;
|
||||
container->position[0] = -0.5;
|
||||
container->position[1] = 0.83;
|
||||
glm_vec3_copy ((vec4) { 1.0, 0.0, 0.0, 1.0 }, container->background_color);
|
||||
|
||||
n_chunks = malloc (sizeof (UIElement));
|
||||
*n_chunks = UINEW (&ui_root);
|
||||
glm_vec3_copy ((vec3) { -0.65, 0.70, 0.0 }, n_chunks->position);
|
||||
glm_vec3_copy ((vec3) { 0.3, 0.03, 1.0 }, n_chunks->scale);
|
||||
UIADD (&ui_root, n_chunks);
|
||||
UIElement *frame_time = UIElement_label_new ("Frame time: ");
|
||||
UIElement *container2 = UIElement_container_new (true);
|
||||
UIElement *entities_rendered = UIElement_label_new ("Entities rendered: ");
|
||||
UIElement *chunks_rendered = UIElement_label_new ("Chunks rendered: ");
|
||||
|
||||
frame_time = malloc (sizeof (UIElement));
|
||||
*frame_time = UINEW (&ui_root);
|
||||
glm_vec3_copy ((vec3) { -0.65, 0.59, 0.0 }, frame_time->position);
|
||||
glm_vec3_copy ((vec3) { 0.3, 0.03, 1.0 }, frame_time->scale);
|
||||
UIADD (&ui_root, frame_time);
|
||||
UIElement_set_on_tick (frame_time, UILabel_on_tick_show_float, &delta_time);
|
||||
UIElement_set_on_tick (entities_rendered, UILabel_on_tick_show_int, &n_frame_ents);
|
||||
UIElement_set_on_tick (chunks_rendered, UILabel_on_tick_show_int, &n_frame_chunks);
|
||||
|
||||
UIElement_add_child (container2, entities_rendered);
|
||||
UIElement_add_child (container2, chunks_rendered);
|
||||
|
||||
UIElement_add_child (container, frame_time);
|
||||
UIElement_add_child (container, container2);
|
||||
|
||||
UIElement_add_child (ui_root, container);
|
||||
}
|
||||
|
||||
void
|
||||
uiman_tick ()
|
||||
{
|
||||
|
||||
UIElement_tick (ui_root);
|
||||
}
|
||||
|
||||
void
|
||||
uiman_render ()
|
||||
{
|
||||
UIElement_render (&ui_root);
|
||||
UIElement_render (ui_root);
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_switch_focus (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
flags_switch ("ui_has_focus");
|
||||
SDL_SetWindowRelativeMouseMode (sdl_window, !flags_get ("ui_has_focus"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_key_down (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_key_up (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_mouse_motion (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_button_down (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_button_up (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_mouse_wheel (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
uiman_cb_text_input (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "uielement.h"
|
||||
#include "../flags.h"
|
||||
#include "../state.h"
|
||||
|
||||
void uiman_init ();
|
||||
void uiman_tick ();
|
||||
void uiman_render ();
|
||||
|
||||
bool uiman_cb_switch_focus (SDL_Event *event, void *data);
|
||||
|
||||
bool uiman_cb_key_down (SDL_Event *event, void *data);
|
||||
bool uiman_cb_key_up (SDL_Event *event, void *data);
|
||||
bool uiman_cb_mouse_motion (SDL_Event *event, void *data);
|
||||
bool uiman_cb_button_down (SDL_Event *event, void *data);
|
||||
bool uiman_cb_button_up (SDL_Event *event, void *data);
|
||||
bool uiman_cb_mouse_wheel (SDL_Event *event, void *data);
|
||||
bool uiman_cb_text_input (SDL_Event *event, void *data);
|
||||
|
||||
Reference in New Issue
Block a user