Browse Source

update renderer to use an array of light objects

master
cinnaboot 8 years ago
parent
commit
1d33ac3379
  1. 2
      Makefile
  2. 19
      data/default.fs
  3. 38
      src/hexgame.cpp
  4. 36
      src/render_group.cpp
  5. 20
      src/render_group.h
  6. 62
      src/renderer.cpp
  7. 23
      src/renderer.h
  8. 7
      src/scene_loader.cpp
  9. 4
      src/scene_loader.h
  10. 2
      src/util.cpp

2
Makefile

@ -8,7 +8,7 @@ OBJ_DIR = build
# TODO: incorporate imgui into project files and not use gl3w
# can also remove -ldl from LDFLAGS then
CC = gcc
GL3W_CFLAGS = -Wall -I$(IMGUI_DIR)/examples/libs/gl3w
GL3W_CFLAGS = -g -Wall -I$(IMGUI_DIR)/examples/libs/gl3w
CXXFLAGS += -I$(IMGUI_DIR)/examples/libs/gl3w
GL3W_LDFLAGS += -ldl

19
data/default.fs

@ -5,9 +5,18 @@ in vec3 fragNormal;
in vec3 fragVertex;
uniform mat4 model;
uniform vec3 light_position;
uniform mat3 normal_matrix;
struct point_light {
uint light_ID;
vec3 position;
vec3 color;
float intensity;
};
#define MAX_LIGHTS 10
uniform point_light lights[MAX_LIGHTS];
uniform int num_lights = 0;
out vec3 color;
void main()
@ -16,7 +25,13 @@ void main()
vec3 normal = normalize(normal_matrix * fragNormal);
vec3 fragPosition = vec3(model * vec4(fragVertex, 1));
vec3 surfaceToLight = light_position - fragPosition;
/////
//vec3 surfaceToLight = light_position - fragPosition;
vec3 surfaceToLight = lights[0].position - fragPosition;
/////
float brightness = dot(normal, surfaceToLight) / (length(surfaceToLight) * length(normal));
brightness = clamp(brightness, 0, 1);

38
src/hexgame.cpp

