diff --git a/game/Makefile b/game/Makefile index 67b93ed..b4d592c 100644 --- a/game/Makefile +++ b/game/Makefile @@ -1,7 +1,8 @@ -SRC=src/main.c src/program.c src/resources.c src/camera.c src/chunk/chunk.c \ - src/chunk/chunkmesh.c src/flags.c src/texture.c src/chunk/chunkman.c \ +SRC=src/main.c src/gl/program.c src/resources.c src/camera.c src/chunk/chunk.c \ + src/chunk/chunkmesh.c src/flags.c src/gl/texture.c src/chunk/chunkman.c \ src/event/manager.c src/event/handlers.c src/state.c src/graphics.c \ - src/entity/meshes.c src/entity/entman.c src/entity/templates.c + src/gl/mesh.c src/entity/entman.c src/entity/templates.c src/ui/uielement.c \ + src/ui/uiman.c OBJ=$(SRC:.c=.o) CFLAGS=-g -pg -Werror -Wextra -Wall `pkg-config --cflags sdl3 sdl3-image cglm gl glib-2.0` diff --git a/game/res/shaders/default.frag b/game/res/shaders/default.frag index 07bea22..d90b2ec 100644 --- a/game/res/shaders/default.frag +++ b/game/res/shaders/default.frag @@ -8,7 +8,7 @@ varying vec2 f_uv; void main () { - if(texture2D (texture, f_uv).a < 0.2) + if(texture2D (texture, f_uv).a < 0.5) { discard; } diff --git a/game/res/shaders/uielement.frag b/game/res/shaders/uielement.frag new file mode 100644 index 0000000..46b2d27 --- /dev/null +++ b/game/res/shaders/uielement.frag @@ -0,0 +1,14 @@ +#version 100 + +precision mediump float; + +uniform vec3 color; +uniform sampler2D texture; + +varying vec2 f_uv; + +void main () +{ + vec4 tex_color = texture2D (texture, f_uv); + gl_FragColor = tex_color * vec4 (color, 1.0); +} diff --git a/game/res/shaders/uielement.vert b/game/res/shaders/uielement.vert new file mode 100644 index 0000000..2601637 --- /dev/null +++ b/game/res/shaders/uielement.vert @@ -0,0 +1,31 @@ +#version 100 + +attribute vec4 position; +attribute vec2 uv; + +uniform mat4 model; +uniform float time; +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 = model * position; +} diff --git a/game/res/textures/font.png b/game/res/textures/font.png new file mode 100644 index 0000000..9dea6b7 Binary files /dev/null and b/game/res/textures/font.png differ diff --git a/game/res/textures/font.xcf b/game/res/textures/font.xcf new file mode 100644 index 0000000..7d2810d Binary files /dev/null and b/game/res/textures/font.xcf differ diff --git a/game/res/textures/grass0.png b/game/res/textures/grass0.png index b15ebef..ade5859 100644 Binary files a/game/res/textures/grass0.png and b/game/res/textures/grass0.png differ diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index 140897a..26fff30 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -106,10 +106,10 @@ chunkman_init () chunk, to save frame time. */ void -chunkman_update (vec3 camera_position) +chunkman_update (vec3 position) { int cx, cz; - chunkman_world_to_chunk (camera_position[0], camera_position[2], &cx, &cz); + chunkman_world_to_chunk (position[0], position[2], &cx, &cz); for (int z = cz - RENDER_DISTANCE - 1; z <= cz + RENDER_DISTANCE + 1; ++z) { @@ -135,10 +135,11 @@ chunkman_update (vec3 camera_position) } void -chunkman_render (vec3 camera_position, int program) +chunkman_render (vec3 position) { int cx = 0, cz = 0; - chunkman_world_to_chunk (camera_position[0], camera_position[2], &cx, &cz); + chunkman_world_to_chunk (position[0], position[2], &cx, &cz); + program_use (RESPRG ("chunk")); for (int z = cz - RENDER_DISTANCE; z <= cz + RENDER_DISTANCE; ++z) { @@ -153,7 +154,7 @@ chunkman_render (vec3 camera_position, int program) bound = true; } - program_set_vec3 (program, "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); + program_set_vec3 (RESPRG ("chunk"), "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); ChunkMesh_render (mesh); } } @@ -200,6 +201,7 @@ chunkman_generate_Chunk_at (int cx, int cz) tree->position[1] = chunk->heightmap [INDEX (x, z)]; tree->position[2] = z + zoffset; tree->rotation[1] = rand () % 180; + tree->scale[1] = (rand() % 5) + 5; ENTADD (tree); } diff --git a/game/src/chunk/chunkman.h b/game/src/chunk/chunkman.h index ac26702..4d4ecf6 100644 --- a/game/src/chunk/chunkman.h +++ b/game/src/chunk/chunkman.h @@ -5,15 +5,15 @@ #include "chunk.h" #include "chunkmesh.h" -#include "../program.h" +#include "../gl/program.h" #include "../entity/entman.h" #include "../entity/templates.h" #define RENDER_DISTANCE 4 void chunkman_init (); -void chunkman_update (vec3 camera_position); -void chunkman_render (vec3 camera_position, int program); +void chunkman_update (vec3 position); +void chunkman_render (vec3 position); float chunkman_get_height_at (float x, float z); diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index c1b0bf4..346500f 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -10,7 +10,7 @@ extern int last_time; Entity *player_entity, *sky_entity; static GSequence *entities; -static EntityMesh mesh_quad1, mesh_quad2, mesh_quad_x; +static SimpleMesh mesh_quad1, mesh_quad2, mesh_quad_x; static unsigned int last_program = -1; static unsigned int last_type = -1; static unsigned int last_texture = -1; @@ -25,9 +25,9 @@ void entman_init () { entities = g_sequence_new (NULL); - mesh_quad1 = EntityMesh_make_quad1 (); - mesh_quad2 = EntityMesh_make_quad2 (); - mesh_quad_x = EntityMesh_make_quad_x (); + mesh_quad1 = SimpleMesh_make_quad1 (); + mesh_quad2 = SimpleMesh_make_quad2 (); + mesh_quad_x = SimpleMesh_make_quad_x (); player_entity = malloc (sizeof (Entity)); *player_entity = (Entity) { @@ -111,7 +111,7 @@ entman_render_internal (gpointer data, gpointer userdata) } #endif - EntityMesh to_render; + SimpleMesh to_render; unsigned int render_type = entity->render_type; switch (entity->mesh_type) @@ -201,13 +201,13 @@ entman_render_internal (gpointer data, gpointer userdata) if (entity->mesh_type != last_type) { - EntityMesh_bind (&to_render); + SimpleMesh_bind (&to_render); } last_program = entity->program; last_type = entity->mesh_type; last_texture = entity->texture; - EntityMesh_render (&to_render); + SimpleMesh_render (&to_render); } void diff --git a/game/src/entity/entman.h b/game/src/entity/entman.h index d610247..2bd1d98 100644 --- a/game/src/entity/entman.h +++ b/game/src/entity/entman.h @@ -4,7 +4,7 @@ #include #include "entity.h" -#include "meshes.h" +#include "../gl/mesh.h" #include "../util.h" #include "../resources.h" #include "../state.h" diff --git a/game/src/entity/meshes.h b/game/src/entity/meshes.h deleted file mode 100644 index 4cd03e1..0000000 --- a/game/src/entity/meshes.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include - -#include "../flags.h" - -typedef struct EntityMesh -{ - size_t indices_len; - unsigned int pbo; - unsigned int uvbo; - unsigned int ebo; -} EntityMesh; - -void EntityMesh_bind (EntityMesh *mesh); -void EntityMesh_render (EntityMesh *mesh); -EntityMesh EntityMesh_make_quad1 (); -EntityMesh EntityMesh_make_quad2 (); -EntityMesh EntityMesh_make_quad_x (); diff --git a/game/src/event/handlers.h b/game/src/event/handlers.h index 656c304..d45bc21 100644 --- a/game/src/event/handlers.h +++ b/game/src/event/handlers.h @@ -6,7 +6,7 @@ #include "manager.h" #include "../camera.h" #include "../flags.h" -#include "../program.h" +#include "../gl/program.h" #include "../state.h" void evt_handlers_init (); diff --git a/game/src/entity/meshes.c b/game/src/gl/mesh.c similarity index 94% rename from game/src/entity/meshes.c rename to game/src/gl/mesh.c index ecb25de..22c0cd5 100644 --- a/game/src/entity/meshes.c +++ b/game/src/gl/mesh.c @@ -1,4 +1,4 @@ -#include "meshes.h" +#include "mesh.h" /* TODO: Theoretically, we could fit all the transforms into one vec4. The caveat? It would be for every vertex. There seems to be a @@ -6,7 +6,7 @@ every subsequent vertex. */ void -EntityMesh_bind (EntityMesh *mesh) +SimpleMesh_bind (SimpleMesh *mesh) { glBindBuffer (GL_ARRAY_BUFFER, mesh->pbo); glEnableVertexAttribArray (0); @@ -20,7 +20,7 @@ EntityMesh_bind (EntityMesh *mesh) } void -EntityMesh_render (EntityMesh *mesh) +SimpleMesh_render (SimpleMesh *mesh) { if (flags_get ("wireframe_enabled")) { @@ -32,8 +32,8 @@ EntityMesh_render (EntityMesh *mesh) } } -EntityMesh -EntityMesh_make_quad1 () +SimpleMesh +SimpleMesh_make_quad1 () { /* The positions are trivial. */ float positions[12] = { @@ -54,7 +54,7 @@ EntityMesh_make_quad1 () 1.0, 0.0, }; - EntityMesh mesh; + SimpleMesh mesh; mesh.indices_len = 6; glGenBuffers (1, &mesh.pbo); glGenBuffers (1, &mesh.uvbo); @@ -77,8 +77,8 @@ EntityMesh_make_quad1 () return mesh; } -EntityMesh -EntityMesh_make_quad2 () +SimpleMesh +SimpleMesh_make_quad2 () { /* The positions are trivial. */ float positions[12] = { @@ -100,7 +100,7 @@ EntityMesh_make_quad2 () 1.0, 0.0, }; - EntityMesh mesh; + SimpleMesh mesh; mesh.indices_len = 12; glGenBuffers (1, &mesh.pbo); glGenBuffers (1, &mesh.uvbo); @@ -123,8 +123,8 @@ EntityMesh_make_quad2 () return mesh; } -EntityMesh -EntityMesh_make_quad_x () +SimpleMesh +SimpleMesh_make_quad_x () { /* The positions are trivial. */ float positions[24] = { @@ -158,7 +158,7 @@ EntityMesh_make_quad_x () 1.0, 0.0 }; - EntityMesh mesh; + SimpleMesh mesh; mesh.indices_len = 24; glGenBuffers (1, &mesh.pbo); glGenBuffers (1, &mesh.uvbo); diff --git a/game/src/gl/mesh.h b/game/src/gl/mesh.h new file mode 100644 index 0000000..55bf4cc --- /dev/null +++ b/game/src/gl/mesh.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "../flags.h" + +typedef struct SimpleMesh +{ + size_t indices_len; + unsigned int pbo; + unsigned int uvbo; + unsigned int ebo; +} SimpleMesh; + +void SimpleMesh_bind (SimpleMesh *mesh); +void SimpleMesh_render (SimpleMesh *mesh); + +SimpleMesh SimpleMesh_make_quad1 (); +SimpleMesh SimpleMesh_make_quad2 (); +SimpleMesh SimpleMesh_make_quad_x (); + diff --git a/game/src/program.c b/game/src/gl/program.c similarity index 100% rename from game/src/program.c rename to game/src/gl/program.c diff --git a/game/src/program.h b/game/src/gl/program.h similarity index 96% rename from game/src/program.h rename to game/src/gl/program.h index c6a5456..4759e6c 100644 --- a/game/src/program.h +++ b/game/src/gl/program.h @@ -3,7 +3,7 @@ #include #include -#include "util.h" +#include "../util.h" /* Just for clarity sake. */ #define program_use glUseProgram diff --git a/game/src/gl/quad.c b/game/src/gl/quad.c new file mode 100644 index 0000000..e6b971c --- /dev/null +++ b/game/src/gl/quad.c @@ -0,0 +1,46 @@ +#include "quad.h" + +EntityMesh +EntityMesh_make_quad1 () +{ + /* The positions are trivial. */ + float positions[12] = { + -1.0, -1.0, 0.0, + +1.0, -1.0, 0.0, + -1.0, 1.0, 0.0, + +1.0, 1.0, 0.0 + }; + + unsigned int indices[12] = { + 3, 2, 0, 0, 1, 3, + }; + + float uvs[8] = { + 0.0, 1.0, + 1.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + }; + + EntityMesh mesh; + mesh.indices_len = 6; + glGenBuffers (1, &mesh.pbo); + glGenBuffers (1, &mesh.uvbo); + glGenBuffers (1, &mesh.ebo); + + glBindBuffer (GL_ARRAY_BUFFER, mesh.pbo); + glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 12, positions, GL_STATIC_DRAW); + glEnableVertexAttribArray (0); + glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (float) * 3, 0); + + glBindBuffer (GL_ARRAY_BUFFER, mesh.uvbo); + glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 8, uvs, GL_STATIC_DRAW); + glEnableVertexAttribArray (1); + glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, sizeof (float) * 2, 0); + + + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh.ebo); + glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int) * mesh.indices_len, indices, GL_STATIC_DRAW); + + return mesh; +} diff --git a/game/src/texture.c b/game/src/gl/texture.c similarity index 50% rename from game/src/texture.c rename to game/src/gl/texture.c index 09f91df..b60a04c 100644 --- a/game/src/texture.c +++ b/game/src/gl/texture.c @@ -11,7 +11,21 @@ texture_create (int width, int height, unsigned char *data) glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap (GL_TEXTURE_2D); - glBindTexture (GL_TEXTURE_2D, 0); + + return texture; +} + +unsigned int +texture_create_no_interp (int width, int height, unsigned char *data) +{ + unsigned int texture; + glGenTextures (1, &texture); + glBindTexture (GL_TEXTURE_2D, texture); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap (GL_TEXTURE_2D); + return texture; } diff --git a/game/src/texture.h b/game/src/gl/texture.h similarity index 59% rename from game/src/texture.h rename to game/src/gl/texture.h index 587abdd..a5beb46 100644 --- a/game/src/texture.h +++ b/game/src/gl/texture.h @@ -3,3 +3,4 @@ #include unsigned int texture_create (int width, int height, unsigned char *data); +unsigned int texture_create_no_interp (int width, int height, unsigned char *data); diff --git a/game/src/graphics.c b/game/src/graphics.c index 4cee223..6485d32 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -5,6 +5,9 @@ extern vec3 camera_position; static SDL_Window *sdl_window; static SDL_GLContext gl_context; +#define WINDOW_WIDTH 800 +#define WINDOW_HEIGHT 600 + void graphics_init () { @@ -13,7 +16,7 @@ graphics_init () FATAL ("Couldn't initialize SDL: %s", SDL_GetError ()); } - sdl_window = SDL_CreateWindow (GAME_NAME, 640, 480, SDL_WINDOW_OPENGL); + sdl_window = SDL_CreateWindow (GAME_NAME, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL); if (!sdl_window) { @@ -21,7 +24,9 @@ graphics_init () } /* We use OpenGL ES 2.0. It should support everything, and it's more - than enough for the game. */ + than enough for the game. Note that regardless of what you set, + the version returned by glGetString can differ. Doesn't + matter. */ SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); @@ -41,7 +46,7 @@ graphics_init () INFO ("GLSL version: %s", glGetString (GL_SHADING_LANGUAGE_VERSION)); INFO ("Max vertex attributes: %d", GL_MAX_VERTEX_ATTRIBS); - glViewport (0, 0, 640, 480); + glViewport (0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); glClearColor (0, 0.3, 0.8, 1); glEnable (GL_CULL_FACE); @@ -54,12 +59,11 @@ graphics_render () glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mat4 projection, view; - camera_get_projection (640.0 / 480.0, projection); + camera_get_projection (WINDOW_WIDTH / WINDOW_HEIGHT, projection); camera_get_view (view); - program_use (RESPRG ("chunk")); - program_set_mat4 (RESPRG ("chunk"), "projection", projection); - program_set_mat4 (RESPRG ("chunk"), "view", view); + resources_programs_set_projection (projection); + resources_programs_set_view (view); glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain0")); @@ -72,16 +76,13 @@ graphics_render () glActiveTexture (GL_TEXTURE4); glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain4")); - chunkman_render (camera_position, RESPRG ("chunk")); - - program_use (RESPRG ("clouds")); - program_set_mat4 (RESPRG ("clouds"), "projection", projection); - program_set_mat4 (RESPRG ("clouds"), "view", view); - program_use (RESPRG ("default")); - program_set_mat4 (RESPRG ("default"), "projection", projection); - program_set_mat4 (RESPRG ("default"), "view", view); + chunkman_render (camera_position); entman_render (view); + glDisable (GL_DEPTH_TEST); + uiman_render (); + glEnable (GL_DEPTH_TEST); + SDL_GL_SwapWindow (sdl_window); } diff --git a/game/src/graphics.h b/game/src/graphics.h index 4ff3a70..40c61b2 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -3,11 +3,12 @@ #include #include -#include "util.h" +#include "ui/uiman.h" #include "chunk/chunkman.h" #include "entity/entman.h" #include "state.h" #include "resources.h" +#include "util.h" void graphics_init (); void graphics_render (); diff --git a/game/src/main.c b/game/src/main.c index e08a691..e4aecfb 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -7,6 +7,7 @@ #include "event/handlers.h" #include "chunk/chunkman.h" #include "entity/templates.h" +#include "ui/uiman.h" #include "state.h" #include "resources.h" #include "graphics.h" @@ -22,6 +23,7 @@ SDL_AppInit (void **appstate, int argc, char **argv) graphics_init (); evt_handlers_init (); resources_init (); + uiman_init (); chunkman_init (); entman_init (); ent_templates_init (); diff --git a/game/src/resources.c b/game/src/resources.c index 9d4842d..c99236e 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -55,6 +55,21 @@ resources_load_texture (const char *path) return texture; } +unsigned int +resources_load_texture_no_interp (const char *path) +{ + SDL_Surface *surface = IMG_Load (path); + + if (surface == NULL) + { + WARN ("Failed to load texture from path %s: %s", path, SDL_GetError ()); + return 0; + } + + unsigned int texture = texture_create_no_interp (surface->w, surface->h, surface->pixels); + return texture; +} + static inline void resources_add_program (char *key, unsigned int program) { @@ -85,6 +100,38 @@ resources_get_texture (char *key) return GPOINTER_TO_INT (g_hash_table_lookup (textures, key)); } +void +res_proj_internal (gpointer key, gpointer value, gpointer userdata) +{ + UNUSED (key); + unsigned int program = GPOINTER_TO_INT (value); + mat4 *projection = userdata; + program_use (program); + program_set_mat4 (program, "projection", *projection); +} + +void +res_view_internal (gpointer key, gpointer value, gpointer userdata) +{ + UNUSED (key); + unsigned int program = GPOINTER_TO_INT (value); + mat4 *view = userdata; + program_use (program); + program_set_mat4 (program, "view", *view); +} + +void +resources_programs_set_projection (mat4 projection) +{ + g_hash_table_foreach (programs, res_proj_internal, projection); +} + +void +resources_programs_set_view (mat4 view) +{ + g_hash_table_foreach (programs, res_view_internal, view); +} + void resources_init () { @@ -95,19 +142,23 @@ resources_init () #define RLP resources_load_program #define RAT resources_add_texture #define RLT resources_load_texture + #define RLTNI resources_load_texture_no_interp - 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 ("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")); - RAT ("terrain0", RLT ("res/textures/dirt.png")); - RAT ("terrain1", RLT ("res/textures/drygrass.png")); - RAT ("terrain2", RLT ("res/textures/grass.png")); - RAT ("terrain3", RLT ("res/textures/rock_cement.png")); - RAT ("terrain4", RLT ("res/textures/asphalt_gravel.png")); - RAT ("tree0", RLT ("res/textures/tree.png")); - RAT ("grass0", RLT ("res/textures/grass0.png")); - RAT ("clouds", RLT ("res/textures/clouds.png")); + RAT ("terrain0", RLT ("res/textures/dirt.png")); + RAT ("terrain1", RLT ("res/textures/drygrass.png")); + RAT ("terrain2", RLT ("res/textures/grass.png")); + RAT ("terrain3", RLT ("res/textures/rock_cement.png")); + RAT ("terrain4", RLT ("res/textures/asphalt_gravel.png")); + RAT ("tree0", RLT ("res/textures/tree.png")); + RAT ("grass0", RLT ("res/textures/grass0.png")); + RAT ("clouds", RLT ("res/textures/clouds.png")); + + RAT ("font0", RLTNI ("res/textures/font.png")); #undef RAP #undef RLP diff --git a/game/src/resources.h b/game/src/resources.h index 17c9fe9..8cd0634 100644 --- a/game/src/resources.h +++ b/game/src/resources.h @@ -2,13 +2,16 @@ #include #include +#include -#include "program.h" -#include "texture.h" +#include "gl/program.h" +#include "gl/texture.h" #define RESPRG(key) (resources_get_program (key)) #define RESTEX(key) (resources_get_texture (key)) +void resources_programs_set_projection (mat4 projection); +void resources_programs_set_view (mat4 view); unsigned int resources_get_program (char *key); unsigned int resources_get_texture (char *key); void resources_init (); diff --git a/game/src/state.c b/game/src/state.c index c77a7e6..3ceac97 100644 --- a/game/src/state.c +++ b/game/src/state.c @@ -1,7 +1,9 @@ #include "state.h" extern vec3 camera_position; +extern vec3 camera_rotation; extern Entity *player_entity, *sky_entity; +extern UIElement *player_pos; float delta_time; int last_time; @@ -21,8 +23,16 @@ game_state_tick (int ticks) glm_vec3_copy (player_entity->position, camera_position); camera_position[1] += player_entity->scale[1] - 0.2; + player_entity->rotation[1] = camera_rotation[1]; sky_entity->position[0] = camera_position[0]; sky_entity->position[2] = camera_position[2]; + + /* Put the player position into the UI. */ + char *buf = malloc (sizeof (char) * 32); + snprintf (buf, 32, "X:%2.1f Y:%2.1f Z:%2.1f", player_entity->position[0], + player_entity->position[1], player_entity->position[2]); + player_pos->text = buf; + if (flags_get ("moving_forward")) { diff --git a/game/src/state.h b/game/src/state.h index a3919a6..8f94fa0 100644 --- a/game/src/state.h +++ b/game/src/state.h @@ -3,6 +3,7 @@ #include "camera.h" #include "flags.h" #include "entity/entity.h" +#include "ui/uielement.h" void game_state_init (int ticks); void game_state_tick (int ticks); diff --git a/game/src/ui/uielement.c b/game/src/ui/uielement.c new file mode 100644 index 0000000..b9bcbb2 --- /dev/null +++ b/game/src/ui/uielement.c @@ -0,0 +1,83 @@ +#include "uielement.h" + +/* TODO: Convert to mat3's and 2D affine transformations. */ + +static SimpleMesh quad; + +void +ui_element_mesh_init () +{ + quad = SimpleMesh_make_quad1 (); +} + +void +UIElement_add_child (UIElement *parent, UIElement *child) +{ + g_sequence_append (parent->children, child); +} + +void +uiel_render_internal (gpointer data, gpointer userdata) +{ + UNUSED (userdata); + UIElement *element = data; + UIElement_render (element); +} + +void +UIElement_render (UIElement *element) +{ + if (element->parent == NULL) + { + SimpleMesh_bind (&quad); + program_use (RESPRG ("uielement")); + } + + if (element->visible) + { + /* First, we render the background as a quad of + `background_color'. */ + 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); + /* TODO: rename this function to vec3_individual or + something. */ + program_set_vec3 (RESPRG ("uielement"), "color", + element->background_color[0], element->background_color[1], + element->background_color[2]); + 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[0], element->text_color[1], + element->text_color[2]); + + for (size_t i = 0; i < strlen (element->text); ++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[i]); + SimpleMesh_render (&quad); + } + } + + if (element->children != NULL) + { + g_sequence_foreach (element->children, uiel_render_internal, NULL); + } +} diff --git a/game/src/ui/uielement.h b/game/src/ui/uielement.h new file mode 100644 index 0000000..671ccb3 --- /dev/null +++ b/game/src/ui/uielement.h @@ -0,0 +1,34 @@ +#pragma once + +/* TODO: Patch up with GLib's GTree */ + +#include + +#include +#include + +#include "../util.h" +#include "../resources.h" +#include "../gl/mesh.h" +#include "../gl/program.h" + +typedef struct UIElement +{ + struct UIElement *parent; + GSequence *children; + + void (*on_left_click) (struct UIElement *self); + void (*on_right_click) (struct UIElement *self); + + bool visible; + vec3 text_color; + vec3 background_color; + + vec3 position; + vec3 scale; + char *text; /* Maybe switch to GString? */ +} UIElement; + +void ui_element_mesh_init (); +void UIElement_render (UIElement *element); +void UIElement_add_child (UIElement *parent, UIElement *child); diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c new file mode 100644 index 0000000..0023752 --- /dev/null +++ b/game/src/ui/uiman.c @@ -0,0 +1,37 @@ +#include "uiman.h" + +UIElement *player_pos; + +static UIElement ui_root; + +void +uiman_init () +{ + ui_root = (UIElement) { + .parent = NULL, + .children = g_sequence_new (NULL), + .visible = false, + }; + + player_pos = malloc (sizeof (UIElement)); + *player_pos = (UIElement) { + .parent = &ui_root, + .children = NULL, + .visible = true, + .background_color = { 0.0, 0.0, 0.0 }, + .text_color = { 1.0, 1.0, 1.0 }, + .position = { -0.65, 0.92, 0.0 }, + .scale = { 0.3, 0.03, 1.0 }, + .text = "POSITION: 0,0,0" + }; + + UIElement_add_child (&ui_root, player_pos); + + ui_element_mesh_init (); +} + +void +uiman_render () +{ + UIElement_render (&ui_root); +} diff --git a/game/src/ui/uiman.h b/game/src/ui/uiman.h new file mode 100644 index 0000000..af4b179 --- /dev/null +++ b/game/src/ui/uiman.h @@ -0,0 +1,6 @@ +#pragma once + +#include "uielement.h" + +void uiman_init (); +void uiman_render ();