diff --git a/src/Makefile b/src/Makefile index c7ad3f0..ff55831 100644 --- a/src/Makefile +++ b/src/Makefile @@ -28,6 +28,7 @@ LDFLAGS += $(shell pkg-config --libs SDL2_image) # TODO: only needed for gl3w, remove later LDFLAGS += -ldl +LDFLAGS += -lassimp all: $(OBJECTS) $(CXX) $(CXXFLAGS) -o hexgame hexgame.cpp $(LDFLAGS) $(OBJECTS) diff --git a/src/hexgame.cpp b/src/hexgame.cpp index 2bb8810..994a7ce 100644 --- a/src/hexgame.cpp +++ b/src/hexgame.cpp @@ -1,3 +1,10 @@ +/* + * TODO: + * - maybe start thinking about separating headers into different compilation units + * - add some sweet unit models + * - map generation + * - pathfinding + */ // Some defaults for the game layout #define HEX_SIZE 10 @@ -25,6 +32,7 @@ #include "hexlib.h" #include "renderer.h" #include "gooey.h" +#include "mesh.h" using std::vector; @@ -421,6 +429,7 @@ cleanUp(SDL_Handles &handles) freeBuffers(); // renderer.h for (SDL_Surface *surface : handles.texSurfaces) SDL_FreeSurface(surface); + shutdownAssimp(); // mesh.h IMG_Quit(); // SDL_image SDL_GL_DeleteContext(handles.glContext); SDL_DestroyWindow(handles.window); @@ -433,6 +442,21 @@ cleanUp(SDL_Handles &handles) delete g_game_state; } + // TODO: C-style memory management for entities + render_state* r = g_render_state; + if (r) { + // delete entities + for (uint i = 0; i < r->entity_count; i++) { + std::free(r->entities[i].vertices); + r->entities[i].vertices = nullptr; + } + + std::free(r->entities); + r->entities = nullptr; + delete r; + r = nullptr; + } + return true; } @@ -497,8 +521,24 @@ int main(int argc, char* argv[]) return 1; } } + + if (!initAssimp()) + { + LOG(ERROR) << "Error initializing assimp\n"; + return 1; + } + + { + // TODO: keep better track of entity memory + Entity* e = (Entity*) std::calloc(1, sizeof(Entity)); + e->num_vertices = getVertexCount(); + e->vertices = (glm::vec3 *) std::calloc(e->num_vertices, sizeof(glm::vec3)); + convertMesh(e); + g_render_state->entities = e; + g_render_state->entity_count++; + } - if (!createScene(g_game_state->hex_array)) + if (!createScene(g_game_state->hex_array, g_render_state->entities, g_render_state->entity_count)) { LOG(ERROR) << "Error in vertex data, exiting\n"; return 1; diff --git a/src/hexgame.h b/src/hexgame.h index 37a1d7a..e6533cc 100644 --- a/src/hexgame.h +++ b/src/hexgame.h @@ -11,6 +11,7 @@ #include #endif #include "aixlog.hpp" +#include // vec3 #include "hexlib.h" @@ -75,12 +76,22 @@ enum HexDrawMode PATHFINDING }; +struct Entity +{ + glm::mat4 model_transform; + glm::vec3 *vertices = nullptr; + uint num_vertices = 0; +}; + struct render_state { v2i viewport_dims; bool is_debug_draw; uint32 fill_color; uint32 selected_fill_color; + + uint32 entity_count = 0; + Entity* entities = nullptr; }; struct game_state @@ -107,7 +118,7 @@ struct game_state game_state(Layout &l) : hex_layout(l) {} }; -real32 +inline real32 SafeRatio(real32 dividend, real32 divisor) { if (divisor == 0) @@ -116,7 +127,7 @@ SafeRatio(real32 dividend, real32 divisor) return dividend / divisor; } -int32 +inline int32 SafeTruncateToInt32(int64 val) { assert(val <= INT32_MAX && val >= INT32_MIN); diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 0000000..73813fe --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,80 @@ +/* + * mesh.h + * - wrapper for assimp http://www.assimp.org + */ + +#pragma once + +#include + +#include // vec3 + +#include +#include +#include + +#include "aixlog.hpp" + +#include "hexgame.h" + + +/* the global Assimp scene object */ +const aiScene* g_scene = NULL; + +bool +initAssimp() +{ + /* get a handle to the predefined STDOUT log stream and attach + * it to the logging system. It remains active for all further + * calls to aiImportFile(Ex) and aiApplyPostProcessing. */ + aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); + aiAttachLogStream(&stream); + + g_scene = aiImportFile("../data/animated.block.dae", aiProcessPreset_TargetRealtime_MaxQuality); + + if (g_scene->mNumMeshes != 1) { + LOG(ERROR) << "We Can only handle 1 mesh per entity atm\n"; + return false; + } + + return true; +} + +uint +getVertexCount() +{ + assert(g_scene); + return g_scene->mMeshes[0]->mNumVertices; +} + +// copy data from assimp for use in our renderer +Entity* +convertMesh(Entity* e) +{ + assert(g_scene); + uint numVertices = getVertexCount(); + assert(e && e->num_vertices == numVertices); + + // copy vertices + for (uint i = 0; i < numVertices; i++) { + aiVector3D v_in = g_scene->mMeshes[0]->mVertices[i]; + glm::vec3 &v_out = e->vertices[i]; + v_out.x = v_in.x; + v_out.y = v_in.y; + v_out.z = v_in.z; + } + + return e; +} + +void +shutdownAssimp() +{ + + /* cleanup - calling 'aiReleaseImport' is important, as the library + keeps internal resources until the scene is freed again. Not + doing so can cause severe resource leaking. */ + aiReleaseImport(g_scene); + aiDetachAllLogStreams(); +} + diff --git a/src/renderer.h b/src/renderer.h index 5101300..5df4941 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -97,9 +97,9 @@ struct camera typedef struct gl_buffer { - GLuint buffer_id; - size_t buffer_len; // NOTE: number of elements in buffer - GLfloat* buffer; + GLuint buffer_id = 0; + size_t buffer_len = 0; // NOTE: number of elements in buffer + GLfloat* buffer = nullptr; } gl_buffer; typedef struct gl_render_group @@ -107,22 +107,23 @@ typedef struct gl_render_group // NOTE: For now the renderFrame function will assume these are the same size gl_buffer vertex_buffer; gl_buffer color_buffer; - GLuint program_id; - GLuint matrix_id; // NOTE: reference to a vertex shader's MVP matrix uniform - GLuint vertex_array_id; + GLuint program_id = 0; + GLuint matrix_id = 0; // NOTE: reference to a vertex shader's MVP matrix uniform + GLuint vertex_array_id = 0; } gl_render_group; 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; // Interface bool initRenderer(SDL_Handles &handles, v2i vpDims); bool addTexture(SDL_Handles &handles, const char * path); -bool createScene(std::vector* hexes); +bool createScene(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); @@ -155,8 +156,10 @@ initRenderer(SDL_Handles &handles, v2i vpDims) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); + // TODO: Line drawing quality seems to depend on graphics driver whims + // maybe try using textured billboards instead? + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); SDL_GL_SetSwapInterval(1); // vsync SDL_GetCurrentDisplayMode(0, &handles.currentDisplayMode); handles.window = @@ -212,6 +215,7 @@ initRenderer(SDL_Handles &handles, v2i vpDims) initShaderProgram(g_filled_hex_render_group, VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE, "MVP"); initShaderProgram(g_hex_line_render_group, VERTEX_SHADER_CODE, LINE_FRAGMENT_SHADER_CODE, "MVP"); initShaderProgram(g_debug_render_group, VERTEX_SHADER_CODE, DEBUG_FRAGMENT_SHADER_CODE, "MVP"); + initShaderProgram(g_entity_render_group, VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE, "MVP"); return true; } @@ -347,7 +351,7 @@ initMatrices(projection_type p) } bool -createScene(std::vector* hexes) +createScene(std::vector* hexes, Entity* entities, uint32 entity_count) { initMatrices(PROJ_TYPE); @@ -392,9 +396,11 @@ createScene(std::vector* hexes) return false; // free temporary buffers + // TODO: temp buffers won't be freed if exit early is hit std::free(vbuf); std::free(cbuf); std::free(line_buf); + vbuf = cbuf = line_buf = nullptr; // debug draw vertexes @@ -403,6 +409,50 @@ createScene(std::vector* hexes) if (!initGLBufferObject(&g_debug_render_group.vertex_buffer, len, GL_DYNAMIC_DRAW, 0)) return false; + + /////////////// + // TODO: Testing Entities/assimp model loading + + // g_entity_render_group + + uint entity_buf_len = entities[0].num_vertices * 3; + GLfloat* entity_buf = (GLfloat*) std::calloc(entity_buf_len, sizeof(GLfloat)); + GLfloat* entity_color_buf = (GLfloat*) std::calloc(entity_buf_len, sizeof(GLfloat)); + + // dump vertices into temporary buffer + uint vertex_index = 0; + uint vertex_prop_index = 0; + GLfloat entity_test_color[3]; + convertColor(entity_test_color, 0x565656FF); + + for (uint j = 0; j < entity_buf_len; j++) { + const glm::vec3& vertex = entities[0].vertices[vertex_index]; + + switch (vertex_prop_index) { + case 0: entity_buf[j] = vertex.x; break; + case 1: entity_buf[j] = vertex.y; break; + case 2: entity_buf[j] = vertex.z; break; + } + + entity_color_buf[j] = entity_test_color[vertex_prop_index]; + vertex_prop_index++; + + if (vertex_prop_index == 3) { + vertex_prop_index = 0; + vertex_index++; + } + } + + if (!initGLBufferObject(&g_entity_render_group.vertex_buffer, entity_buf_len, + GL_DYNAMIC_DRAW, entity_buf)) + return false; + + std::free(entity_buf); + std::free(entity_color_buf); + entity_buf = entity_color_buf = nullptr; + + ///////// + return true; } @@ -692,6 +742,9 @@ renderFrame(std::vector *hexes) // hex lines drawRenderGroup(&g_hex_line_render_group, GL_LINES); + + // TODO: testing entity rendering + drawRenderGroup(&g_entity_render_group, GL_TRIANGLES); } void @@ -719,7 +772,8 @@ freeBuffers() std::vector groups = { g_filled_hex_render_group, g_hex_line_render_group, - g_debug_render_group + g_debug_render_group, + //g_entity_render_group TODO: handle enitiy memory separately }; for (gl_render_group group : groups)