diff --git a/game/res/shaders/uielement.frag b/game/res/shaders/uielement.frag index 02c951d..e713d5d 100644 --- a/game/res/shaders/uielement.frag +++ b/game/res/shaders/uielement.frag @@ -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); } diff --git a/game/res/shaders/uielement.vert b/game/res/shaders/uielement.vert index 2601637..e3a1281 100644 --- a/game/res/shaders/uielement.vert +++ b/game/res/shaders/uielement.vert @@ -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); } diff --git a/game/res/shaders/uitext.frag b/game/res/shaders/uitext.frag new file mode 100644 index 0000000..c2262a7 --- /dev/null +++ b/game/res/shaders/uitext.frag @@ -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); +} diff --git a/game/res/shaders/uitext.vert b/game/res/shaders/uitext.vert new file mode 100644 index 0000000..e6d8332 --- /dev/null +++ b/game/res/shaders/uitext.vert @@ -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); +} diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index b8b6bb8..f6a8885 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -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; + } + } } } diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index 8d695be..0c8955c 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -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]); diff --git a/game/src/event/evtman.c b/game/src/event/evtman.c index bb878c8..58aaccb 100644 --- a/game/src/event/evtman.c +++ b/game/src/event/evtman.c @@ -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; } diff --git a/game/src/event/evtman.h b/game/src/event/evtman.h index 76d1fb5..c96eaa2 100644 --- a/game/src/event/evtman.h +++ b/game/src/event/evtman.h @@ -7,6 +7,7 @@ #include "handler.h" #include "../flags.h" #include "../util.h" +#include "../ui/uiman.h" void evtman_init (); diff --git a/game/src/flags.c b/game/src/flags.c index 2e08392..1b42cbc 100644 --- a/game/src/flags.c +++ b/game/src/flags.c @@ -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) { diff --git a/game/src/flags.h b/game/src/flags.h index f23136e..d56c754 100644 --- a/game/src/flags.h +++ b/game/src/flags.h @@ -4,6 +4,22 @@ #include +/* + + 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); diff --git a/game/src/gl/program.c b/game/src/gl/program.c index 2d35e3b..31f45c2 100644 --- a/game/src/gl/program.c +++ b/game/src/gl/program.c @@ -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) { diff --git a/game/src/gl/program.h b/game/src/gl/program.h index 3d49ae9..f05c42a 100644 --- a/game/src/gl/program.h +++ b/game/src/gl/program.h @@ -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); diff --git a/game/src/graphics.c b/game/src/graphics.c index a1eedd3..97b72b7 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -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 diff --git a/game/src/main.c b/game/src/main.c index 5591e90..7a937e7 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -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; diff --git a/game/src/resources.c b/game/src/resources.c index b70495c..862f83c 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -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")); diff --git a/game/src/state.c b/game/src/state.c index f1f0437..64628ca 100644 --- a/game/src/state.c +++ b/game/src/state.c @@ -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")) { diff --git a/game/src/ui/uielement.c b/game/src/ui/uielement.c index 24f4623..da46871 100644 --- a/game/src/ui/uielement.c +++ b/game/src/ui/uielement.c @@ -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); +} diff --git a/game/src/ui/uielement.h b/game/src/ui/uielement.h index 6f8efcf..c9f08bf 100644 --- a/game/src/ui/uielement.h +++ b/game/src/ui/uielement.h @@ -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); diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index e64e2a0..aa2adc6 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -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; } diff --git a/game/src/ui/uiman.h b/game/src/ui/uiman.h index af4b179..0617d2d 100644 --- a/game/src/ui/uiman.h +++ b/game/src/ui/uiman.h @@ -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);