@ -3,6 +3,10 @@
* - add 3d orientation widget to gooey
* - lighting
* - test adding more lights
* - implement texturing to reduce the number of meshes generated by assimp
* from materials (currently creates a sepereate mesh per material)
* - need to do UV mapping on models, and parse UV data in shader
* - move renderer globals to render_state object
* - map generation
* - pathfinding
* - assimp animation
@ -19,6 +23,7 @@
* - use a storage pool for assimp meshes allowing reuse across entities
* - replace remaining calls to malloc/free with safe(r) function in util.h
* - add cpu perforcmace counters in render loop
* - maybe try deferred rendering at some point to use a ton of lights
* - check for memory leaks w/ valgrind
******************************************************************************/
@ -35,6 +40,7 @@
#define SCENE_SCHEMA_FILE "scene_schema.json"
#define MAX_ENTITIES 1000
#define RS_MAX_LIGHTS 10 // NOTE: needs to match the fragment shader source
#include <vector>
@ -426,8 +432,10 @@ processSDLEvents()
bool
cleanUp(SDL_Handles &handles)
{
#if 0
shutdownGooey();
freeBuffers(); // renderer.h
#endif
freeBuffers(g_render_state); // renderer.h
for (SDL_Surface *surface : handles.texSurfaces)
SDL_FreeSurface(surface);
meShutdownAssimp(); // mesh.h
@ -476,6 +484,7 @@ int main(int argc, char* argv[])
g_render_state = UTIL_ALLOC(1, render_state);
g_render_state->is_debug_draw = DEBUG_DRAW;
g_render_state->viewport_dims = v2i(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
g_render_state->max_lights = RS_MAX_LIGHTS;
SDL_Handles handles;
@ -489,6 +498,11 @@ int main(int argc, char* argv[])
return 1;
}
if (!initGooey(handles, g_render_state->viewport_dims)) {
LOG(ERROR) << "Fooey, No Gooey!\n";
return 1;
}
{
// load support for the JPG and PNG image formats
int flags=IMG_INIT_JPG|IMG_INIT_PNG;
@ -520,25 +534,29 @@ int main(int argc, char* argv[])
slSceneDoc* sd = slLoadFile(DATA_DIR, DEFAULT_SCENE_FILE, SCENE_SCHEMA_FILE);
if (sd != nullptr) {
game_state* g = g_game_state;
slParseEntities(sd, g->entities, g->entity_count, MAX_ENTITIES, DATA_DIR);
render_state* rs = g_render_state;
if (!slParseEntities(sd, g->entities, g->entity_count, MAX_ENTITIES, DATA_DIR)) {
LOG(ERROR) << "Error loading Entities, exiting\n";
return 1;
}
slParseCamera(sd, renGetCamera());
slParseHexGrid(sd, g->grid);
slParseLights(sd, rs->lights, rs->num_lights, rs->max_lights);
slFreeSceneDoc(sd);
} else {
LOG(ERROR) << "Error loading scene, exiting\n";
return 1;
}
if (!createScene(g_game_state->grid.hex_array, g_game_state->entities, g_game_state->entity_count)) {
if (!createScene(g_render_state, g_game_state->grid.hex_array,
g_game_state->entities, g_game_state->entity_count))
{
LOG(ERROR) << "Error in vertex data, exiting\n";
return 1;
}
if (!initGooey(handles, g_render_state->viewport_dims)) {
LOG(ERROR) << "Fooey, No Gooey!\n";
return 1;
}
#if defined(_WIN32)
if (!platform_init(handles.window)) {
LOG(ERROR) << "Couldn't get SDL platform info, exiting\n";
@ -561,10 +579,10 @@ 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->grid.hex_array, g->entities, g->entity_count);
renderFrame(r, g->grid.hex_array, g->entities, g->entity_count);
if (r->is_debug_draw && g->grid.draw_mode == CONE_FILL)
renderDebug(g_polygon_select_vertices);
renderDebug(r, g_polygon_select_vertices);
renderGooey(handles, g->grid.draw_mode, r->is_debug_draw, g->grid.start_hex,
g->grid.current_hex, g->grid.is_selecting, getCameraPosition());

36
src/render_group.cpp

@ -1,4 +1,5 @@
#include <sstream> // TODO: remove this and make something in util.h
#include <cassert>
#include <cstdlib> // calloc
@ -23,7 +24,7 @@ bool convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals);
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,
rg_point_light* lights, uint num_lights,
bool update_vertex_data, bool update_color_data);
@ -74,6 +75,8 @@ rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char
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");
sp.lights_id = glGetUniformLocation(sp.program_id, "lights");
sp.num_lights_id = glGetUniformLocation(sp.program_id, "num_lights");
glDetachShader(sp.program_id, vertex_shader_id);
glDetachShader(sp.program_id, fragment_shader_id);
@ -138,6 +141,9 @@ rgInitEntity(Entity* e)
return true;
}
// TODO: this should be called more like, rgInitGLBuffer()
// NOTE: could also make internal by adding more utility function for eg)
// initHexGrid(), initDebugDraw()...
void
rgBufferData(gl_buffer* buffer, GLenum usage, GLenum target)
{
@ -147,13 +153,16 @@ rgBufferData(gl_buffer* buffer, GLenum usage, GLenum target)
}
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, bool update_color_data)
rgDraw(render_group* rg, glm::mat4 model_matrix,
glm::mat4 view_matrix, glm::mat4 projection_matrix,
rg_point_light* lights, uint num_lights,
bool update_vertex_data, bool update_color_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, update_vertex_data, update_color_data);
drawRenderObject(rg, rg->render_objects[i],
model_matrix, view_matrix, projection_matrix,
lights, num_lights,
update_vertex_data, update_color_data);
}
}
@ -284,7 +293,7 @@ convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals)
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,
rg_point_light* lights, uint num_lights,
bool update_vertex_data, bool update_color_data)
{
glUseProgram(rg->shader.program_id);
@ -323,9 +332,20 @@ drawRenderObject(render_group* rg, render_object* ro,
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);
// TODO: use Uniform Buffer Objects to update light data
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt
// https://www.khronos.org/opengl/wiki/Uniform_Buffer_Objects
glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model_matrix)));
glUniformMatrix3fv(rg->shader.normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]);
for (uint i = 0; i < num_lights; i++) {
// TODO: don't do this every frame * every render_group
std::stringstream ss;
ss << "lights[" << i << "].position";
int light_pos_loc = glGetUniformLocation(rg->shader.program_id, ss.str().c_str());
glUniform3fv(light_pos_loc, 1, &lights[i].position[0]);
}
}
// draw

