From 1d33ac337927a28d0bf7451a6d4a28cfab0deb91 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Fri, 30 Nov 2018 15:25:06 -0500 Subject: [PATCH] update renderer to use an array of light objects --- Makefile | 2 +- data/default.fs | 19 ++++++++++++-- src/gooey.cpp | 4 +-- src/hexgame.cpp | 38 ++++++++++++++++++++------- src/render_group.cpp | 36 +++++++++++++++++++------ src/render_group.h | 20 +++++++++++--- src/renderer.cpp | 62 +++++++++++++++++++++++++------------------- src/renderer.h | 23 +++++++--------- src/scene_loader.cpp | 7 +++++ src/scene_loader.h | 4 +++ src/util.cpp | 2 ++ 11 files changed, 151 insertions(+), 66 deletions(-) diff --git a/Makefile b/Makefile index 44771ae..dae0f08 100644 --- a/Makefile +++ b/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 diff --git a/data/default.fs b/data/default.fs index 7d87f03..6a21be9 100644 --- a/data/default.fs +++ b/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); diff --git a/src/gooey.cpp b/src/gooey.cpp index f4fd52c..338292b 100644 --- a/src/gooey.cpp +++ b/src/gooey.cpp @@ -1,5 +1,5 @@ -#if defined (_WIN32) +#if defined (_WIN32) #include #else #include @@ -52,7 +52,7 @@ renderGooey(SDL_Handles &handles, HexDrawMode &mode, bool &is_debug, ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(handles.window); ImGui::NewFrame(); - + ImGuiWindowFlags window_flags = 0; window_flags |= ImGuiWindowFlags_NoTitleBar; window_flags |= ImGuiWindowFlags_NoScrollbar; diff --git a/src/hexgame.cpp b/src/hexgame.cpp index 0f23cc6..74d18dd 100644 --- a/src/hexgame.cpp +++ b/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 @@ -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()); diff --git a/src/render_group.cpp b/src/render_group.cpp index b6e071a..8920aec 100644 --- a/src/render_group.cpp +++ b/src/render_group.cpp @@ -1,4 +1,5 @@ +#include // TODO: remove this and make something in util.h #include #include // 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 diff --git a/src/render_group.h b/src/render_group.h index e5724ef..c2794d4 100644 --- a/src/render_group.h +++ b/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); diff --git a/src/renderer.cpp b/src/renderer.cpp index 363df69..f0c766d 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -58,6 +58,7 @@ void fillHexLineBuffer(GLfloat buf[], int len, std::vector* 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 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* hexes, Entity* entities, uint32 entity_count) +createScene(render_state* rs, std::vector* hexes, Entity* entities, uint32 entity_count) { // entities @@ -245,11 +263,16 @@ createScene(std::vector* 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 *hexes, Entity* entities, uint32 entity_count) +renderFrame(render_state* rs, std::vector *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 *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 &vertices) +renderDebug(render_state* rs, std::vector &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 &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 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); } diff --git a/src/renderer.h b/src/renderer.h index 2146ece..9e5f818 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -24,32 +24,29 @@ struct SDL_Handles std::vector 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* hexes, Entity* entities, uint32 entity_count); +bool createScene(render_state* rs, std::vector* 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 *hexes, Entity* entities, uint32 entity_count); -void renderDebug(std::vector &vertices); -void freeBuffers(); +void renderFrame(render_state* rs, std::vector *hexes, Entity* entities, uint32 entity_count); +void renderDebug(render_state* rs, std::vector &vertices); diff --git a/src/scene_loader.cpp b/src/scene_loader.cpp index f612364..4882778 100644 --- a/src/scene_loader.cpp +++ b/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 diff --git a/src/scene_loader.h b/src/scene_loader.h index dad960a..c9bcfc9 100644 --- a/src/scene_loader.h +++ b/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); diff --git a/src/util.cpp b/src/util.cpp index d222553..4582db2 100644 --- a/src/util.cpp +++ b/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) {