A 3d fps game made in OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Symmetry/src/camera.c

212 lines
5.8 KiB

#include "GLFW/glfw3.h"
#include "camera.h"
#include "entity.h"
#include "transform.h"
#include "array.h"
#include "framebuffer.h"
#include "texture.h"
#include "utils.h"
#include "log.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
static struct Camera* camera_list;
static int* empty_indices;
static int primary_camera_index;
struct Camera* camera_get(int index)
{
struct Camera* camera = NULL;
if(index > -1 && index < array_len(camera_list))
camera = &camera_list[index];
return camera;
}
void camera_init(void)
{
camera_list = array_new(struct Camera);
empty_indices = array_new(int);
primary_camera_index = -1;
}
void camera_remove(int index)
{
if(index > -1 && index < array_len(camera_list))
{
struct Camera* camera = &camera_list[index];
if(camera->fbo != -1) framebuffer_remove(camera->fbo);
if(camera->render_tex != -1) texture_remove(camera->render_tex);
if(camera->depth_tex != -1) texture_remove(camera->depth_tex);
camera->fbo = camera->render_tex = camera->depth_tex = camera->node = -1;
array_push(empty_indices, index, int);
}
}
void camera_cleanup(void)
{
for(int i = 0; i < array_len(camera_list); i++)
if(camera_list[i].node != -1) camera_remove(i);
array_free(camera_list);
array_free(empty_indices);
}
int camera_create(int node, int width, int height)
{
int index = -1;
struct Camera* new_camera = NULL;
if(array_len(empty_indices) > 0)
{
index = *array_get_last(empty_indices, int);
new_camera = &camera_list[index];
array_pop(empty_indices);
}
else
{
new_camera = array_grow(camera_list, struct Camera);
index = array_len(camera_list) - 1;
}
new_camera->fbo = -1;
new_camera->render_tex = -1;
new_camera->depth_tex = -1;
new_camera->node = node;
new_camera->farz = 1000.f;
new_camera->nearz = 0.1f;
new_camera->fov = 60.f;
float aspect_ratio = (float)width / (float)height;
new_camera->aspect_ratio = aspect_ratio <= 0.f ? (4.f / 3.f) : aspect_ratio;
new_camera->ortho = 0;
mat4_identity(&new_camera->view_mat);
mat4_identity(&new_camera->proj_mat);
mat4_identity(&new_camera->view_proj_mat);
camera_update_view(new_camera);
camera_update_proj(new_camera);
vec4_fill(&new_camera->clear_color, 1.f, 1.f, 1.f, 1.f);
return index;
}
void camera_update_view_proj(struct Camera* camera)
{
mat4_mul(&camera->view_proj_mat, &camera->proj_mat, &camera->view_mat);
}
void camera_update_view(struct Camera* camera)
{
struct Entity* entity = entity_get(camera->node);
struct Transform* transform = entity_component_get(entity, C_TRANSFORM);
vec3 lookat = {0.f, 0.f, 0.f};
vec3 up = {0.f, 0.f, 0.f};
vec3 position = {0.f, 0.f, 0.f};
transform_get_absolute_lookat(transform, &lookat);
transform_get_absolute_up(transform, &up);
transform_get_absolute_pos(transform, &position);
mat4_lookat(&camera->view_mat, &position, &lookat, &up);
camera_update_view_proj(camera);
}
void camera_update_proj(struct Camera* camera)
{
if(!camera->ortho)
{
mat4_perspective(&camera->proj_mat,
camera->fov,
camera->aspect_ratio,
camera->nearz,
camera->farz);
}
else
{
mat4_ortho(&camera->proj_mat, -1, 1, -1, 1, camera->nearz, camera->farz);
}
camera_update_view_proj(camera);
}
void camera_attach_fbo(struct Camera* camera, int width, int height, int has_depth, int has_color)
{
assert(width > 0 && height > 0 && camera);
if(camera->fbo != -1)
{
log_error("camera:attach_fbo", "Camera already has fbo attached!");
return;
}
camera->fbo = framebuffer_create(width, height, has_depth, has_color);
if(camera->fbo > -1)
{
char tex_name[128];
snprintf(tex_name, 128, "cam_render_tex_%d", camera->node);
camera->render_tex = texture_create(tex_name,
TU_DIFFUSE,
width, height,
GL_RGBA,
GL_RGBA8,
GL_UNSIGNED_BYTE,
NULL);
texture_set_param(camera->render_tex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
texture_set_param(camera->render_tex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
texture_set_param(camera->render_tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
texture_set_param(camera->render_tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
memset(tex_name, '\0', 128);
snprintf(tex_name, 128, "cam_depth_tex_%d", camera->node);
camera->depth_tex = texture_create(tex_name,
TU_SHADOWMAP1,
width, height,
GL_DEPTH_COMPONENT,
GL_DEPTH_COMPONENT,
GL_UNSIGNED_BYTE,
NULL);
texture_set_param(camera->depth_tex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
texture_set_param(camera->depth_tex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
texture_set_param(camera->depth_tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
texture_set_param(camera->depth_tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
texture_set_param(camera->depth_tex, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
texture_set_param(camera->depth_tex, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
camera->fbo = framebuffer_create(width, height, 0, 1);
framebuffer_set_texture(camera->fbo, camera->render_tex, GL_COLOR_ATTACHMENT0);
framebuffer_set_texture(camera->fbo, camera->depth_tex, GL_DEPTH_ATTACHMENT);
}
else
{
log_error("camera:attach_fbo", "Framebuffer not attached to camera!");
}
}
struct Camera* camera_get_all(void)
{
return camera_list;
}
void camera_set_primary_viewer(struct Camera* camera)
{
assert(camera);
if(camera->node == -1)
{
log_error("camera:set_primary_viewer", "Invalid camera!");
}
else
{
/* locate the index of this camera */
for(int i = 0; i < array_len(camera_list); i++)
{
if(camera_list[i].node == camera->node)
{
primary_camera_index = i;
log_message("Camera at index %d set as primary viewer", primary_camera_index);
break;
}
}
}
}
struct Camera* camera_get_primary(void)
{
struct Camera* primary_camera = NULL;
if(primary_camera_index != -1)
primary_camera = &camera_list[primary_camera_index];
return primary_camera;
}