Browse Source

staging entity changes to renderer

master
cinnaboot 8 years ago
parent
commit
096f3b16e7
  1. 2
      .gitignore
  2. 1
      data/default.fs
  3. 17
      src/entity.h
  4. 97
      src/hexgame.cpp
  5. 19
      src/hexgame.h
  6. 80
      src/mesh.cpp
  7. 12
      src/mesh.h
  8. 294
      src/render_group.cpp
  9. 42
      src/render_group.h
  10. 126
      src/renderer.cpp
  11. 23
      src/util.cpp
  12. 6
      src/util.h

2
.gitignore vendored

@ -5,4 +5,4 @@ tags
msvc/.vs/
msvc/x64/
imgui.ini
doc/

1
data/default.fs

@ -22,5 +22,6 @@ void main()
brightness = clamp(brightness, 0, 1);
color = brightness * fragmentColor;
//color = vec3(255, 255, 255);
}

17
src/entity.h

@ -0,0 +1,17 @@
#pragma once
#include "mesh.h"
#include "render_group.h"
struct render_group;
struct Entity
{
meMeshGroup mesh_group;
render_group* ren_group;
//TODO: more entity properties: sound, gameplay info
};

97
src/hexgame.cpp

@ -1,18 +1,27 @@
//-----------------------------------------------------------------------------
// TODO:
// - add a color buffer to hex_line and debug render groups to re-use
// fragment shaders and simplify draw rgDraw()
// - need to add normal buffer too
// - lighting
// - add light struct
// - pass all lights to render groups/shaders every frame
// - need to give hexagons vertex normals (can then get rid of rgDraw())
// - maybe use more than one model in a scene
// - map generation
// - pathfinding
// - assimp animation
// - update imgui to v1.62 -- requires changes to example api
// - replace aixlog with custom logging iostream?
// - fix vector normalization in renderer.cpp when moving in 2 directions
// - add prefix to interface function names for eg) gooey.h, renderer.h
// - test build on windows / update vs project files
// - move hex logic to new file to leave only init glue in a main.cpp
// - move SDL input callbacks somewhere too?
// - think about combining mesh data and render_group data to save some memory
// - actually don't need to save the vertex/normal buffers after passing
// to opengl
// - replace calls to malloc/free with safe(r) function in util.h
// - also need to make a macro that works with malloc void * and c++
// - add cpu perforcmace counters in render loop
// - check for memory leaks w/ valgrind
//-----------------------------------------------------------------------------
// Some defaults for the game layout
@ -47,19 +56,19 @@
#endif
#include "aixlog.hpp"
#include "util.h"
#include "gooey.h"
#include "hexgame.h"
#include "hexlib.h"
#include "renderer.h"
#include "gooey.h"
#include "mesh.h"
#include "platform_wait_for_vblank.h"
#include "renderer.h"
#include "util.h"
using std::vector;
game_state* g_game_state;
render_state* g_render_state;
vector<Point> g_polygon_select_vertices = {Point(), Point(), Point(), Point()};
static game_state* g_game_state;
static render_state* g_render_state;
static vector<Point> g_polygon_select_vertices = {Point(), Point(), Point(), Point()};
void
createHexes(vector<hex_info> *hxi_array, const Layout &layout, uint32 color)
@ -454,26 +463,20 @@ cleanUp(SDL_Handles &handles)
SDL_DestroyWindow(handles.window);
SDL_Quit();
if (g_game_state)
{
if (g_game_state->hex_array)
delete g_game_state->hex_array;
delete g_game_state;
}
game_state* g = g_game_state;
// TODO: C-style memory management for entities
render_state* r = g_render_state;
if (r) {
for (uint i = 0; i < r->entity_count; i++) {
meFreeMesh(r->entities[i].mesh);
}
if (g_game_state->hex_array)
delete g_game_state->hex_array;
std::free(r->entities);
r->entities = nullptr;
delete r;
r = nullptr;
for (uint i = 0; i < g->entity_count; i++) {
meFreeMeshGroup(g->entities[i].mesh_group);
rgFree(g->entities[i].ren_group);
}
utilSafeFree(g->entities);
delete g_render_state;
delete g_game_state;
return true;
}
@ -541,19 +544,32 @@ int main(int argc, char* argv[])
}
}
// TODO: better entity memory management
if (meInitAssimp()) {
// TODO: better entity memory management
// TODO: hard coded limit of 1000 entities here
Entity* e = (Entity*) std::calloc(1000, sizeof(Entity));
render_state* r = g_render_state;
r->entities = e;
//const char* test_file = "../data/animated.block.dae";
const char* test_file = "../data/catepillar.dae";
meMeshInfo* mesh = meLoadFromFile(test_file);
if (mesh != nullptr) {
r->entities[r->entity_count].mesh = mesh;
r->entity_count++;
game_state* g = g_game_state;
g->entities = (Entity*) std::calloc(1000, sizeof(Entity));
const char* test_file1 = "../data/animated.block.dae";
const char* test_file2 = "../data/catepillar.dae";
meMeshGroup mg1, mg2;
if (meLoadFromFile(test_file1, mg1)) {
g->entities[g->entity_count].mesh_group = mg1;
g->entity_count++;
}
else {
LOG(ERROR) << "Error loading file, exiting\n";
return 1;
}
if (meLoadFromFile(test_file2, mg2)) {
g->entities[g->entity_count].mesh_group = mg2;
g->entity_count++;
}
else {
LOG(ERROR) << "Error loading file, exiting\n";
return 1;
}
} else {
@ -561,7 +577,7 @@ int main(int argc, char* argv[])
return 1;
}
if (!createScene(g_game_state->hex_array, g_render_state->entities, g_render_state->entity_count)) {
if (!createScene(g_game_state->hex_array, g_game_state->entities, g_game_state->entity_count)) {
LOG(ERROR) << "Error in vertex data, exiting\n";
return 1;
}
@ -571,17 +587,20 @@ int main(int argc, char* argv[])
return 1;
}
#if defined(_WIN32)
if (!platform_init(handles.window)) {
LOG(ERROR) << "Couldn't get SDL platform info, exiting\n";
return 1;
}
#else
LOG(DEBUG) << "TODO: Implement better frame timer on linux\n"; // should notice this
#endif
// main loop
while (processSDLEvents()) {
#if defined(_WIN32)
// sort-of fixed in windows with platform_wait_for_vblank()
#else
LOG(DEBUG) << "TODO: Implement better frame timer on linux\n"; // should notice this
SDL_Delay(16); // ~60hz
#endif
game_state* g = g_game_state;
@ -590,7 +609,7 @@ int main(int argc, char* argv[])
moveCamera(g->is_moveup, g->is_moveleft, g->is_movedown, g->is_moveright,
g->is_moveforward, g->is_movebackward);
renderFrame(g->hex_array, g_render_state->entities, g_render_state->entity_count);
renderFrame(g->hex_array, g->entities, g->entity_count);
if (r->is_debug_draw && g->draw_mode == CONE_FILL)
renderDebug(g_polygon_select_vertices);

19
src/hexgame.h

@ -11,9 +11,10 @@
#include <glm/glm.hpp>
#include "entity.h"
#include "hexlib.h"
#include "util.h"
#include "mesh.h"
#include "util.h"
// TODO: should move this to renderer.h
@ -46,22 +47,12 @@ enum HexDrawMode
PATHFINDING
};
struct Entity
{
meMeshInfo* mesh;
//TODO: more entity properties: sound, gameplay info
};
struct render_state
{
v2i viewport_dims;
bool is_debug_draw;
uint32 fill_color;
uint32 selected_fill_color;
// TODO: should move this to game_state
uint32 entity_count = 0;
Entity* entities = nullptr;
};
struct game_state
@ -73,7 +64,11 @@ struct game_state
HexDrawMode draw_mode;
const Layout hex_layout;
// movement controls
// TODO: WiP
uint32 entity_count = 0;
Entity* entities = nullptr;
// camera movement controls
bool is_selecting = false;
bool is_camera_rotate = false;
bool is_moveforward = false;

80
src/mesh.cpp

@ -14,6 +14,10 @@
#include "mesh.h"
inline glm::vec3 copyVector(aiVector3D v_in, glm::vec3& v_out);
meMeshInfo* copyMeshInfo(const aiScene* scene, aiMesh* mesh);
void freeMesh(meMeshInfo* mesh);
bool
meInitAssimp()
{
@ -27,6 +31,43 @@ meInitAssimp()
return true;
}
bool
meLoadFromFile(const char* filename, meMeshGroup& mesh_group)
{
LOG(INFO) << "Loading file: " << filename << "\n";
const aiScene* scene = aiImportFile(filename, aiProcessPreset_TargetRealtime_MaxQuality);
if (scene->mNumMeshes < 1) {
LOG(ERROR) << "Scene contains no meshes\n";
return false;
}
mesh_group.num_meshes = scene->mNumMeshes;
mesh_group.meshes = (meMeshInfo**) std::calloc(mesh_group.num_meshes, sizeof(meMeshInfo*));
mesh_group.use_normals = scene->mMeshes[0]->HasNormals();
for (uint i = 0; i < scene->mNumMeshes; i++) {
mesh_group.meshes[i] = copyMeshInfo(scene, scene->mMeshes[i]);
}
// free memeory from assimp
aiReleaseImport(scene);
return true;
}
void
meFreeMeshGroup(meMeshGroup& mesh_group)
{
for (uint i = 0; i < mesh_group.num_meshes; i++)
freeMesh(mesh_group.meshes[i]);
}
void
meShutdownAssimp()
{
aiDetachAllLogStreams();
}
inline glm::vec3
copyVector(aiVector3D v_in, glm::vec3& v_out)
{
@ -37,26 +78,13 @@ copyVector(aiVector3D v_in, glm::vec3& v_out)
}
meMeshInfo*
meLoadFromFile(const char* filename)
copyMeshInfo(const aiScene* scene, aiMesh* mesh)
{
const aiScene* scene = aiImportFile(filename, aiProcessPreset_TargetRealtime_MaxQuality);
if (scene->mNumMeshes != 1) {
LOG(ERROR) << "We Can only handle 1 mesh per entity atm\n";
#if 0
return nullptr;
#else
LOG(DEBUG) << "num meshes: " << scene->mNumMeshes << "\n";
LOG(DEBUG) << "num materials: " << scene->mNumMaterials << "\n";
#endif
}
meMeshInfo* mi = (meMeshInfo*) std::calloc(1, sizeof(meMeshInfo));
// TODO: using hard coded model transform for now
mi->model_transform = glm::scale(glm::mat4(1), glm::vec3(100, 100, 100));
// allocate buffers for vertex and index data from mesh
aiMesh* mesh = scene->mMeshes[2];
mi->num_vertices = mesh->mNumVertices;
mi->vertices = (glm::vec3 *) std::calloc(mi->num_vertices, sizeof(glm::vec3));
mi->normals = (glm::vec3 *) std::calloc(mi->num_vertices, sizeof(glm::vec3));
@ -77,7 +105,7 @@ meLoadFromFile(const char* filename)
mi->indices[i * 3 + j] = mesh->mFaces[i].mIndices[j];
// material
aiMaterial* mat = scene->mMaterials[1];
aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
aiColor3D color(0.f, 0.f, 0.f);
if (AI_SUCCESS != mat->Get(AI_MATKEY_COLOR_DIFFUSE, color)) {
LOG(ERROR) << "Some Assimp-type-error\n";
@ -87,27 +115,15 @@ meLoadFromFile(const char* filename)
mi->diffuse_color.b = color.b;
}
// free memeory from assimp
aiReleaseImport(scene);
return mi;
}
void
meFreeMesh(meMeshInfo* mesh)
freeMesh(meMeshInfo* mesh)
{
std::free(mesh->vertices);
mesh->vertices = nullptr;
std::free(mesh->normals);
mesh->normals = nullptr;
std::free(mesh->indices);
mesh->indices = nullptr;
std::free(mesh);
mesh = nullptr;
}
void
meShutdownAssimp()
{
aiDetachAllLogStreams();
utilSafeFree(mesh->vertices);
utilSafeFree(mesh->normals);
utilSafeFree(mesh->indices);
utilSafeFree(mesh);
}

12
src/mesh.h

@ -20,12 +20,20 @@ struct meMeshInfo
glm::vec3 diffuse_color;
};
struct meMeshGroup
{
bool use_normals = false;
uint num_meshes = 0;
meMeshInfo** meshes = nullptr;
// animation/bonemapping info here...
};
bool meInitAssimp();
meMeshInfo* meLoadFromFile(const char* filename);
bool meLoadFromFile(const char* filename, meMeshGroup& mesh_group);
void meFreeMesh(meMeshInfo* mesh);
void meFreeMeshGroup(meMeshGroup& mesh_group);
void meShutdownAssimp();

