1
0
Fork 0
2022-untitled-game/code/src/game/render.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();
}