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/game/im_render.c

327 lines
9.7 KiB

#include "im_render.h"
#include "entity.h"
#include "camera.h"
#include "gl_load.h"
#include "../common/array.h"
#include "../common/num_types.h"
#include "shader.h"
#include "../common/log.h"
#include "geometry.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define MAX_IM_VERTICES 2048
#define MAX_IM_GEOMETRIES (MAX_IM_VERTICES / 2)
static struct
{
struct IM_Vertex current_vertices[MAX_IM_VERTICES];
struct IM_Geom geometries[MAX_IM_GEOMETRIES];
uint vao;
uint vbo;
int im_shader;
int curr_geom;
int curr_vertex;
}
IM_State;
static struct IM_Geom* active_geom = NULL;
static int current_vertex_index = 0;
static void im_geom_reset(struct IM_Geom* geom);
static int im_sort_func(const void* p1, const void* p2);
void im_init(void)
{
glGenVertexArrays(1, &IM_State.vao);
glBindVertexArray(IM_State.vao);
glGenBuffers(1, &IM_State.vbo);
glBindBuffer(GL_ARRAY_BUFFER, IM_State.vbo);
GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(struct IM_Vertex) * MAX_IM_VERTICES * MAX_IM_GEOMETRIES, NULL, GL_STREAM_DRAW));
//Position
GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), 0));
GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_POSITION));
////Color
//GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), sizeof(vec3)));
//GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_COLOR));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
memset(&IM_State.geometries[0], 0, sizeof(struct IM_Geom) * MAX_IM_GEOMETRIES);
memset(&IM_State.current_vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES);
IM_State.curr_geom = -1;
IM_State.curr_vertex = 0;
IM_State.im_shader = shader_create("im_geom.vert", "im_geom.frag");
}
void im_cleanup(void)
{
shader_remove(IM_State.im_shader);
glDeleteBuffers(1, &IM_State.vbo);
glDeleteVertexArrays(1, &IM_State.vao);
memset(&IM_State.geometries[0], 0, sizeof(struct IM_Geom) * MAX_IM_GEOMETRIES);
memset(&IM_State.current_vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES);
IM_State.vao = 0;
IM_State.vbo = 0;
IM_State.curr_geom = -1;
IM_State.curr_vertex = 0;
IM_State.im_shader = -1;
}
void im_begin(vec3 position, quat rotation, vec3 scale, vec4 color, int draw_mode, int draw_order)
{
if(active_geom)
{
log_error("im_begin", "im_begin called before im_end");
return;
}
IM_State.curr_geom++;
active_geom = &IM_State.geometries[IM_State.curr_geom];
im_geom_reset(active_geom);
active_geom->start_index = IM_State.curr_vertex;
active_geom->type = IGT_DYNAMIC;
active_geom->draw_mode = draw_mode;
active_geom->draw_order = draw_order;
vec3_assign(&active_geom->position, &position);
vec3_assign(&active_geom->scale, &scale);
vec4_assign(&active_geom->color, &color);
quat_assign(&active_geom->rotation, &rotation);
}
void im_pos(float x, float y, float z)
{
if(IM_State.curr_vertex == MAX_IM_VERTICES)
{
log_error("im_pos", "Buffer full!");
return;
}
current_vertex_index++;
vec3_fill(&IM_State.current_vertices[current_vertex_index].position, x, y, z);
IM_State.curr_vertex++;
}
void im_box(float x, float y, float z, vec3 position, quat rotation, vec4 color, int draw_mode, int draw_order)
{
if(active_geom)
{
log_error("im_box", "im_box called before im_end");
return;
}
IM_State.curr_geom++;
active_geom = &IM_State.geometries[IM_State.curr_geom];
im_geom_reset(active_geom);
active_geom->type = IGT_PRIMITIVE;
active_geom->draw_mode = draw_mode;
active_geom->draw_order = draw_order;
active_geom->prim_geom_index = geom_create_from_file("cube.symbres");
vec3_assign(&active_geom->position, &position);
vec3 scale = { x, y, z};
vec3_assign(&active_geom->scale, &scale);
vec4_assign(&active_geom->color, &color);
quat_assign(&active_geom->rotation, &rotation);
active_geom = NULL;
}
void im_sphere(float radius, vec3 position, quat rotation, vec4 color, int draw_mode, int draw_order)
{
if(active_geom)
{
log_error("im_sphere", "im_sphere called before im_end");
return;
}
IM_State.curr_geom++;
active_geom = &IM_State.geometries[IM_State.curr_geom];
im_geom_reset(active_geom);
active_geom->type = IGT_PRIMITIVE;
active_geom->draw_mode = draw_mode;
active_geom->draw_order = draw_order;
active_geom->prim_geom_index = geom_create_from_file("sphere.symbres");
vec3_assign(&active_geom->position, &position);
vec3 scale = { radius, radius, radius };
vec3_assign(&active_geom->scale, &scale);
quat_assign(&active_geom->rotation, &rotation);
vec4_assign(&active_geom->color, &color);
active_geom = NULL;
}
void im_line(vec3 p1, vec3 p2, vec3 position, quat rotation, vec4 color, int draw_order)
{
im_begin(position, rotation, (vec3) { 1.f, 1.f, 1.f }, color, GDM_LINES, draw_order);
im_pos(p1.x, p1.y, p1.z);
im_pos(p2.x, p2.y, p2.z);
im_end();
}
void im_circle(float radius, int num_divisions, bool filled, vec3 position, quat rotation, vec4 color, int draw_order)
{
im_arc(radius, 0.f, 360.f, num_divisions, filled, position, rotation, color, draw_order);
}
void im_arc(float radius, float angle_start, float angle_end, int num_divisions, bool filled, vec3 position, quat rotation, vec4 color, int draw_order)
{
float arc_degrees = angle_end - angle_start;
if(fabsf(arc_degrees) < 0.01f)
return;
im_begin(position, rotation, (vec3) { 1.f, 1.f, 1.f }, color, filled ? GDM_TRIANGLE_FAN : GDM_LINE_LOOP, draw_order);
if(arc_degrees != 360)
im_pos(0.f, 0.f, 0.f);
if(arc_degrees > 360.f)
{
arc_degrees = (int)arc_degrees % 360;
angle_end = arc_degrees;
}
else if(arc_degrees < -360.f)
{
arc_degrees = (int)arc_degrees % -360;
angle_end = arc_degrees;
}
if(fabsf(arc_degrees) < 0.01f)
arc_degrees = arc_degrees < 0.f ? -0.01f : 0.01f;
float increment = arc_degrees / num_divisions;
if(fabsf(increment) < 0.01f)
increment = increment < 0.f ? -0.01f : 0.01f;
if(angle_start < angle_end)
{
int count = 0;
for(float i = angle_start; i <= angle_end; i += increment)
{
count++;
im_pos(sinf(i * M_PI / 180.f) * radius, cosf(i * M_PI / 180.f) * radius, 0.f);
}
}
else
{
for(float i = angle_start; i >= angle_end; i += increment)
im_pos(sinf(i * M_PI / 180.f) * radius, cosf(i * M_PI / 180.f) * radius, 0.f);
}
im_end();
}
void im_ray(struct Ray* ray, float length, vec4 color, int draw_order)
{
vec3 ending_pos = { 0.f, 0.f, 0.f };
vec3_scale(&ending_pos, &ray->direction, length);
vec3_add(&ending_pos, &ending_pos, &ray->origin);
im_line(ray->origin, ending_pos, (vec3) { 0.f, 0.f, 0.f }, (quat) { 0.f, 0.f, 0.f, 1.f }, color, draw_order);
}
void im_end(void)
{
active_geom->num_vertices = current_vertex_index + 1;
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, IM_State.vbo));
GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER,
sizeof(struct IM_Vertex) * active_geom->start_index,
sizeof(struct IM_Vertex) * active_geom->num_vertices,
&IM_State.current_vertices[0]));
glBindBuffer(GL_ARRAY_BUFFER, 0);
active_geom = NULL;
current_vertex_index = -1;
memset(&IM_State.current_vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES);
}
void im_render(struct Camera* active_viewer)
{
if(IM_State.curr_geom == -1)
return;
/* Sort by draw order, geometries with lower draw order get drawn first */
if(IM_State.curr_geom + 1 > 1)
qsort(IM_State.geometries, IM_State.curr_geom + 1, sizeof(struct IM_Geom), &im_sort_func);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_MULTISAMPLE);
shader_bind(IM_State.im_shader);
{
static mat4 mvp, translation, rotation, scale;
for(int i = 0; i <= IM_State.curr_geom; i++)
{
struct IM_Geom* geom = &IM_State.geometries[i];
mat4_identity(&mvp);
mat4_identity(&scale);
mat4_identity(&translation);
mat4_identity(&rotation);
mat4_scale(&scale, geom->scale.x, geom->scale.y, geom->scale.z);
mat4_translate(&translation, geom->position.x, geom->position.y, geom->position.z);
mat4_from_quat(&rotation, &geom->rotation);
mat4_mul(&mvp, &mvp, &translation);
mat4_mul(&mvp, &mvp, &rotation);
mat4_mul(&mvp, &mvp, &scale);
mat4_mul(&mvp, &active_viewer->view_proj_mat, &mvp);
shader_set_uniform_mat4(IM_State.im_shader, "mvp", &mvp);
shader_set_uniform_vec4(IM_State.im_shader, "geom_color", &geom->color);
if(geom->type == IGT_DYNAMIC)
{
GL_CHECK(glBindVertexArray(IM_State.vao));
GL_CHECK(glDrawArrays(draw_modes[geom->draw_mode], geom->start_index, geom->num_vertices));
GL_CHECK(glBindVertexArray(0));
}
else
{
GL_CHECK(glPolygonMode(GL_FRONT_AND_BACK, GL_LINE));
geom_render(geom->prim_geom_index, geom->draw_mode);
GL_CHECK(glPolygonMode(GL_FRONT_AND_BACK, GL_FILL));
}
}
}
shader_unbind();
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_MULTISAMPLE);
IM_State.curr_geom = -1;
IM_State.curr_vertex = 0;
}
void im_geom_reset(struct IM_Geom* geom)
{
vec3_fill(&geom->position, 0.f, 0.f, 0.f);
quat_identity(&geom->rotation);
vec3_fill(&geom->scale, 1.f, 1.f, 1.f);
vec4_fill(&geom->color, 0.f, 0.f, 0.f, 0.f);
geom->type = -1;
geom->start_index = -1;
geom->num_vertices = 0;
geom->prim_geom_index = -1;
geom->draw_mode = -1;
geom->draw_order = -1;
}
int im_sort_func(const void* p1, const void* p2)
{
struct IM_Geom* g1 = (struct IM_Geom*)p1;
struct IM_Geom* g2 = (struct IM_Geom*)p2;
if(g1->draw_order < g2->draw_order)
return -1;
else if(g1->draw_order == g2->draw_order)
return 0;
else
return 1;
}