294
src/render_group.cpp

@ -2,9 +2,6 @@
#include <cassert>
#include <cstdlib> // calloc
// TODO: decide on extension library
//#include <GL/glew.h>
#include <GL/gl3w.h>
#include <glm/glm.hpp>
#include <glm/geometric.hpp>
#include <glm/gtc/matrix_transform.hpp>
@ -13,14 +10,30 @@
#include "render_group.h"
#include "mesh.h"
#include "util.h"
#define INFO_LOG_MAX_LENGTH 312;
// forward declarations
render_object * allocateRenderObject(uint buffer_len, uint index_len = 0);
void freeRenderObject(render_object* ro);
bool convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals);
void sendBufferToGL(gl_buffer* buffer, GLenum usage, GLenum target);
void sendIndexBufferToGL(gl_index_buffer* index_buffer, GLenum usage, GLenum target);
void drawRenderObject(render_group* rg, render_object* ro,
glm::mat4 model_matrix, glm::mat4 view_matrix, glm::mat4 projection_matrix,
glm::vec3 light_position, GLuint light_id, bool update_vertex_data);
// interface
bool
rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char * frag_code)
rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char * frag_code)
{
glGenVertexArrays(1, &rg->vertex_array_id);
glBindVertexArray(rg->vertex_array_id);
glGenVertexArrays(1, &sp.vertex_array_id);
glBindVertexArray(sp.vertex_array_id);
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER);
@ -29,18 +42,18 @@ rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char *
glCompileShader(vertex_shader_id);
glCompileShader(fragment_shader_id);
rg->program_id = glCreateProgram();
glAttachShader(rg->program_id, vertex_shader_id);
glAttachShader(rg->program_id, fragment_shader_id);
glLinkProgram(rg->program_id);
sp.program_id = glCreateProgram();
glAttachShader(sp.program_id, vertex_shader_id);
glAttachShader(sp.program_id, fragment_shader_id);
glLinkProgram(sp.program_id);
rg->model_matrix_id = glGetUniformLocation(rg->program_id, "model");
rg->view_matrix_id = glGetUniformLocation(rg->program_id, "view");
rg->projection_matrix_id = glGetUniformLocation(rg->program_id, "projection");
rg->normal_matrix_id = glGetUniformLocation(rg->program_id, "normal_matrix");
sp.model_matrix_id = glGetUniformLocation(sp.program_id, "model");
sp.view_matrix_id = glGetUniformLocation(sp.program_id, "view");
sp.projection_matrix_id = glGetUniformLocation(sp.program_id, "projection");
sp.normal_matrix_id = glGetUniformLocation(sp.program_id, "normal_matrix");
glDetachShader(rg->program_id, vertex_shader_id);
glDetachShader(rg->program_id, fragment_shader_id);
glDetachShader(sp.program_id, vertex_shader_id);
glDetachShader(sp.program_id, fragment_shader_id);
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
@ -48,18 +61,18 @@ rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char *
// also remove INFO_LOG_MAX_LENGTH define
#if 1
GLint isLinked = 0;
glGetProgramiv(rg->program_id, GL_LINK_STATUS, &isLinked);
glGetProgramiv(sp.program_id, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE) {
GLint maxLength = INFO_LOG_MAX_LENGTH;
glGetProgramiv(rg->program_id, GL_INFO_LOG_LENGTH, &maxLength);
glGetProgramiv(sp.program_id, GL_INFO_LOG_LENGTH, &maxLength);
#ifdef _WIN32
GLchar infoLog[312] = { 0 };
#else
GLchar infoLog[maxLength] = { 0 };
#endif
glGetProgramInfoLog(rg->program_id, maxLength, &maxLength, &infoLog[0]);
glGetProgramInfoLog(sp.program_id, maxLength, &maxLength, &infoLog[0]);
LOG(ERROR) << infoLog << "\n";
glDeleteProgram(rg->program_id);
glDeleteProgram(sp.program_id);
return false;
}
@ -68,32 +81,130 @@ rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char *
return true;
}
gl_buffer *
rgInitGLBuffer(gl_buffer* buffer, uint buffer_len)
// TODO: should pass in a buffer of colors here instead of hexes, move to renderer.cpp
// we don't need to know about hexes here
#if 0
void
rgFillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes)
{
int buf_idx;
int buf_len_per_hex = 54; // NOTE: 3 * 3 * 6
GLfloat color_buf[3];
for (int i = 0; i < (int) hexes->size(); i++)
{
buf_idx = i * buf_len_per_hex;
hex_info hxi = (*hexes)[i];
utilConvertColor(color_buf, hxi.current_color);
for (int j = 0; j < buf_len_per_hex; j+=3)
{
buf[buf_idx + j] = color_buf[0];
buf[buf_idx + j + 1] = color_buf[1];
buf[buf_idx + j + 2] = color_buf[2];
}
}
}
#endif
bool
rgInitEntity(Entity* e)
{
render_group* rg = UTIL_ALLOC(1, render_group);
e->ren_group = rg;
rg->draw_indexed = true;
rg->use_normals = e->mesh_group.use_normals;
uint num_meshes = rg->num_objects = e->mesh_group.num_meshes;
rg->render_objects = (render_object**) std::calloc(num_meshes, sizeof(render_object*));
for (uint i = 0; i < num_meshes; i++)
{
uint buffer_len = e->mesh_group.meshes[i]->num_vertices * 3;
uint index_len = e->mesh_group.meshes[i]->num_indices;
rg->render_objects[i] = allocateRenderObject(buffer_len, index_len);
if (rg->render_objects[i] == nullptr)
return false;
// TODO: safely free memory here when convertMeshInfo returns false
if (!convertMeshInfo(e->mesh_group.meshes[i], rg->render_objects[i], rg->use_normals))
return false;
}
return true;
}
void
rgDraw(render_group* rg, glm::mat4 model_matrix, glm::mat4 view_matrix, glm::mat4 projection_matrix,
glm::vec3 light_position, GLuint light_id, bool update_vertex_data)
{
for (uint i = 0; i < rg->num_objects; i++) {
drawRenderObject(rg, rg->render_objects[i], model_matrix, view_matrix, projection_matrix,
light_position, light_id, false);
}
}
void
rgFree(render_group* rg)
{
buffer->buffer_len = buffer_len;
buffer->buffer = (GLfloat*) std::calloc(buffer_len, sizeof(GLfloat));
if (rg == nullptr) {
LOG(ERROR) << "tried to free nullptr\n";
return;
}
if (!buffer->buffer)
LOG(ERROR) << "Error allocating memory\n";
for (uint i = 0; i < rg->num_objects; i++)
freeRenderObject(rg->render_objects[i]);
return buffer;
utilSafeFree(rg);
}
gl_index_buffer *
initGLIndexBuffer(gl_index_buffer* index_buffer, uint buffer_len)
// internal
render_object *
allocateRenderObject(uint buffer_len, uint index_len)
{
index_buffer->buffer_len = buffer_len;
index_buffer->buffer = (uint*) std::calloc(buffer_len, sizeof(uint));
render_object* ro = UTIL_ALLOC(1, render_object);
if (ro == nullptr)
return nullptr;
ro->vertex_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat);
ro->vertex_buffer.buffer_len = buffer_len;
ro->normal_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat);
ro->normal_buffer.buffer_len = buffer_len;
ro->color_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat);
ro->color_buffer.buffer_len = buffer_len;
if (!index_buffer->buffer)
LOG(ERROR) << "Error allocating memory\n";
if (index_len > 0) {
ro->index_buffer.buffer = UTIL_ALLOC(index_len, uint);
ro->index_buffer.buffer_len = index_len;
}
if (ro->vertex_buffer.buffer == nullptr ||
ro->normal_buffer.buffer == nullptr ||
ro->color_buffer.buffer == nullptr ||
((index_len > 0) && (ro->vertex_buffer.buffer == nullptr)))
{
freeRenderObject(ro);
return nullptr;
}
return ro;
}
return index_buffer;
void
freeRenderObject(render_object* ro)
{
utilSafeFree(ro->vertex_buffer.buffer);
utilSafeFree(ro->normal_buffer.buffer);
utilSafeFree(ro->color_buffer.buffer);
utilSafeFree(ro->index_buffer.buffer);
utilSafeFree(ro);
}
void
rgSendBufferToGL(gl_buffer* buffer, GLenum usage, GLenum target)
sendBufferToGL(gl_buffer* buffer, GLenum usage, GLenum target)
{
glGenBuffers(1, &buffer->buffer_id);
glBindBuffer(target, buffer->buffer_id);
@ -108,39 +219,14 @@ sendIndexBufferToGL(gl_index_buffer* index_buffer, GLenum usage, GLenum target)
glBufferData(target, index_buffer->buffer_len * sizeof(uint), index_buffer->buffer, usage);
}
void
rgFillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes)
{
int buf_idx;
int buf_len_per_hex = 54; // NOTE: 3 * 3 * 6
GLfloat color_buf[3];
for (int i = 0; i < (int) hexes->size(); i++)
{
buf_idx = i * buf_len_per_hex;
hex_info hxi = (*hexes)[i];
utilConvertColor(color_buf, hxi.current_color);
for (int j = 0; j < buf_len_per_hex; j+=3)
{
buf[buf_idx + j] = color_buf[0];
buf[buf_idx + j + 1] = color_buf[1];
buf[buf_idx + j + 2] = color_buf[2];
}
}
}
// NOTE: Copy assimp data to our structures for openGL
bool
rgInitEntity(gl_render_group* rg, Entity* e)
convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals)
{
rg->draw_indexed = true;
rg->use_normals = (e->mesh->normals != nullptr);
uint vertex_buf_len = e->mesh->num_vertices * 3;
GLfloat* vertex_buf = rgInitGLBuffer(&rg->vertex_buffer, vertex_buf_len)->buffer;
GLfloat* color_buf = rgInitGLBuffer(&rg->color_buffer, vertex_buf_len)->buffer;
GLfloat* normal_buf = rgInitGLBuffer(&rg->normal_buffer, vertex_buf_len)->buffer;
uint* index_buf = initGLIndexBuffer(&rg->index_buffer, e->mesh->num_indices)->buffer;
uint vertex_buf_len = mesh->num_vertices * 3;
GLfloat* vertex_buf = ro->vertex_buffer.buffer;
GLfloat* color_buf = ro->color_buffer.buffer;
GLfloat* normal_buf = ro->normal_buffer.buffer;
uint* index_buf = ro->index_buffer.buffer;
if (!vertex_buf || !color_buf || !normal_buf || !index_buf)
return false;
@ -150,8 +236,8 @@ rgInitEntity(gl_render_group* rg, Entity* e)
uint vertex_prop_index = 0;
for (uint i = 0; i < vertex_buf_len; i++) {
const glm::vec3& vertex = e->mesh->vertices[vertex_index];
const glm::vec3& normal = e->mesh->normals[vertex_index];
const glm::vec3& vertex = mesh->vertices[vertex_index];
const glm::vec3& normal = mesh->normals[vertex_index];
switch (vertex_prop_index) {
case 0: vertex_buf[i] = vertex.x; break;
@ -159,7 +245,7 @@ rgInitEntity(gl_render_group* rg, Entity* e)
case 2: vertex_buf[i] = vertex.z; break;
}
if (rg->use_normals) {
if (use_normals) {
switch (vertex_prop_index) {
case 0: normal_buf[i] = normal.x; break;
case 1: normal_buf[i] = normal.y; break;
@ -167,7 +253,7 @@ rgInitEntity(gl_render_group* rg, Entity* e)
}
}
color_buf[i] = e->mesh->diffuse_color[vertex_prop_index];
color_buf[i] = mesh->diffuse_color[vertex_prop_index];
vertex_prop_index++;
if (vertex_prop_index == 3) {
@ -177,89 +263,77 @@ rgInitEntity(gl_render_group* rg, Entity* e)
}
// dump indices
for (uint i = 0; i < e->mesh->num_indices; i++)
index_buf[i] = e->mesh->indices[i];
for (uint i = 0; i < mesh->num_indices; i++)
index_buf[i] = mesh->indices[i];
rgSendBufferToGL(&rg->vertex_buffer, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER);
rgSendBufferToGL(&rg->color_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
if (rg->use_normals)
rgSendBufferToGL(&rg->normal_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
sendIndexBufferToGL(&rg->index_buffer, GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
sendBufferToGL(&ro->vertex_buffer, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER);
sendBufferToGL(&ro->color_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
if (use_normals)
sendBufferToGL(&ro->normal_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
sendIndexBufferToGL(&ro->index_buffer, GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
return true;
}
void
rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix,
glm::mat4 view_matrix, glm::mat4 projection_matrix,
drawRenderObject(render_group* rg, render_object* ro,
glm::mat4 model_matrix, glm::mat4 view_matrix, glm::mat4 projection_matrix,
glm::vec3 light_position, GLuint light_id, bool update_vertex_data)
{
glUseProgram(rg->program_id);
glUniformMatrix4fv(rg->model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]);
glUniformMatrix4fv(rg->view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]);
glUniformMatrix4fv(rg->projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]);
glUseProgram(rg->shader.program_id);
glUniformMatrix4fv(rg->shader.model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]);
glUniformMatrix4fv(rg->shader.view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]);
glUniformMatrix4fv(rg->shader.projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, rg->vertex_buffer.buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, ro->vertex_buffer.buffer_id);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
if (update_vertex_data)
{
glBufferSubData(GL_ARRAY_BUFFER, 0, rg->vertex_buffer.buffer_len * sizeof(GLfloat),
rg->vertex_buffer.buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, ro->vertex_buffer.buffer_len * sizeof(GLfloat),
ro->vertex_buffer.buffer);
}
// 2nd attribute buffer : colors
if (rg->color_buffer.buffer)
if (ro->color_buffer.buffer)
{
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, rg->color_buffer.buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, ro->color_buffer.buffer_id);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
// TODO: maybe add an option to not send color data every frame?
glBufferSubData(GL_ARRAY_BUFFER, 0, rg->color_buffer.buffer_len * sizeof(GLfloat),
rg->color_buffer.buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, ro->color_buffer.buffer_len * sizeof(GLfloat),
ro->color_buffer.buffer);
}
// 3rd attribute buffer: normals
#if 1
if (rg->use_normals) {
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, rg->normal_buffer.buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, ro->normal_buffer.buffer_id);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
// TODO: testing lighting
glUniform3f(light_id, light_position.x, light_position.y, light_position.z);
glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model_matrix)));
glUniformMatrix3fv(rg->normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]);
glUniformMatrix3fv(rg->shader.normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]);
}
#endif
// draw
if (rg->draw_indexed) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rg->index_buffer.buffer_id);
glDrawElements(draw_mode, rg->index_buffer.buffer_len, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ro->index_buffer.buffer_id);
glDrawElements(GL_TRIANGLES, ro->index_buffer.buffer_len, GL_UNSIGNED_INT, 0);
} else {
glDrawArrays(draw_mode, 0, rg->vertex_buffer.buffer_len / 3);
glDrawArrays(rg->draw_mode, 0, ro->vertex_buffer.buffer_len / 3);
}
// cleanup
glDisableVertexAttribArray(0);
if (rg->color_buffer.buffer)
if (ro->color_buffer.buffer)
glDisableVertexAttribArray(1);
if (rg->use_normals)
glDisableVertexAttribArray(2);
}
void
rgFree(gl_render_group* rg)
{
if (rg == nullptr)
return;
utilSafeFree(rg->vertex_buffer.buffer);
utilSafeFree(rg->normal_buffer.buffer);
utilSafeFree(rg->index_buffer.buffer);
utilSafeFree(rg->color_buffer.buffer);
utilSafeFree(rg);
}