20
src/render_group.h

@ -6,8 +6,8 @@
#include "entity.h"
#include "util.h"
struct Entity;
struct Entity;
// TODO: can these structs be used as opaque pointers?
struct gl_buffer
@ -40,6 +40,10 @@ struct rg_shader_program
GLuint projection_matrix_id = 0;
GLuint normal_matrix_id = 0;
GLuint vertex_array_id = 0;
// TODO: testing lighting changes
GLuint lights_id = 0;
GLuint num_lights_id = 0;
};
struct render_group
@ -52,6 +56,15 @@ struct render_group
GLenum draw_mode = GL_TRIANGLES;
};
// TODO: maybe pull out to seperate header
struct rg_point_light
{
uint light_ID;
glm::vec3 position;
glm::vec3 color;
float intensity;
};
// NOTE: initializes a render_group with 1 render_object allocated
render_group* rgInitSingle(rg_shader_program& sp, uint vertex_buffer_len,
bool use_normals = false, uint index_buffer_len = 0,
@ -61,12 +74,11 @@ bool rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const
bool rgInitEntity(Entity* e);
void
rgBufferData(gl_buffer* buffer, GLenum usage, GLenum target);
void rgBufferData(gl_buffer* buffer, GLenum usage, GLenum target);
void rgDraw(render_group* rg, glm::mat4 model_matrix,
glm::mat4 view_matrix, glm::mat4 projection_matrix,
glm::vec3 light_position, GLuint light_id,
rg_point_light* lights, uint num_lights,
bool update_vertex_data = false, bool update_color_data = false);
void rgFree(render_group* rg);

62
src/renderer.cpp

@ -58,6 +58,7 @@ void fillHexLineBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes);
// globals
// TODO: store scene_matrices on camera object
static gl_matrix_info g_scene_matrices;
static render_group* g_filled_hex_render_group;
static render_group* g_hex_line_render_group;
@ -67,11 +68,13 @@ static rg_shader_program g_default_shader;
static camera g_camera;
// TODO: testing lighting
static renPointLight g_test_light;
//static renPointLight g_test_light;
// TODO: maybe keep all these globals in the render_state object?
// interface
// TODO: maybe make this a contructor for render_state?
bool
initRenderer(SDL_Handles &handles, v2i vpDims)
{
@ -146,6 +149,21 @@ initRenderer(SDL_Handles &handles, v2i vpDims)
return true;
}
void
freeBuffers(render_state* rs)
{
utilSafeFree(rs->lights);
std::vector<render_group*> groups = {
g_filled_hex_render_group,
g_hex_line_render_group,
g_debug_render_group,
};
for (render_group* group : groups)
rgFree(group);
}
bool
addTexture(SDL_Handles &handles, const char * path)
{
@ -201,7 +219,7 @@ getCameraPosition()
}
bool
createScene(std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count)
createScene(render_state* rs, std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count)
{
// entities
@ -245,11 +263,16 @@ createScene(std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count)
// lights
// TODO: load light properties from scene/level files
g_test_light.light_ID = glGetUniformLocation(g_default_shader.program_id, "light_position");
g_test_light.position = glm::vec3(800, 300, 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;
// light testing
// TODO: allocate this in scene_loader... or initRenderer?
rs->lights = UTIL_ALLOC(rs->max_lights, rg_point_light);
#if 1
rs->lights[0].light_ID = 0;
rs->lights[0].position = glm::vec3(0.f, 0.f, 200.f);
rs->lights[0].color = glm::vec3(1.f, 1.f, 1.f);
rs->lights[0].intensity = 1.f;
rs->num_lights = 1;
#endif
return true;
}
@ -340,7 +363,7 @@ rollCamera(bool CW, bool CCW)
}
void
renderFrame(std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count)
renderFrame(render_state* rs, 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);
@ -356,21 +379,21 @@ renderFrame(std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count)
gl_buffer& color_buf = rg->render_objects[0]->color_buffer;
fillColorBuffer(color_buf.buffer, color_buf.buffer_len, hexes);
rgDraw(rg, m_model, m_view, m_projection,
g_test_light.position, g_test_light.light_ID, false, true);
rs->lights, rs->num_lights, false, true);
// hex lines
rgDraw(g_hex_line_render_group, m_model, m_view, m_projection,
g_test_light.position, g_test_light.light_ID);
rs->lights, rs->num_lights);
// entities
for (uint i = 0; i < entity_count; i++) {
rgDraw(entities[i].ren_group, entities[i].world_transform , m_view, m_projection,
g_test_light.position, g_test_light.light_ID);
rs->lights, rs->num_lights);
}
}
void
renderDebug(std::vector<Point> &vertices)
renderDebug(render_state* rs, std::vector<Point> &vertices)
{
GLfloat* buf = g_debug_render_group->render_objects[0]->vertex_buffer.buffer;
buf[0] = vertices[0].x; buf[1] = vertices[0].y; buf[2] = 0;
@ -379,20 +402,7 @@ renderDebug(std::vector<Point> &vertices)
buf[9] = vertices[3].x; buf[10] = vertices[3].y; buf[11] = 0;
rgDraw(g_debug_render_group, g_scene_matrices.model, g_scene_matrices.view,
g_scene_matrices.projection, g_test_light.position, g_test_light.light_ID, true);
}
void
freeBuffers()
{
std::vector<render_group*> groups = {
g_filled_hex_render_group,
g_hex_line_render_group,
g_debug_render_group,
};
for (render_group* group : groups)
rgFree(group);
g_scene_matrices.projection, rs->lights, rs->num_lights, true);
}

