490 lines
14 KiB
C
490 lines
14 KiB
C
enum {MAX_COINS_VISIBLE = 30};
|
|
|
|
void
|
|
render_geo(void)
|
|
{
|
|
data_t* data = &g_game->data;
|
|
state_t* state = &g_game->state;
|
|
|
|
render_geo_begin(&state->camera);
|
|
|
|
struct {
|
|
vec3 position;
|
|
vec3 color;
|
|
float intensity;
|
|
} light;
|
|
|
|
// Determine which coins are near the camera
|
|
int coin_count = 0;
|
|
transform_t coins[MAX_COINS_VISIBLE] = {0};
|
|
|
|
for (int i = 0; i < state->coin_count; i++)
|
|
{
|
|
transform_t coin = state->coins[i];
|
|
|
|
vec3 heading = vec3_normalize(vec3_sub(coin.position, state->camera.position));
|
|
float dot = vec3_dot(heading, state->camera.front);
|
|
|
|
// Only check coins that are in front of us
|
|
if (dot > 0.0f)
|
|
{
|
|
ray_t ray = {
|
|
.origin = state->camera.position,
|
|
.direction = heading};
|
|
|
|
bool coin_obscured = false;
|
|
|
|
for (size_t j = 0; j < data->wall_count; j++)
|
|
{
|
|
aabb_t aabb = data->walls[j];
|
|
aabb.extents.x *= 0.80f;
|
|
aabb.extents.y *= 0.80f;
|
|
|
|
float coin_distance = vec3_length(vec3_sub(state->camera.position, coin.position));
|
|
|
|
float wall_distance = vec3_length(vec3_sub(state->camera.position, aabb.origin));
|
|
|
|
if (coin_distance > wall_distance)
|
|
{
|
|
if (ray_aabb_intersect(aabb, ray))
|
|
{
|
|
coin_obscured = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!coin_obscured){
|
|
coins[coin_count++] = state->coins[i];
|
|
}
|
|
}
|
|
|
|
LOG_ASSERT(coin_count <= MAX_COINS_VISIBLE, "More coins visible than rendered");
|
|
}
|
|
|
|
transform_t* rendered_coins;
|
|
if (state->powerup_timer > 0.0f)
|
|
{
|
|
rendered_coins = state->coins;
|
|
coin_count = state->coin_count;
|
|
glUniform1i(g_render_mgr->geo.u_light_count, 0);
|
|
}
|
|
else
|
|
{
|
|
rendered_coins = coins;
|
|
glUniform1i(g_render_mgr->geo.u_light_count, coin_count);
|
|
}
|
|
|
|
// Render the visble lit coins
|
|
{
|
|
mesh_t* coin = (mesh_t*)get_mesh_by_name("M_Coin");
|
|
material_t* material = (material_t*)get_material_by_handle(coin->material);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 1);
|
|
glUniform1f(g_render_mgr->geo.u_ambient_adjust, 0.75f);
|
|
light.color = (vec3){1.0f, 0.7f, 0.0f};
|
|
light.intensity = 1.0f;
|
|
|
|
float sine = sinf(state->time);
|
|
float cosine = cosf(state->time);
|
|
float sine_rate_light = sine / 8.0f;
|
|
float sine_rate_mesh = sine / 16.0f;
|
|
|
|
mat4 rotation = mat4_identity();
|
|
rotation.e00 = cosine;
|
|
rotation.e01 = -sine;
|
|
rotation.e10 = sine;
|
|
rotation.e11 = cosine;
|
|
|
|
mat4 translation = mat4_identity();
|
|
glBindVertexArray(coin->vao);
|
|
for (int i = 0; i < coin_count; i++)
|
|
{
|
|
char buf[30];
|
|
GLuint u_light_position;
|
|
{
|
|
snprintf(buf, sizeof(buf), "u_lights[%d].position", i);
|
|
u_light_position = glGetUniformLocation(g_render_mgr->geo.shader, buf);
|
|
}
|
|
|
|
GLuint u_light_color;
|
|
{
|
|
snprintf(buf, sizeof(buf), "u_lights[%d].color", i);
|
|
u_light_color = glGetUniformLocation(g_render_mgr->geo.shader, buf);
|
|
}
|
|
|
|
GLuint u_light_intensity;
|
|
{
|
|
snprintf(buf, sizeof(buf), "u_lights[%d].intensity", i);
|
|
u_light_intensity = glGetUniformLocation(g_render_mgr->geo.shader, buf);
|
|
}
|
|
|
|
light.position = (vec3){rendered_coins[i].position.x, rendered_coins[i].position.y, 0.25f + sine_rate_light};
|
|
|
|
glUniform3fv(u_light_position, 1, (float*)&light.position);
|
|
glUniform3fv(u_light_color, 1, (float*)&light.color);
|
|
glUniform1f(u_light_intensity, light.intensity);
|
|
|
|
translation.e03 = rendered_coins[i].position.x;
|
|
translation.e13 = rendered_coins[i].position.y;
|
|
translation.e23 = rendered_coins[i].position.z + sine_rate_mesh;
|
|
|
|
mat4 model_mat = mat4_multm(translation, rotation);
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, coin->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 0);
|
|
}
|
|
|
|
// Render skybox
|
|
{
|
|
mesh_t* mesh = (mesh_t*)get_mesh_by_name("M_Skybox");
|
|
material_t* material = (material_t*)get_material_by_handle(mesh->material);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 1);
|
|
glUniform1f(g_render_mgr->geo.u_ambient_adjust, 0.01f);
|
|
|
|
state->skybox_offset.x += 0.0002f;
|
|
if (state->skybox_offset.x >= 1.0f) { state->skybox_offset.x = 0.0f; };
|
|
|
|
glUniform2fv(g_render_mgr->geo.u_uv_translation, 1, (float*)&state->skybox_offset);
|
|
|
|
mat4 model_mat = mat4_identity();
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
|
|
glBindVertexArray(mesh->vao);
|
|
glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
glUniform2f(g_render_mgr->geo.u_uv_translation, 0.0f, 0.0f);
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 0);
|
|
}
|
|
|
|
// Render maze
|
|
{
|
|
mesh_t* maze = (mesh_t*)get_mesh_by_name("M_Maze");
|
|
material_t* material = (material_t*)get_material_by_handle(maze->material);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
if (state->powerup_timer > 0.0f)
|
|
{
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 1);
|
|
glUniform1f(g_render_mgr->geo.u_ambient_adjust, 0.05f);
|
|
}
|
|
else
|
|
{
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 0);
|
|
}
|
|
|
|
mat4 model_mat = mat4_identity();
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
|
|
glUniform1f(g_render_mgr->geo.u_powerup_timer, state->powerup_timer);
|
|
|
|
glBindVertexArray(maze->vao);
|
|
glDrawElements(GL_TRIANGLES, maze->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
|
|
glUniform1f(g_render_mgr->geo.u_powerup_timer, 0.0f);
|
|
}
|
|
|
|
// Render pedestals
|
|
{
|
|
mesh_t* pedestal = (mesh_t*)get_mesh_by_name("M_Pedestal");
|
|
material_t* material = (material_t*)get_material_by_handle(pedestal->material);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
mat4 model_mat = mat4_identity();
|
|
glBindVertexArray(pedestal->vao);
|
|
for (int i = 0; i < data->items.pedestal_count; i++)
|
|
{
|
|
transform_t transform = data->items.pedestals[i];
|
|
|
|
model_mat.e03 = transform.position.x;
|
|
model_mat.e13 = transform.position.y;
|
|
model_mat.e23 = transform.position.z;
|
|
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, pedestal->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
}
|
|
|
|
// Render the eyeballs
|
|
{
|
|
material_t* material = get_material_by_name("T_Eyeball");
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 1);
|
|
glUniform1f(g_render_mgr->geo.u_ambient_adjust, 0.50f);
|
|
light.color = (vec3){0.8f, 0.3f, 0.0f};
|
|
light.intensity = 0.5f;
|
|
|
|
for (int i = 0; i < data->items.eyeball_count; i++)
|
|
{
|
|
mesh_t* eyeball;
|
|
mat4 model_mat;
|
|
|
|
vec3 position = state->eyeballs[i].transform.position;
|
|
mat4 translation = mat4_identity();
|
|
translation.e03 = position.x;
|
|
translation.e13 = position.y;
|
|
translation.e23 = position.z;
|
|
|
|
if (!state->eyeballs[i].used)
|
|
{
|
|
eyeball = get_mesh_by_name("M_Eyeball");
|
|
|
|
light.position = state->eyeballs[i].transform.position;
|
|
|
|
glUniform3fv(g_render_mgr->geo.u_lights+(3*(i+state->coin_count))+0, 1, (float*)&light.position);
|
|
glUniform3fv(g_render_mgr->geo.u_lights+(3*(i+state->coin_count))+1, 1, (float*)&light.color);
|
|
glUniform1f(g_render_mgr->geo.u_lights+(3*(i+state->coin_count))+2, light.intensity);
|
|
|
|
// Look at the player
|
|
vec3 front = vec3_normalize(vec3_sub(position, state->camera.position));
|
|
vec3 side = vec3_normalize(vec3_cross(front, (vec3){0.0f, 0.0f, 1.0f}));
|
|
vec3 up = vec3_cross(side, front);
|
|
|
|
mat4 rotation = mat4_identity();
|
|
rotation.e00 = side.x; rotation.e01 = front.x; rotation.e02 = up.x;
|
|
rotation.e10 = side.y; rotation.e11 = front.y; rotation.e12 = up.y;
|
|
rotation.e20 = side.z; rotation.e21 = front.z; rotation.e22 = up.z;
|
|
|
|
model_mat = mat4_multm(translation, rotation);
|
|
} else {
|
|
eyeball = get_mesh_by_name("M_EyeballUsed");
|
|
|
|
model_mat = translation;
|
|
}
|
|
|
|
glBindVertexArray(eyeball->vao);
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, eyeball->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 0);
|
|
glUniform1f(g_render_mgr->geo.u_ambient_adjust, 0.01f);
|
|
}
|
|
|
|
// Render the skulls
|
|
{
|
|
mesh_t* mesh_top = (mesh_t*)get_mesh_by_name("M_SkullTop");
|
|
mesh_t* mesh_bottom = (mesh_t*)get_mesh_by_name("M_SkullBottom");
|
|
material_t* material = (material_t*)get_material_by_handle(mesh_top->material);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
float z_translation = 1.25f;
|
|
mat4 scale = mat4_identity();
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
for (int i = 0; i < ENEMY_COUNT; i++)
|
|
{
|
|
vec3 position = {
|
|
state->skulls[i].tile_pos.x * 2.0f + 1.0f + state->skulls[i].delta.x,
|
|
state->skulls[i].tile_pos.y * 2.0f + 1.0f + state->skulls[i].delta.y,
|
|
z_translation};
|
|
|
|
mat4 model_mat = mat4_identity();
|
|
|
|
// Rotate top
|
|
{
|
|
float angle = atan2(state->skulls[i].front.y, state->skulls[i].front.x);
|
|
|
|
// Compensate by 90 deg to align with Cartesian rotation
|
|
angle += PI_DIV_2;
|
|
|
|
float sin_angle = sinf(angle);
|
|
float cos_angle = cosf(angle);
|
|
|
|
model_mat.e00 = cos_angle;
|
|
model_mat.e01 = -sin_angle;
|
|
model_mat.e10 = sin_angle;
|
|
model_mat.e11 = cos_angle;
|
|
|
|
model_mat.e03 = position.x;
|
|
model_mat.e13 = position.y;
|
|
model_mat.e23 = position.z;
|
|
|
|
float distance = vec3_length(vec3_sub(state->camera.position, position));
|
|
distance = normalize(distance, 1.0f, 5.0f);
|
|
|
|
float mouth_angle = lerp(-45.0f, 0.0f, distance);
|
|
|
|
mat4 rotate_x = mat4_identity();
|
|
|
|
sin_angle = sinf(DEG_TO_RAD(mouth_angle));
|
|
cos_angle = cosf(DEG_TO_RAD(mouth_angle));
|
|
|
|
rotate_x.e11 = cos_angle;
|
|
rotate_x.e12 = -sin_angle;
|
|
rotate_x.e21 = sin_angle;
|
|
rotate_x.e22 = cos_angle;
|
|
|
|
model_mat = mat4_multm(model_mat, scale);
|
|
model_mat = mat4_multm(model_mat, rotate_x);
|
|
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
|
|
glBindVertexArray(mesh_top->vao);
|
|
glDrawElements(GL_TRIANGLES, mesh_top->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
|
|
// Rotate bottom
|
|
{
|
|
float distance = vec3_length(vec3_sub(state->camera.position, position));
|
|
distance = 1.0f - normalize(distance, 1.0f, 5.0f);
|
|
|
|
float mouth_angle = lerp(0.0f, 45.0f, distance);
|
|
|
|
mat4 rotate_x = mat4_identity();
|
|
|
|
float sin_angle = sinf(DEG_TO_RAD(mouth_angle));
|
|
float cos_angle = cosf(DEG_TO_RAD(mouth_angle));
|
|
|
|
rotate_x.e11 = cos_angle;
|
|
rotate_x.e12 = -sin_angle;
|
|
rotate_x.e21 = sin_angle;
|
|
rotate_x.e22 = cos_angle;
|
|
|
|
rotate_x = mat4_multm(model_mat, rotate_x);
|
|
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&rotate_x);
|
|
|
|
glBindVertexArray(mesh_bottom->vao);
|
|
glDrawElements(GL_TRIANGLES, mesh_bottom->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Render score
|
|
{
|
|
material_t* material = get_material_by_name("T_Numeral");
|
|
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_texture_alpha, 0.4f);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 1);
|
|
glUniform1f(g_render_mgr->geo.u_ambient_adjust, 0.75f);
|
|
|
|
float sine = sinf(2.0f*state->time);
|
|
float cosine = cosf(2.0f*state->time);
|
|
mat4 rotation = mat4_identity();
|
|
rotation.e00 = cosine;
|
|
rotation.e01 = -sine;
|
|
rotation.e10 = sine;
|
|
rotation.e11 = cosine;
|
|
{
|
|
state->nodes[0].rotation = rotation;
|
|
update_node(state->nodes, &state->nodes[0]);
|
|
|
|
// Render the hundreds place
|
|
{
|
|
mat4 model_mat = state->nodes[1].matrix;
|
|
|
|
int hundreds = state->coin_count / 100;
|
|
|
|
char mesh_name[32];
|
|
snprintf(mesh_name, sizeof(mesh_name), "M_Digit%d", hundreds);
|
|
|
|
mesh_t* mesh = get_mesh_by_name(mesh_name);
|
|
glBindVertexArray(mesh->vao);
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
|
|
// Render the tens place
|
|
{
|
|
mat4 model_mat = state->nodes[2].matrix;
|
|
|
|
int tens = (state->coin_count % 100) / 10;
|
|
|
|
char mesh_name[32];
|
|
snprintf(mesh_name, sizeof(mesh_name), "M_Digit%d", tens);
|
|
|
|
mesh_t* mesh = get_mesh_by_name(mesh_name);
|
|
glBindVertexArray(mesh->vao);
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
|
|
// Render the ones place
|
|
{
|
|
mat4 model_mat = state->nodes[3].matrix;
|
|
|
|
int ones = (state->coin_count % 100 % 10);
|
|
char mesh_name[32];
|
|
snprintf(mesh_name, sizeof(mesh_name), "M_Digit%d", ones);
|
|
|
|
mesh_t* mesh = get_mesh_by_name(mesh_name);
|
|
glBindVertexArray(mesh->vao);
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
}
|
|
|
|
// Render the coin
|
|
{
|
|
mat4 translation = mat4_identity();
|
|
translation.e03 = data->score.coin.position.x;
|
|
translation.e13 = data->score.coin.position.y;
|
|
translation.e23 = data->score.coin.position.z;
|
|
|
|
mat4 scale = mat4_identity();
|
|
scale.e00 = data->score.coin.scale.x;
|
|
scale.e11 = data->score.coin.scale.y;
|
|
scale.e22 = data->score.coin.scale.z;
|
|
|
|
mat4 model_mat = mat4_multm(rotation, scale);
|
|
model_mat = mat4_multm(translation, model_mat);
|
|
|
|
mesh_t* mesh = get_mesh_by_name("M_Coin");
|
|
material = get_material_by_handle(mesh->material);
|
|
glBindTexture(GL_TEXTURE_2D, material->texture);
|
|
glUniform1i(g_render_mgr->geo.u_texture, 0);
|
|
glUniform1f(g_render_mgr->geo.u_uv_scale, 1.0f);
|
|
|
|
|
|
glBindVertexArray(mesh->vao);
|
|
glUniformMatrix4fv(g_render_mgr->geo.u_model, 1, GL_TRUE, (float*)&model_mat);
|
|
glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_SHORT, NULL);
|
|
}
|
|
|
|
glUniform1i(g_render_mgr->geo.u_is_emitter, 0);
|
|
glUniform1f(g_render_mgr->geo.u_texture_alpha, 1.0f);
|
|
}
|
|
|
|
render_geo_end();
|
|
}
|
|
|
|
void
|
|
render_screen(void)
|
|
{
|
|
state_t* state = &g_game->state;
|
|
|
|
render_screen_begin();
|
|
|
|
glUniform1i(g_render_mgr->screen.u_texture, 0);
|
|
glUniform1f(g_render_mgr->screen.u_powerup_timer, state->powerup_timer);
|
|
|
|
render_screen_end();
|
|
}
|
|
|