Files
wschod/game/src/entity/entity.c
T
2025-07-24 07:49:24 +02:00

124 lines
3.6 KiB
C

#include "entity.h"
extern SimpleMesh mesh_quad1, mesh_quad2, mesh_quad_x;
Entity *
Entity_new ()
{
Entity *e = g_new0 (Entity, 1);
e->cull_distance = 100;
e->visible = true; /* Usually are. */
e->origin = ORIGIN_BOTTOM; /* Usually is. */
return e;
}
gboolean
Entity_render (Entity *entity, vec3 camera_position, mat4 view, vec4 frustum_planes[6],
int render_distance, gboolean wireframe_enabled)
{
if (!entity->visible)
{
return FALSE;
}
/* Why an int, why int division? It's simply much faster than
floating point operations. No need to have super accurate cull
distance anyway, and might as well save a lot when rendering entities. */
unsigned int cull_dist = (render_distance * CHUNK_DIM * entity->cull_distance) / 100;
/* Underneath is the slowest (for the CPU) part of the entity render
process. Moving the camera positions from memory into some
registers. Thus the entity rendering function optimization is
finished, as the last bottleneck is the amount of entities. */
vec2 c_xz = { camera_position[0], camera_position[2] };
vec2 e_xz = { entity->position[0], entity->position[2] };
if (glm_vec2_distance2 (c_xz, e_xz) > cull_dist*cull_dist && !entity->dont_cull)
{
return FALSE;
}
vec3 aabb[2];
entity_compute_aabb (entity, aabb[0], aabb[1]);
if (!glm_aabb_frustum (aabb, frustum_planes))
{
return FALSE;
}
SimpleMesh to_render;
unsigned int render_type = entity->render_type;
switch (entity->mesh_type)
{
case MESH_QUAD_X:
to_render = mesh_quad_x;
break;
case MESH_QUAD1:
to_render = mesh_quad1;
break;
default:
to_render = mesh_quad2;
break;
}
mat4 model = GLM_MAT4_IDENTITY_INIT;
switch (render_type)
{
case RENDER_BILLBOARD:
mat4 inv_view;
glm_mat4_copy (view, inv_view);
glm_mat4_inv (inv_view, inv_view);
vec3 right = { inv_view[0][0], inv_view[1][0], inv_view[2][0] };
vec3 up = { inv_view[0][1], inv_view[1][1], inv_view[2][1] };
vec3 forward = { inv_view[0][2], inv_view[1][2], inv_view[2][2] };
mat4 rotation = GLM_MAT4_IDENTITY_INIT;
for (int i = 0; i < 3; ++i)
{
rotation[i][0] = right[i];
rotation[i][1] = up[i];
rotation[i][2] = forward[i];
}
glm_translate (model, entity->position);
glm_mat4_mul (model, rotation, model);
break;
case RENDER_BILLBOARD_Y:
/* It's not quite a "real" billboard, but the effect is much
better on the eye. */
vec3 delta;
glm_vec3_sub (camera_position, entity->position, delta);
delta[1] = 0.0;
glm_normalize (delta);
glm_rotate_at(model, entity->position, atan2f (delta[0], delta[2]), (vec3) { 0.0, 1.0, 0.0 });
glm_translate (model, entity->position);
break;
default:
glm_rotate_at (model, entity->position, glm_rad (entity->rotation[0]), (vec3) { 1.0, 0.0, 0.0 });
glm_rotate_at (model, entity->position, glm_rad (entity->rotation[1]), (vec3) { 0.0, 1.0, 0.0 });
glm_rotate_at (model, entity->position, glm_rad (entity->rotation[2]), (vec3) { 0.0, 0.0, 1.0 });
glm_translate (model, entity->position);
break;
}
if (entity->origin == ORIGIN_BOTTOM)
{
glm_translate (model, (vec3) { 0.0, entity->scale[1], 0.0 });
}
glm_scale (model, entity->scale);
program_use (entity->program);
program_set_mat4 (entity->program, "model", model);
program_set_float (entity->program, "wavy", entity->wavy);
texture_use (entity->texture, 0);
SimpleMesh_bind (&to_render);
SimpleMesh_render (&to_render, wireframe_enabled);
return TRUE;
}