Potentially speed up entity rendering?

This commit is contained in:
2025-06-05 21:42:14 +02:00
parent 63af50742d
commit 6399b355bc
18 changed files with 158 additions and 145 deletions
+1 -2
View File
@@ -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);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.
+25 -6
View File
@@ -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++;
}
}
}
+1 -1
View File
@@ -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);
+35 -42
View File
@@ -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;
}
+7 -1
View File
@@ -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);
}
+2 -1
View File
@@ -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);
-15
View File
@@ -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;
}
-1
View File
@@ -3,4 +3,3 @@
#include <SDL3/SDL_opengles2.h>
unsigned int texture_create (int width, int height, unsigned char *data);
unsigned int texture_create_no_interp (int width, int height, unsigned char *data);
+10 -14
View File
@@ -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);
}
+31 -27
View File
@@ -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
+2 -2
View File
@@ -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 ();
+15 -5
View File
@@ -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"))
{
+2 -1
View File
@@ -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);
+2 -6
View File
@@ -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)
{
+2 -2
View File
@@ -1,7 +1,5 @@
#pragma once
/* TODO: Patch up with GLib's GTree */
#include <stdbool.h>
#include <glib-2.0/glib.h>
@@ -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;
+23 -19
View File
@@ -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