diff --git a/game/res/shaders/uielement.frag b/game/res/shaders/uielement.frag index 46b2d27..02c951d 100644 --- a/game/res/shaders/uielement.frag +++ b/game/res/shaders/uielement.frag @@ -9,6 +9,5 @@ varying vec2 f_uv; void main () { - vec4 tex_color = texture2D (texture, f_uv); - gl_FragColor = tex_color * vec4 (color, 1.0); + gl_FragColor = texture2D (texture, f_uv) * vec4 (color, 1.0); } diff --git a/game/res/textures/font.png b/game/res/textures/font.png index 9dea6b7..538cdf5 100644 Binary files a/game/res/textures/font.png and b/game/res/textures/font.png differ diff --git a/game/res/textures/font.xcf b/game/res/textures/font.xcf index 7d2810d..32430c6 100644 Binary files a/game/res/textures/font.xcf and b/game/res/textures/font.xcf differ diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index 26fff30..20e8de6 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -3,6 +3,8 @@ /* TODO: perhaps render the chunks in a circle, not a square, around the player? */ +int n_frame_chunks; + static GHashTable *chunks; static GHashTable *chunk_meshes; @@ -11,16 +13,19 @@ static bool bound = false; guint chunkman_ivec2_hash (gconstpointer key) { + /* This makes sure there's no collisions, thus making the whole + table much, much faster. */ const ivec2 *v = key; - return g_int_hash(&(*v)[0]) ^ g_int_hash(&(*v)[1]); + guint x = (guint) (*v)[0]; + guint y = (guint) (*v)[1]; + return (x * 73856093u) ^ (y * 19349663u); } gboolean chunkman_ivec2_equal (gconstpointer a, gconstpointer b) { - const ivec2 *av = a; - const ivec2 *bv = b; - return (*av)[0] == (*bv)[0] && (*av)[1] == (*bv)[1]; + /* Much faster than comparing the integer values. */ + return memcmp (a, b, sizeof (int) * 2) == 0; } ivec2 * @@ -141,6 +146,19 @@ chunkman_render (vec3 position) chunkman_world_to_chunk (position[0], position[2], &cx, &cz); program_use (RESPRG ("chunk")); + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain0")); + glActiveTexture (GL_TEXTURE1); + glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain1")); + glActiveTexture (GL_TEXTURE2); + glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain2")); + glActiveTexture (GL_TEXTURE3); + glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain3")); + glActiveTexture (GL_TEXTURE4); + glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain4")); + + n_frame_chunks = 0; + for (int z = cz - RENDER_DISTANCE; z <= cz + RENDER_DISTANCE; ++z) { for (int x = cx - RENDER_DISTANCE; x <= cx + RENDER_DISTANCE; ++x) @@ -154,8 +172,9 @@ chunkman_render (vec3 position) bound = true; } - program_set_vec3 (RESPRG ("chunk"), "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); - ChunkMesh_render (mesh); + program_set_vec3_ind (RESPRG ("chunk"), "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); + ChunkMesh_render (mesh); + n_frame_chunks++; } } } diff --git a/game/src/chunk/chunkman.h b/game/src/chunk/chunkman.h index 4d4ecf6..1fcb6c3 100644 --- a/game/src/chunk/chunkman.h +++ b/game/src/chunk/chunkman.h @@ -9,7 +9,7 @@ #include "../entity/entman.h" #include "../entity/templates.h" -#define RENDER_DISTANCE 4 +#define RENDER_DISTANCE 3 void chunkman_init (); void chunkman_update (vec3 position); diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index 346500f..7b94851 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -5,9 +5,9 @@ seperately somehow. */ extern vec3 camera_position; -extern int last_time; Entity *player_entity, *sky_entity; +int n_frame_ents; static GSequence *entities; static SimpleMesh mesh_quad1, mesh_quad2, mesh_quad_x; @@ -78,7 +78,13 @@ void entman_render_internal (gpointer data, gpointer userdata) { Entity *entity = data; - mat4 *view = userdata; + + struct { + mat4 *view; +#ifdef FRUSTUM_CULL + vec4 *frustum_planes[6]; +#endif + } *vp = userdata; if (!entity->visible) { @@ -90,22 +96,15 @@ entman_render_internal (gpointer data, gpointer userdata) { return; } - + /* TODO: Fix this up. It still isn't perfect, when you look up, sometimes the entities get culled. */ #if FRUSTUM_CULL - vec4 planes[6]; - mat4 proj, view_proj; - - camera_get_projection (640.0 / 480.0, proj); - glm_mat4_mul (proj, *view, view_proj); - glm_frustum_planes (view_proj, planes); - vec3 aabb[2]; entity_compute_aabb (entity, aabb[0], aabb[1]); - if (!glm_aabb_frustum (aabb, planes)) + if (!glm_aabb_frustum (aabb, *vp->frustum_planes)) { return; } @@ -133,7 +132,7 @@ entman_render_internal (gpointer data, gpointer userdata) { case RENDER_BILLBOARD: mat4 inv_view; - glm_mat4_copy (*view, inv_view); + glm_mat4_copy (*vp->view, inv_view); glm_mat4_inv (inv_view, inv_view); vec3 right = { inv_view[0][0], inv_view[1][0], inv_view[2][0] }; @@ -182,16 +181,7 @@ entman_render_internal (gpointer data, gpointer userdata) } program_set_mat4 (entity->program, "model", model); - program_set_float (entity->program, "time", last_time); - - if (entity->wavy) - { - program_set_float (entity->program, "wavy", true); - } - else - { - program_set_float (entity->program, "wavy", false); - } + program_set_float (entity->program, "wavy", entity->wavy); if (entity->texture != last_texture) { @@ -208,12 +198,33 @@ entman_render_internal (gpointer data, gpointer userdata) last_type = entity->mesh_type; last_texture = entity->texture; SimpleMesh_render (&to_render); + + n_frame_ents++; } void -entman_render (mat4 view) +entman_render (mat4 *view, mat4 *proj) { - g_sequence_foreach (entities, entman_render_internal, view); + last_program = -1; + last_texture = -1; + last_type = -1; + n_frame_ents = 0; + +#ifdef FRUSTUM_CULL + vec4 planes[6]; + mat4 view_proj; + glm_mat4_mul (*proj, *view, view_proj); + glm_frustum_planes (view_proj, planes); +#endif + + struct { + mat4 *view; +#ifdef FRUSTUM_CULL + vec4 *frustum_planes; +#endif + } data = { view, planes }; + + g_sequence_foreach (entities, entman_render_internal, &data); } static inline int @@ -225,24 +236,6 @@ entman_compare (gconstpointer a, gconstpointer b, gpointer userdata) const Entity *entity1 = a; const Entity *entity2 = b; - if (entity1->mesh_type == entity2->mesh_type) - { - return 0; - } - - // Handle MESH_QUAD1 - if (entity1->mesh_type == MESH_QUAD1) - return -1; - if (entity2->mesh_type == MESH_QUAD1) - return 1; - - // Handle MESH_QUAD_X vs MESH_QUAD2 - if (entity1->mesh_type == MESH_QUAD_X && entity2->mesh_type == MESH_QUAD2) - return -1; - if (entity1->mesh_type == MESH_QUAD2 && entity2->mesh_type == MESH_QUAD_X) - return 1; - - // Default: compare numerically return (int) entity1->mesh_type - (int) entity2->mesh_type; } diff --git a/game/src/gl/program.c b/game/src/gl/program.c index 9121cb8..2d35e3b 100644 --- a/game/src/gl/program.c +++ b/game/src/gl/program.c @@ -73,7 +73,13 @@ program_create (const char *v_src, const char *f_src) } void -program_set_vec3 (int program, const char *name, float x, float y, float z) +program_set_vec3 (int program, const char *name, vec3 value) +{ + glUniform3f (glGetUniformLocation (program, name), value[0], value[1], value[2]); +} + +void +program_set_vec3_ind (int program, const char *name, float x, float y, float z) { glUniform3f (glGetUniformLocation (program, name), x, y, z); } diff --git a/game/src/gl/program.h b/game/src/gl/program.h index 4759e6c..3d49ae9 100644 --- a/game/src/gl/program.h +++ b/game/src/gl/program.h @@ -13,6 +13,7 @@ void program_fail (int program); int program_create (const char *v_src, const char *f_src); 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, float x, float y, float z); +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_mat4 (int program, const char *name, mat4 value); void program_print (int program); diff --git a/game/src/gl/texture.c b/game/src/gl/texture.c index b60a04c..efeedaf 100644 --- a/game/src/gl/texture.c +++ b/game/src/gl/texture.c @@ -14,18 +14,3 @@ texture_create (int width, int height, unsigned char *data) 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/gl/texture.h b/game/src/gl/texture.h index a5beb46..587abdd 100644 --- a/game/src/gl/texture.h +++ b/game/src/gl/texture.h @@ -3,4 +3,3 @@ #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 6485d32..1a06827 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -1,6 +1,7 @@ #include "graphics.h" extern vec3 camera_position; +extern int last_time; static SDL_Window *sdl_window; static SDL_GLContext gl_context; @@ -51,6 +52,8 @@ graphics_init () glEnable (GL_CULL_FACE); glEnable (GL_DEPTH_TEST); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); } void @@ -62,26 +65,19 @@ graphics_render () camera_get_projection (WINDOW_WIDTH / WINDOW_HEIGHT, projection); camera_get_view (view); - resources_programs_set_projection (projection); - resources_programs_set_view (view); - - glActiveTexture (GL_TEXTURE0); - glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain0")); - glActiveTexture (GL_TEXTURE1); - glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain1")); - glActiveTexture (GL_TEXTURE2); - glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain2")); - glActiveTexture (GL_TEXTURE3); - glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain3")); - glActiveTexture (GL_TEXTURE4); - glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain4")); + resources_programs_set_mat4 ("projection", &projection); + resources_programs_set_mat4 ("view", &view); + resources_programs_set_float ("time", last_time); chunkman_render (camera_position); - entman_render (view); + entman_render (view, projection); + /* We don't care about blending elsewhere for now. */ + glEnable (GL_BLEND); glDisable (GL_DEPTH_TEST); uiman_render (); glEnable (GL_DEPTH_TEST); + glDisable (GL_BLEND); SDL_GL_SwapWindow (sdl_window); } diff --git a/game/src/resources.c b/game/src/resources.c index c99236e..8782c26 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -55,21 +55,6 @@ 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) { @@ -101,35 +86,55 @@ resources_get_texture (char *key) } void -res_proj_internal (gpointer key, gpointer value, gpointer userdata) +res_mat4_internal (gpointer key, gpointer value, gpointer userdata) { UNUSED (key); unsigned int program = GPOINTER_TO_INT (value); - mat4 *projection = userdata; + + struct { + const char *name; + mat4 *mat; + } *data = userdata; + program_use (program); - program_set_mat4 (program, "projection", *projection); + program_set_mat4 (program, data->name, *data->mat); } void -res_view_internal (gpointer key, gpointer value, gpointer userdata) +res_float_internal (gpointer key, gpointer value, gpointer userdata) { UNUSED (key); unsigned int program = GPOINTER_TO_INT (value); - mat4 *view = userdata; + + struct { + const char *name; + float val; + } *data = userdata; + program_use (program); - program_set_mat4 (program, "view", *view); + program_set_float (program, data->name, data->val); } void -resources_programs_set_projection (mat4 projection) +resources_programs_set_float (const char *name, float value) { - g_hash_table_foreach (programs, res_proj_internal, projection); + struct { + const char *name; + float val; + } data = { name, value }; + + g_hash_table_foreach (programs, res_float_internal, &data); } void -resources_programs_set_view (mat4 view) +resources_programs_set_mat4 (const char *name, mat4 *value) { - g_hash_table_foreach (programs, res_view_internal, view); + struct { + const char *name; + mat4 *mat; + } data = { name, value }; + + g_hash_table_foreach (programs, res_mat4_internal, &data); } void @@ -142,7 +147,6 @@ 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")); @@ -158,7 +162,7 @@ resources_init () RAT ("grass0", RLT ("res/textures/grass0.png")); RAT ("clouds", RLT ("res/textures/clouds.png")); - RAT ("font0", RLTNI ("res/textures/font.png")); + RAT ("font0", RLT ("res/textures/font.png")); #undef RAP #undef RLP diff --git a/game/src/resources.h b/game/src/resources.h index 8cd0634..4516815 100644 --- a/game/src/resources.h +++ b/game/src/resources.h @@ -10,8 +10,8 @@ #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); +void resources_programs_set_float (const char *name, float value); +void resources_programs_set_mat4 (const char *name, mat4 *mat); 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 3ceac97..dc49185 100644 --- a/game/src/state.c +++ b/game/src/state.c @@ -3,7 +3,8 @@ extern vec3 camera_position; extern vec3 camera_rotation; extern Entity *player_entity, *sky_entity; -extern UIElement *player_pos; +extern UIElement *player_pos, *n_ents, *n_chunks; +extern int n_frame_ents, n_frame_chunks; float delta_time; int last_time; @@ -21,18 +22,27 @@ game_state_tick (int ticks) delta_time = (ticks - last_time) / 1000.0; last_time = ticks; + /* We pin the camera to the player position, with eye level 20 + centimeters below the height. */ glm_vec3_copy (player_entity->position, camera_position); camera_position[1] += player_entity->scale[1] - 0.2; player_entity->rotation[1] = camera_rotation[1]; + /* The sky needs to be in the center of the world all the time, + otherwise, as we explore the world, we might reach the end of the + sky. */ 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_pos->text = malloc (sizeof (char) * 32); + snprintf (player_pos->text, 32, "position 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; - + /* Put the amount of entities rendered into the UI. */ + n_ents->text = malloc (sizeof (char) * 32); + snprintf (n_ents->text, 32, "entities rendered: %d", n_frame_ents); + /* Put the amount of chunks rendered into the UI. */ + n_chunks->text = malloc (sizeof (char) * 32); + snprintf (n_chunks->text, 32, "chunks rendered: %d", n_frame_chunks); if (flags_get ("moving_forward")) { diff --git a/game/src/state.h b/game/src/state.h index 8f94fa0..d3fe675 100644 --- a/game/src/state.h +++ b/game/src/state.h @@ -2,7 +2,8 @@ #include "camera.h" #include "flags.h" -#include "entity/entity.h" +#include "chunk/chunkman.h" +#include "entity/entman.h" #include "ui/uielement.h" void game_state_init (int ticks); diff --git a/game/src/ui/uielement.c b/game/src/ui/uielement.c index b9bcbb2..18ce98b 100644 --- a/game/src/ui/uielement.c +++ b/game/src/ui/uielement.c @@ -47,18 +47,14 @@ UIElement_render (UIElement *element) 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]); + 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[0], element->text_color[1], - element->text_color[2]); + program_set_vec3 (RESPRG ("uielement"), "color", element->text_color); for (size_t i = 0; i < strlen (element->text); ++i) { diff --git a/game/src/ui/uielement.h b/game/src/ui/uielement.h index 671ccb3..9d20106 100644 --- a/game/src/ui/uielement.h +++ b/game/src/ui/uielement.h @@ -1,7 +1,5 @@ #pragma once -/* TODO: Patch up with GLib's GTree */ - #include #include @@ -19,6 +17,8 @@ typedef struct UIElement void (*on_left_click) (struct UIElement *self); void (*on_right_click) (struct UIElement *self); + void (*on_tick) (struct UIElement *self); + void *userdata; bool visible; vec3 text_color; diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index 0023752..ea839d3 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -1,33 +1,37 @@ #include "uiman.h" -UIElement *player_pos; +UIElement *player_pos, *n_ents, *n_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 }) +#define UIADD(pare, child) (UIElement_add_child (pare, child)) + void uiman_init () { - ui_root = (UIElement) { - .parent = NULL, - .children = g_sequence_new (NULL), - .visible = false, - }; + ui_element_mesh_init (); + ui_root = UINEWROOT (); 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); + *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_element_mesh_init (); + 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); + + 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); } void