124 lines
3.6 KiB
C
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;
|
|
}
|