42
src/render_group.h

@ -1,6 +1,13 @@
#pragma once
#include <GL/gl3w.h>
#include "entity.h"
//#include "hexgame.h"
#include "util.h"
#include "hexgame.h"
struct Entity;
// TODO: can these structs be used as opaque pointers?
@ -18,39 +25,44 @@ struct gl_index_buffer
uint* buffer = nullptr;
};
struct gl_render_group
struct render_object
{
gl_buffer vertex_buffer;
gl_buffer normal_buffer;
gl_buffer color_buffer;
gl_index_buffer index_buffer;
};
struct rg_shader_program
{
GLuint program_id = 0;
GLuint model_matrix_id = 0;
GLuint view_matrix_id = 0;
GLuint projection_matrix_id = 0;
GLuint normal_matrix_id = 0;
GLuint vertex_array_id = 0;
};
struct render_group
{
uint num_objects = 0;
render_object** render_objects = nullptr;
rg_shader_program shader;
bool use_normals = false;
bool draw_indexed = false;
GLenum draw_mode = GL_TRIANGLES;
};
typedef struct gl_buffer gl_buffer;
typedef struct gl_index_buffer gl_index_buffer;
typedef struct gl_render_group gl_render_group;
bool rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char * frag_code);
gl_buffer * rgInitGLBuffer(gl_buffer* buffer, uint buffer_len);
void rgSendBufferToGL(gl_buffer* buffer, GLenum usage, GLenum target);
bool rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char * frag_code);
bool rgInitEntity(gl_render_group* rg, Entity* e);
bool rgInitEntity(Entity* e);
void rgFillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes);
// TODO: fix this function to use just buffers instead of hexes
//void rgFillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes);
void rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix,
void rgDraw(render_group* rg, glm::mat4 model_matrix,
glm::mat4 view_matrix, glm::mat4 projection_matrix,
glm::vec3 light_position, GLuint light_id, bool update_vertex_data = false);
void rgFree(gl_render_group* rg);
void rgFree(render_group* rg);