23
src/renderer.h

@ -24,32 +24,29 @@ struct SDL_Handles
std::vector<SDL_Surface*> texSurfaces;
};
struct rg_point_light;
struct render_state
{
v2i viewport_dims;
bool is_debug_draw;
};
struct renPointLight
{
glm::vec3 position;
glm::vec3 direction;
glm::vec3 color;
float intensity;
uint light_ID;
// TODO: testing lighting
rg_point_light* lights = nullptr;
uint num_lights = 0;
uint max_lights = 0;
};
bool initRenderer(SDL_Handles &handles, v2i vpDims);
void freeBuffers(render_state* rs);
bool addTexture(SDL_Handles &handles, const char * path);
camera& renGetCamera();
v2f getUnprojectedCoords(int32 x, int32 y, int32 vp_width, int32 vp_height);
v3f getCameraPosition();
bool createScene(std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count);
bool createScene(render_state* rs, std::vector<hex_info>* hexes, Entity* entities, uint32 entity_count);
void moveCamera(bool up, bool left, bool down, bool right, bool forward, bool backward);
void rollCamera(bool CW, bool CCW);
void rotateCamera(int32 xrel, int32 yrel);
void renderFrame(std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count);
void renderDebug(std::vector<Point> &vertices);
void freeBuffers();
void renderFrame(render_state* rs, std::vector<hex_info> *hexes, Entity* entities, uint32 entity_count);
void renderDebug(render_state* rs, std::vector<Point> &vertices);

7
src/scene_loader.cpp

@ -146,6 +146,13 @@ slParseHexGrid(slSceneDoc* sd, hexgrid& hg)
}
void
slParseLights(slSceneDoc* sd, rg_point_light* lights, uint& num_lights, uint max_lights)
{
//const rapidjson::Value& json_lights = (*sd->doc)["lights"];
}
// internal
bool

4
src/scene_loader.h

@ -1,6 +1,9 @@
#pragma once
#include "camera.h"
#include "hexgrid.h"
#include "render_group.h" // rg_point_light
#include "util.h"
@ -19,3 +22,4 @@ bool slParseEntities(
void slParseCamera(slSceneDoc* sd, camera& cam);
void slParseHexGrid(slSceneDoc* sd, hexgrid& hg);
void slParseLights(slSceneDoc* sd, rg_point_light* lights, uint& num_lights, uint max_lights);

2
src/util.cpp

@ -37,6 +37,8 @@ utilDumpTextFile(const char* filename)
void *
utilLogAlloc(uint item_count, uint type_size, const char* file_name, const int line)
{
assert(item_count > 0); // that was a fun bug
void* mem = std::calloc(item_count, type_size);
if (mem == nullptr) {

Loading…
Cancel
Save