dev
parent
a40b11870d
commit
6d56ff2bb1
@ -0,0 +1,254 @@ |
||||
#include "geometry.h" |
||||
#include "array.h" |
||||
#include "num_types.h" |
||||
#include "linmath.h" |
||||
#include "string_utils.h" |
||||
#include "file_io.h" |
||||
#include "log.h" |
||||
#include "renderer.h" |
||||
|
||||
#include "GL/glew.h" |
||||
#include "GLFW/glfw3.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
|
||||
typedef struct
|
||||
{ |
||||
char* filename; |
||||
bool draw_indexed; |
||||
Array* vertices; |
||||
Array* vertex_colors; |
||||
Array* normals; |
||||
Array* uvs; |
||||
Array* indices; |
||||
uint vao; |
||||
uint vertex_vbo; |
||||
uint uv_vbo; |
||||
uint normal_vbo; |
||||
uint color_vbo; |
||||
uint index_vbo; |
||||
uint ref_count; |
||||
/* BoundingBox boundingBox; */ |
||||
/* BoundingSphere boundingSphere; */ |
||||
} Geometry; |
||||
|
||||
/* Data */ |
||||
static Array* geometry_list; |
||||
static Array* empty_indices; |
||||
|
||||
/* Function definitions */ |
||||
bool load_from_file(Geometry* geometry, const char* filename); |
||||
void create_vao(Geometry* geometry); |
||||
|
||||
void geom_initialize(void) |
||||
{ |
||||
geometry_list = array_new(Geometry); |
||||
empty_indices = array_new(int); |
||||
} |
||||
|
||||
int geom_find(const char* filename) |
||||
{ |
||||
int index = -1; |
||||
for(int i = 0; i < (int)geometry_list->length; i++) |
||||
{ |
||||
Geometry* geometry = array_get(geometry_list, i); |
||||
if(strcmp(geometry->filename, filename) == 0) |
||||
{ |
||||
index = i; |
||||
break; |
||||
} |
||||
} |
||||
return index; |
||||
} |
||||
|
||||
int geom_create(const char* name) |
||||
{ |
||||
// check if exists
|
||||
int index = geom_find(name); |
||||
if(index == -1) |
||||
{ |
||||
/* add new geometry object or overwrite existing one */ |
||||
Geometry* new_geo = NULL; |
||||
int index = -1; |
||||
if(empty_indices->length != 0) |
||||
{ |
||||
index = array_get_last_val(empty_indices, int); |
||||
array_pop(empty_indices); |
||||
new_geo = array_get(geometry_list, index); |
||||
} |
||||
else |
||||
{ |
||||
new_geo = array_add(geometry_list); |
||||
index = geometry_list->length - 1; |
||||
} |
||||
assert(new_geo); |
||||
|
||||
|
||||
if(load_from_file(new_geo, name)) |
||||
{ |
||||
create_vao(new_geo); |
||||
//generateBoundingBox(index);
|
||||
} |
||||
else |
||||
{ |
||||
/* TODO: Some error here, find it and fix it */ |
||||
array_pop(geometry_list); |
||||
index = -1; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
Geometry* raw_geom_array = array_get_raw(geometry_list, Geometry); |
||||
raw_geom_array[index].ref_count++; |
||||
} |
||||
return index; |
||||
} |
||||
|
||||
void geom_remove(int index) |
||||
{ |
||||
if(index >= 0 && index < (int)geometry_list->length) |
||||
{ |
||||
Geometry* geometry = array_get(geometry_list, index); |
||||
array_free(geometry->indices); |
||||
array_free(geometry->vertices); |
||||
array_free(geometry->uvs); |
||||
array_free(geometry->normals); |
||||
array_free(geometry->vertex_colors); |
||||
free(geometry->filename); |
||||
array_push(empty_indices, index, int); |
||||
} |
||||
} |
||||
|
||||
void geom_cleanup(void) |
||||
{ |
||||
for(uint i = 0; i < geometry_list->length; i++) |
||||
geom_remove(i); |
||||
|
||||
array_free(geometry_list); |
||||
array_free(empty_indices); |
||||
} |
||||
|
||||
bool load_from_file(Geometry* geometry, const char* filename) |
||||
{ |
||||
assert(filename); |
||||
bool success = true; |
||||
char* full_path = str_new("models/"); |
||||
full_path = str_concat(full_path, filename); |
||||
|
||||
FILE* file = io_file_open(full_path, "rb"); |
||||
free(full_path); |
||||
if(file) |
||||
{
|
||||
const uint32 INDEX_SIZE = sizeof(uint32); |
||||
const uint32 VEC3_SIZE = sizeof(vec3); |
||||
const uint32 VEC2_SIZE = sizeof(vec2); |
||||
uint32 header[4]; |
||||
size_t bytes_read = 0; |
||||
if((bytes_read = fread(header, INDEX_SIZE, 4, file)) <= 0) |
||||
{ |
||||
log_error("geometry:load_from_file", "Read failed"); |
||||
success = false; |
||||
} |
||||
else |
||||
{ |
||||
uint32 indices_count = header[0]; |
||||
uint32 vertices_count = header[1]; |
||||
uint32 normals_count = header[2]; |
||||
uint32 uvs_count = header[3]; |
||||
// Indices
|
||||
geometry->indices = array_new_cap(uint, indices_count); |
||||
fread(geometry->indices->data, INDEX_SIZE, indices_count, file); |
||||
// Vertices
|
||||
geometry->vertices = array_new_cap(uint, vertices_count); |
||||
fread(geometry->vertices->data, VEC3_SIZE, vertices_count, file); |
||||
// Normals
|
||||
geometry->normals = array_new_cap(uint, normals_count); |
||||
fread(&geometry->normals->data, VEC3_SIZE, normals_count, file); |
||||
// Uvs
|
||||
geometry->uvs = array_new_cap(uint, uvs_count); |
||||
fread(&geometry->uvs->data, VEC2_SIZE, uvs_count, file); |
||||
} |
||||
fclose(file); |
||||
geometry->filename = str_new(filename); |
||||
geometry->draw_indexed = true; |
||||
geometry->ref_count++; |
||||
} |
||||
else |
||||
{ |
||||
success = false; |
||||
} |
||||
|
||||
return success; |
||||
} |
||||
|
||||
void create_vao(Geometry* geometry) |
||||
{ |
||||
// TODO : Add support for different model formats and interleaving VBO
|
||||
assert(geometry); |
||||
glGenVertexArrays(1, &geometry->vao); |
||||
glBindVertexArray(geometry->vao); |
||||
|
||||
glGenBuffers(1, &geometry->vertex_vbo); |
||||
glBindBuffer(GL_ARRAY_BUFFER, geometry->vertex_vbo); |
||||
glBufferData(GL_ARRAY_BUFFER, |
||||
geometry->vertices->length * sizeof(vec3), |
||||
geometry->vertices->data, |
||||
GL_STATIC_DRAW); |
||||
renderer_check_glerror("Geometry::create_vbo::vertex"); |
||||
glEnableVertexAttribArray(0); |
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); |
||||
|
||||
if(geometry->normals->length > 0) |
||||
{ |
||||
glGenBuffers(1, &geometry->normal_vbo); |
||||
glBindBuffer(GL_ARRAY_BUFFER, geometry->normal_vbo); |
||||
glBufferData(GL_ARRAY_BUFFER, |
||||
geometry->normals->length * sizeof(vec3), |
||||
geometry->normals->data, |
||||
GL_STATIC_DRAW); |
||||
renderer_check_glerror("Geometry::create_vbo::normal"); |
||||
glEnableVertexAttribArray(1); |
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, 0); |
||||
} |
||||
|
||||
if(geometry->uvs->length > 0) |
||||
{ |
||||
glGenBuffers(1, &geometry->uv_vbo); |
||||
glBindBuffer(GL_ARRAY_BUFFER, geometry->uv_vbo); |
||||
glBufferData(GL_ARRAY_BUFFER, |
||||
geometry->uvs->length * sizeof(vec2), |
||||
geometry->uvs->data, |
||||
GL_STATIC_DRAW); |
||||
renderer_check_glerror("Geometry::create_vbo::uv"); |
||||
glEnableVertexAttribArray(2); |
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); |
||||
} |
||||
|
||||
if(geometry->vertex_colors->length > 0) |
||||
{ |
||||
glGenBuffers(1, &geometry->color_vbo); |
||||
glBindBuffer(GL_ARRAY_BUFFER, geometry->color_vbo); |
||||
glBufferData(GL_ARRAY_BUFFER, |
||||
geometry->vertex_colors->length * sizeof(vec3), |
||||
geometry->vertex_colors->data, |
||||
GL_STATIC_DRAW); |
||||
renderer_check_glerror("Geometry::create_vbo::color"); |
||||
glEnableVertexAttribArray(3); |
||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0); |
||||
} |
||||
|
||||
if(geometry->indices->length > 0) |
||||
{ |
||||
glGenBuffers(1, &geometry->index_vbo); |
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->index_vbo); |
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, |
||||
geometry->indices->length * sizeof(GLuint), |
||||
geometry->indices->data, |
||||
GL_STATIC_DRAW); |
||||
geometry->draw_indexed = true; |
||||
} |
||||
glBindVertexArray(0); |
||||
} |
@ -0,0 +1,10 @@ |
||||
#ifndef geometry_H |
||||
#define geometry_H |
||||
|
||||
void geom_initialize(void); |
||||
int geom_ceate(const char* name); |
||||
int geom_find(const char* filename); |
||||
void geom_remove(int index); |
||||
void geom_cleanup(void); |
||||
|
||||
#endif |
@ -0,0 +1,309 @@ |
||||
#include "shader.h" |
||||
#include "file_io.h" |
||||
#include "array.h" |
||||
#include "num_types.h" |
||||
#include "string_utils.h" |
||||
#include "log.h" |
||||
#include "renderer.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
|
||||
#include "GL/glew.h" |
||||
#include "GLFW/glfw3.h" |
||||
|
||||
typedef struct |
||||
{ |
||||
unsigned int vertex_shader; |
||||
unsigned int fragment_shader; |
||||
unsigned int program; |
||||
|
||||
} Shader_Object; |
||||
|
||||
|
||||
// Constants for locations of attributes inside all shaders
|
||||
const int POSITION_LOC = 0; |
||||
const int NORMAL_LOC = 1; |
||||
const int UV_LOC = 2; |
||||
const int COLOR_LOC = 3; |
||||
|
||||
static Array* shader_list; |
||||
static Array* empty_indices; |
||||
|
||||
void debug_print_shader(const char* shaderText) |
||||
{ |
||||
size_t len = strlen(shaderText); |
||||
int line_count = 1; |
||||
printf("%d. ", line_count); |
||||
for(uint i = 0; i < len; i++) |
||||
{ |
||||
if(shaderText[i] != '\n') |
||||
printf("%c", shaderText[i]); |
||||
else |
||||
printf("\n%d. ", ++line_count); |
||||
} |
||||
printf("\n END_DEBUG_PRINT\n\n"); |
||||
} |
||||
|
||||
char* run_preprocessor(char* shader_text) |
||||
{ |
||||
char* include_loc = strstr(shader_text, "//include"); |
||||
if(include_loc) |
||||
{ |
||||
char* line_end = strchr(include_loc, '\n'); |
||||
int line_size = line_end - include_loc; |
||||
char* inc_line = malloc((sizeof(char) * line_size) + 1); |
||||
strncpy(inc_line, include_loc, line_size); |
||||
inc_line[line_size] = '\0'; |
||||
|
||||
char* filename = strtok(inc_line, " "); |
||||
while(filename) |
||||
{ |
||||
filename = strtok(NULL, " "); |
||||
if(filename) |
||||
{ |
||||
char* path = str_new("shaders/"); |
||||
path = str_concat(path, filename); |
||||
char* file = io_file_read(path); |
||||
char* shader_copy = str_new(shader_text); |
||||
char* temp = realloc(shader_text, (strlen(shader_text) + strlen(file) + 2)); |
||||
if(temp) |
||||
{ |
||||
shader_text = temp; |
||||
strcpy(shader_text, file); |
||||
strcat(shader_text, shader_copy); |
||||
} |
||||
else |
||||
{ |
||||
log_warning("Realloc failed in Shader::run_preprocessor"); |
||||
} |
||||
|
||||
free(path); |
||||
free(shader_copy); |
||||
free(file); |
||||
} |
||||
} |
||||
free(inc_line); |
||||
} |
||||
return shader_text; |
||||
} |
||||
|
||||
void shader_initialize(void) |
||||
{ |
||||
shader_list = array_new(Shader_Object); |
||||
empty_indices = array_new(int); |
||||
} |
||||
|
||||
int shader_create(const char* vert_shader_name, const char* frag_shader_name) |
||||
{ |
||||
char* vs_path = str_new("shaders/"); |
||||
vs_path = str_concat(vs_path, vert_shader_name); |
||||
char* fs_path = str_new("shaders/"); |
||||
fs_path = str_concat(fs_path, frag_shader_name); |
||||
|
||||
GLuint vert_shader = glCreateShader(GL_VERTEX_SHADER); |
||||
GLuint frag_shader = glCreateShader(GL_FRAGMENT_SHADER); |
||||
|
||||
char* vert_source = io_file_read(vs_path); |
||||
char* frag_source = io_file_read(fs_path); |
||||
|
||||
assert(vert_source != NULL); |
||||
assert(frag_source != NULL); |
||||
|
||||
vert_source = run_preprocessor(vert_source);
|
||||
frag_source = run_preprocessor(frag_source); |
||||
|
||||
GLint v_size = (GLint)strlen(vert_source); |
||||
GLint f_size = (GLint)strlen(frag_source); |
||||
|
||||
const char* vert_sourcePtr = vert_source; |
||||
const char* frag_sourcePtr = frag_source; |
||||
|
||||
const GLint* vert_size = &v_size; |
||||
const GLint* frag_size = &f_size; |
||||
|
||||
glShaderSource(vert_shader, 1, &vert_sourcePtr, vert_size); |
||||
glShaderSource(frag_shader, 1, &frag_sourcePtr, frag_size); |
||||
|
||||
glCompileShader(vert_shader); |
||||
glCompileShader(frag_shader); |
||||
|
||||
GLint is_vert_compiled = 0; |
||||
GLint is_frag_compiled = 0; |
||||
glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &is_vert_compiled); |
||||
glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &is_frag_compiled); |
||||
|
||||
if(!is_vert_compiled) |
||||
{ |
||||
GLint log_size = 0; |
||||
glGetShaderiv(vert_shader, GL_INFO_LOG_LENGTH, &log_size); |
||||
char* message = (char *)malloc(sizeof(char) * log_size); |
||||
glGetShaderInfoLog(vert_shader, log_size, NULL, message); |
||||
|
||||
log_error("shader:create", "COMPILING VS %s : %s", vert_shader_name, message); |
||||
debug_print_shader(vert_source); |
||||
free(message); |
||||
} |
||||
|
||||
if(!is_frag_compiled) |
||||
{ |
||||
GLint log_size = 0; |
||||
glGetShaderiv(frag_shader, GL_INFO_LOG_LENGTH, &log_size); |
||||
char* message = (char *)malloc(sizeof(char) * log_size); |
||||
glGetShaderInfoLog(frag_shader, log_size, NULL, message); |
||||
|
||||
log_error("shader:create", "COMPILING FS %s : %s", frag_shader_name, message); |
||||
debug_print_shader(frag_source); |
||||
free(message); |
||||
} |
||||
|
||||
free(vert_source); |
||||
free(frag_source); |
||||
|
||||
if(!is_vert_compiled || !is_frag_compiled) |
||||
{ |
||||
glDeleteShader(vert_shader); |
||||
glDeleteShader(frag_shader); |
||||
return -1; |
||||
} |
||||
|
||||
GLuint program = glCreateProgram(); |
||||
glAttachShader(program, vert_shader); |
||||
glAttachShader(program, frag_shader); |
||||
|
||||
// Bind attribute locations
|
||||
glBindAttribLocation(program, POSITION_LOC, "vPosition"); |
||||
glBindAttribLocation(program, NORMAL_LOC, "vNormal"); |
||||
glBindAttribLocation(program, UV_LOC, "vUV"); |
||||
glBindAttribLocation(program, COLOR_LOC, "vColor"); |
||||
renderer_check_glerror("shader:create"); |
||||
glLinkProgram(program); |
||||
|
||||
GLint is_linked = 0; |
||||
glGetProgramiv(program, GL_LINK_STATUS, &is_linked); |
||||
if(!is_linked) |
||||
{ |
||||
GLint log_size = 0; |
||||
glGetProgramiv(program, GL_LINK_STATUS, &log_size); |
||||
char* message = (char *)malloc(sizeof(char) * log_size); |
||||
glGetProgramInfoLog(program, log_size, NULL, message); |
||||
log_error("shader:create", "LINK SHADER : %s", message); |
||||
free(message); |
||||
|
||||
glDeleteProgram(program); |
||||
glDeleteShader(vert_shader); |
||||
glDeleteShader(frag_shader); |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
/* add new object or overwrite existing one */ |
||||
Shader_Object* new_object = NULL; |
||||
int index = -1; |
||||
if(empty_indices->length != 0) |
||||
{ |
||||
index = array_get_last_val(empty_indices, int); |
||||
array_pop(empty_indices); |
||||
new_object = array_get(shader_list, index); |
||||
} |
||||
else |
||||
{ |
||||
new_object = array_add(shader_list); |
||||
index = shader_list->length - 1; |
||||
} |
||||
assert(new_object); |
||||
new_object->vertex_shader = vert_shader; |
||||
new_object->fragment_shader = frag_shader; |
||||
new_object->program = program; |
||||
|
||||
log_message("%s, %s compiled into shader program", vert_shader_name, frag_shader_name); |
||||
free(vs_path); |
||||
free(fs_path); |
||||
|
||||
return index; |
||||
} |
||||
|
||||
void shader_bind(const int shader_index) |
||||
{ |
||||
Shader_Object* shader_object = array_get(shader_list, shader_index); |
||||
glUseProgram(shader_object->program); |
||||
} |
||||
|
||||
void shader_unbind(void) |
||||
{ |
||||
glUseProgram(0); |
||||
} |
||||
|
||||
int get_uniform_location(const int shader_index, const char* name) |
||||
{ |
||||
Shader_Object shader_object = array_get_val(shader_list, Shader_Object, shader_index); |
||||
GLint handle = glGetUniformLocation(shader_object.program, name); |
||||
|
||||
if(handle == -1) |
||||
log_error("shader:get_uniform_location", "Invalid uniform %s", name); |
||||
|
||||
return handle; |
||||
} |
||||
|
||||
void set_uniform_int(const int shader_index, const char* name, const int value) |
||||
{ |
||||
GLint location = get_uniform_location(shader_index, name); |
||||
if(location >= 0) |
||||
glUniform1i(location, value); |
||||
} |
||||
|
||||
void set_uniform_float(const int shader_index, const char* name, const float value) |
||||
{ |
||||
GLint location = get_uniform_location(shader_index, name); |
||||
if(location >= 0) |
||||
glUniform1f(location, value); |
||||
} |
||||
|
||||
void set_uniform_vec2(const int shader_index, const char* name, const vec2 value) |
||||
{ |
||||
GLint location = get_uniform_location(shader_index, name); |
||||
if(location >= 0) |
||||
glUniform2fv(location, 1, value); |
||||
} |
||||
|
||||
void set_uniform_vec3(const int shader_index, const char* name, const vec3 value) |
||||
{ |
||||
GLint location = get_uniform_location(shader_index, name); |
||||
if(location >= 0) |
||||
glUniform3fv(location, 1, value); |
||||
} |
||||
|
||||
void set_uniform_vec4(const int shader_index, const char* name, const vec4 value) |
||||
{ |
||||
GLint location = get_uniform_location(shader_index, name); |
||||
if(location >= 0) |
||||
glUniform4fv(location, 1, value); |
||||
} |
||||
|
||||
void setUniformMat4(const int shader_index, const char* name, const mat4 value) |
||||
{ |
||||
GLint location = get_uniform_location(shader_index, name); |
||||
if(location >= 0) |
||||
glUniformMatrix4fv(location, 1, GL_FALSE, *value); |
||||
} |
||||
|
||||
void shader_remove(const int shader_index) |
||||
{ |
||||
Shader_Object* shader_object = array_get(shader_list, shader_index); |
||||
glDeleteProgram(shader_object->program); |
||||
glDeleteShader(shader_object->vertex_shader); |
||||
glDeleteShader(shader_object->fragment_shader); |
||||
shader_object->fragment_shader = shader_object->vertex_shader = shader_object->program = -1; |
||||
array_push(empty_indices, shader_index, int); |
||||
} |
||||
|
||||
void shader_cleanup(void) |
||||
{ |
||||
for(int i = 0; i < (int)shader_list->length; i++) |
||||
shader_remove(i); |
||||
|
||||
array_free(shader_list); |
||||
array_free(empty_indices); |
||||
} |
@ -0,0 +1,20 @@ |
||||
#ifndef shader_H |
||||
#define shader_H |
||||
|
||||
#include "linmath.h" |
||||
|
||||
int shader_create(const char* vert_shader_name, const char* frag_shader_name); |
||||
void shader_initialize(void); |
||||
void shader_bind(const int shader_index); |
||||
void shader_remove(const int shader_index); |
||||
void shader_unbind(void); |
||||
void shader_set_uniform_int(const int shaderIndex, const char* name, const int value); |
||||
void shader_set_uniform_float(const int shaderIndex, const char* name, const float value); |
||||
void shader_set_uniform_vec2(const int shaderIndex, const char* name, const vec2 value); |
||||
void shader_set_uniform_vec3(const int shaderIndex, const char* name, const vec3 value); |
||||
void shader_set_uniform_vec4(const int shaderIndex, const char* name, const vec4 value); |
||||
void shader_set_uniform_mat4(const int shaderIndex, const char* name, const mat4 value); |
||||
void shader_cleanup(void); |
||||
int shader_uniform_location_get(const int shader_index, const char* name); |
||||
|
||||
#endif |
Loading…
Reference in new issue