126
src/renderer.cpp

@ -83,16 +83,16 @@ struct camera
};
gl_matrix_info g_scene_matrices;
gl_render_group* g_filled_hex_render_group;
gl_render_group* g_hex_line_render_group;
gl_render_group* g_debug_render_group;
gl_render_group* g_entity_render_group;
camera g_camera;
// globals
static gl_matrix_info g_scene_matrices;
static render_group g_filled_hex_render_group;
static render_group g_hex_line_render_group;
static render_group g_debug_render_group;
// NOTE: entity render_group references are kept in the entity struct
static camera g_camera;
// TODO: testing lighting
renPointLight g_test_light;
static renPointLight g_test_light;
bool
@ -158,6 +158,7 @@ initMatrices(projection_type p)
g_camera.position = glm::vec3(640,0,100);
g_camera.target = glm::vec3(640,500,0);
//g_camera.target = glm::vec3(0,0,0);
// inital rotation should match target direction
glm::vec3 &p = g_camera.position;
glm::vec3 &t = g_camera.target;
@ -274,29 +275,26 @@ initRenderer(SDL_Handles &handles, v2i vpDims)
// hide VRAM debug messages
glDebugMessageControl(GL_DONT_CARE, 33361, GL_DONT_CARE, 0, 0, GL_FALSE);
g_filled_hex_render_group = (gl_render_group *) std::calloc(1, sizeof(gl_render_group));
g_hex_line_render_group = (gl_render_group *) std::calloc(1, sizeof(gl_render_group));
g_debug_render_group = (gl_render_group *) std::calloc(1, sizeof(gl_render_group));
g_entity_render_group = (gl_render_group *) std::calloc(1, sizeof(gl_render_group));
if (!g_filled_hex_render_group || !g_hex_line_render_group
|| !g_debug_render_group || !g_entity_render_group)
{
return false;
}
#if 0
const char* vs_code = utilDumpTextFile(DEFAULT_VERTEX_SHADER_FILE);
const char* fs_code = utilDumpTextFile(DEFAULT_FRAGMENT_SHADER_FILE);
if (!rgInitShaderProgram(g_filled_hex_render_group, vs_code, fs_code)
|| !rgInitShaderProgram(g_hex_line_render_group, vs_code, LINE_FRAGMENT_SHADER_CODE)
|| !rgInitShaderProgram(g_debug_render_group, vs_code, DEBUG_FRAGMENT_SHADER_CODE)
|| !rgInitShaderProgram(g_entity_render_group, vs_code, fs_code))
{
bool shader_error = (!rgInitShaderProgram(&g_filled_hex_render_group, vs_code, fs_code)
|| !rgInitShaderProgram(&g_hex_line_render_group, vs_code, LINE_FRAGMENT_SHADER_CODE)
|| !rgInitShaderProgram(&g_debug_render_group, vs_code, DEBUG_FRAGMENT_SHADER_CODE));
utilSafeFree(vs_code);
utilSafeFree(fs_code);
if (shader_error) {
LOG(ERROR) << "Error initializing shader program\n";
return false;
} else {
return true;
}
#else
return true;
#endif
}
void
@ -370,16 +368,17 @@ fillHexLineBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes)
bool
initHexGridBuffers(std::vector<hex_info>* hexes)
{
#if 0
// TODO: index duplicate vertices
// 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54
uint vbuf_len = hexes->size() * 6 * 3 * 3;
uint line_vertices_per_hex = 6 * 2; // 12 vertices since we're using line segments atm
uint line_buf_len = hexes->size() * line_vertices_per_hex * 3; // 3 floats per vertex
gl_buffer& vbuf = * rgInitGLBuffer(&g_filled_hex_render_group->vertex_buffer, vbuf_len);
gl_buffer& cbuf = * rgInitGLBuffer(&g_filled_hex_render_group->color_buffer, vbuf_len);
gl_buffer& normal_buf = * rgInitGLBuffer(&g_filled_hex_render_group->normal_buffer, vbuf_len);
gl_buffer& line_buf = * rgInitGLBuffer(&g_hex_line_render_group->vertex_buffer, line_buf_len);
gl_buffer& vbuf = * rgInitGLBuffer(&g_filled_hex_render_group.vertex_buffer, vbuf_len);
gl_buffer& cbuf = * rgInitGLBuffer(&g_filled_hex_render_group.color_buffer, vbuf_len);
gl_buffer& normal_buf = * rgInitGLBuffer(&g_filled_hex_render_group.normal_buffer, vbuf_len);
gl_buffer& line_buf = * rgInitGLBuffer(&g_hex_line_render_group.vertex_buffer, line_buf_len);
if (!vbuf.buffer || !cbuf.buffer || !line_buf.buffer || !normal_buf.buffer)
return false;
@ -411,6 +410,7 @@ initHexGridBuffers(std::vector<hex_info>* hexes)
rgSendBufferToGL(&line_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER);
// TODO: add a color buffer to hex_line and debug render groups to re-use
// fragment shaders and simplify draw rgDraw()
#endif
return true;
}
@ -422,30 +422,53 @@ createScene(std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count)
if (!initHexGridBuffers(hexes))
return false;
// debug draw vertexes
// debug draw vertices
#if 0
rgInitGLBuffer(&g_debug_render_group->vertex_buffer, 4 * 3); // 4 vertices * 3 floats per vertex
if (!g_debug_render_group->vertex_buffer.buffer)
return false;
rgSendBufferToGL(&g_debug_render_group->vertex_buffer, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER);
#endif
// entities
// TODO: wtf, I only accounted for 1 entity in the entity render group :(
// probably need one render_group struct for each entity
for (uint i = 0; i < entity_count; i++)
rgInitEntity(g_entity_render_group, &entities[i]);
#if 1
const char* vs_code = utilDumpTextFile(DEFAULT_VERTEX_SHADER_FILE);
const char* fs_code = utilDumpTextFile(DEFAULT_FRAGMENT_SHADER_FILE);
rg_shader_program sp;
bool shader_errors = !rgInitShaderProgram(sp, vs_code, fs_code);
utilSafeFree(vs_code);
utilSafeFree(fs_code);
if (shader_errors)
return false;
for (uint i = 0; i < entity_count; i++) {
rgInitEntity(&entities[i]);
entities[i].ren_group->shader = sp;
}
#else
if (!rgInitEntity(&entities[0])) {
LOG(ERROR) << "Error initialzing entity\n";
return false;
}
#endif
// lights
// TODO: load light properties from scene/level files
g_test_light.light_ID = glGetUniformLocation(g_entity_render_group->program_id, "light_position");
g_test_light.position = glm::vec3(640, 500, 400); // above center of hexgrid
g_test_light.direction = glm::vec3(0, 0, 0) - g_test_light.position; // back towards test entity
g_test_light.color = glm::vec3(1.f, 1.f, 1.f);
g_test_light.intensity = 1.f;
//g_test_light.light_ID = glGetUniformLocation(g_entity_render_group.program_id, "light_position");
if (entities[0].ren_group != nullptr) {
g_test_light.light_ID = glGetUniformLocation(entities[0].ren_group->shader.program_id, "light_position");
g_test_light.position = glm::vec3(640, 500, 400); // above center of hexgrid
g_test_light.direction = glm::vec3(0, 0, 0) - g_test_light.position; // back towards test entity
g_test_light.color = glm::vec3(1.f, 1.f, 1.f);
g_test_light.intensity = 1.f;
}
return true;
}
@ -541,12 +564,13 @@ renderFrame(std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count)
glClearColor(g_clear_col.R, g_clear_col.G, g_clear_col.B, g_clear_col.A);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glm::mat4 m_model = g_scene_matrices.model;
//glm::mat4 m_model = g_scene_matrices.model;
glm::mat4 m_view = g_scene_matrices.view;
glm::mat4 m_projection = g_scene_matrices.projection;
// filled hexes
#if 0
// get new colors every frame
gl_render_group* rg = g_filled_hex_render_group;
rgFillColorBuffer(rg->color_buffer.buffer, rg->color_buffer.buffer_len, hexes);
@ -557,14 +581,16 @@ renderFrame(std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count)
rgDraw(g_hex_line_render_group, GL_LINES, m_model, m_view, m_projection,
g_test_light.position, g_test_light.light_ID);
#endif
// TODO: update and send array of lights (pos, dir, color, intesity to shaders
// every frame through rgDrawIndexed()
// entities
for (uint i = 0; i < entity_count; i++) {
// TODO: find a way to store model xform on the meMeshGroup object
glm::mat4 model_transform = entities[i].mesh_group.meshes[0]->model_transform;
rgDraw(
g_entity_render_group, GL_TRIANGLES,
entities[i].mesh->model_transform, m_view, m_projection,
entities[i].ren_group, model_transform, m_view, m_projection,
g_test_light.position, g_test_light.light_ID
);
}
@ -573,8 +599,9 @@ renderFrame(std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count)
void
renderDebug(std::vector<Point> &vertices)
{
#if 0
// TODO: indexed line drawing
// copy vertexes to render group
// copy vertices to render group
GLfloat* buf = g_debug_render_group->vertex_buffer.buffer;
buf[0] = vertices[0].x; buf[1] = vertices[0].y; buf[2] = 0;
buf[3] = vertices[1].x; buf[4] = vertices[1].y; buf[2] = 0;
@ -583,19 +610,22 @@ renderDebug(std::vector<Point> &vertices)
rgDraw(g_debug_render_group, GL_LINE_LOOP, g_scene_matrices.model, g_scene_matrices.view,
g_scene_matrices.projection, g_test_light.position, g_test_light.light_ID, true);
#endif
}
void
freeBuffers()
{
std::vector<gl_render_group*> groups = {
LOG(DEBUG) << "redo freeBuffers function after render_group update\n";
#if 0
std::vector<render_group> groups = {
g_filled_hex_render_group,
g_hex_line_render_group,
g_debug_render_group,
g_entity_render_group
};
for (gl_render_group* group : groups)
for (render_group group : groups)
rgFree(group);
#endif
}

23
src/util.cpp

@ -7,6 +7,7 @@
#include "util.h"
const uint MAX_FILESIZE = 2 * 1024 * 1024; // 2MB
const uint MAX_STRING_LENGTH = 1024;
char *
utilDumpTextFile(const char* filename)
@ -30,6 +31,19 @@ utilDumpTextFile(const char* filename)
return buf;
}
void *
utilLogAlloc(uint item_count, uint type_size, const char* file_name, const int line)
{
void* mem = std::calloc(item_count, type_size);
if (mem == nullptr) {
LOG(ERROR) << "Memory allocation failed, called from "
<< file_name << ":" << line;
}
return mem;
}
// TODO: search/replace other calls to std::free with this
void
utilSafeFree(void* mem)
@ -40,3 +54,12 @@ utilSafeFree(void* mem)
}
}
// TODO: re-use non-const version, macro or cast away const
void utilSafeFree(const void* mem)
{
if (mem != nullptr) {
std::free((void *) mem);
mem = nullptr;
}
}

6
src/util.h

@ -74,7 +74,11 @@ utilConvertColor(GLfloat buf[3], uint32 color)
buf[2] = (GLfloat) ((color >> 8) & 0xFF) / (GLfloat) 255;
}
char * utilDumpTextFile(const char* filename);
// NOTE: Wrapper for calloc that will send error message on out of memory
void * utilLogAlloc(uint item_count, uint type_size, const char* file_name, const int line);
#define UTIL_ALLOC(len, type) (type *) utilLogAlloc((len), sizeof(type), __FILE__, __LINE__)
char * utilDumpTextFile(const char* filename);
void utilSafeFree(void* mem);
void utilSafeFree(const void* mem);

Loading…
Cancel
Save