From b7e6f5af21108bd86a5d58382b02228524aedb0f Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Fri, 4 Dec 2020 16:07:33 -0500 Subject: [PATCH] add simple mesh, render object, and shader types --- examples/Makefile | 9 +- examples/assimp_loading/main.cpp | 8 +- examples/simple_mesh/main.cpp | 54 ++++++++++++ include/entity.h | 17 +++- include/lights.h | 2 +- include/mesh.h | 9 ++ include/render_object.h | 21 ++++- include/renderer.h | 11 +-- include/shader_program.h | 36 +++++++- src/default_shaders.cpp | 32 +++++++ src/entity.cpp | 67 +++++++++++++-- src/lights.cpp | 2 +- src/mesh.cpp | 10 +++ src/render_object.cpp | 61 +++++++++++-- src/renderer.cpp | 142 +++++++++++++++++-------------- src/shader_program.cpp | 134 ++++++++++++++++++++++------- 16 files changed, 489 insertions(+), 126 deletions(-) create mode 100644 examples/simple_mesh/main.cpp diff --git a/examples/Makefile b/examples/Makefile index 222aef6..0f871cc 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -7,7 +7,10 @@ LIB = ../build/libTangerine.a BINDIR = bin -all: mkdirs $(OBJDIR)/hello_world.o $(OBJDIR)/assimp_loading.o +all: mkdirs \ + $(OBJDIR)/hello_world.o \ + $(OBJDIR)/assimp_loading.o \ + $(OBJDIR)/simple_mesh.o .PHONY: all -include $(OBJDIR)/*.d @@ -24,6 +27,10 @@ $(OBJDIR)/assimp_loading.o: $(LIB) $(CXX) $(CXXFLAGS) -c -MMD assimp_loading/main.cpp -o $@ $(CXX) -o $(BINDIR)/assimp_loading $(LDFLAGS) $@ $(LIB) +$(OBJDIR)/simple_mesh.o: $(LIB) + $(CXX) $(CXXFLAGS) -c -MMD simple_mesh/main.cpp -o $@ + $(CXX) -o $(BINDIR)/simple_mesh $(LDFLAGS) $@ $(LIB) + clean: rm -rf $(OBJDIR)/* bin/* .PHONY: clean diff --git a/examples/assimp_loading/main.cpp b/examples/assimp_loading/main.cpp index 5874c47..1b6475d 100644 --- a/examples/assimp_loading/main.cpp +++ b/examples/assimp_loading/main.cpp @@ -4,8 +4,9 @@ #include "camera.h" #include "dumbLog.h" -#include "renderer.h" #include "entity.h" +#include "renderer.h" +#include "shader_program.h" void @@ -27,7 +28,8 @@ main() } // TODO: this needs to be more convenient - rs->render_groups = renAllocateGroup(1, *rs->default_shader); + shader_wrapper sw = { DEFAULT_SHADER, rs->default_shader, nullptr }; + rs->render_groups = renAllocateGroup(1, sw); rs->render_group_count = 1; entity& spaceship = rs->render_groups->entities[0]; @@ -48,7 +50,7 @@ main() // NOTE: testing assimp animation info logDebugAnimationInfo("../data/spaceship.glb"); - if (entInit(spaceship, "../data/spaceship.glb")) { + if (entInitModel(spaceship, "../data/spaceship.glb")) { // TODO: this should be handled in entInit entSetWorldPosition(spaceship, glm::vec3(0, 0, 0)); entScale(spaceship, glm::vec3(20, 20, 20)); diff --git a/examples/simple_mesh/main.cpp b/examples/simple_mesh/main.cpp new file mode 100644 index 0000000..7f6e6f9 --- /dev/null +++ b/examples/simple_mesh/main.cpp @@ -0,0 +1,54 @@ + +#include + +#include "dumbLog.h" +#include "mesh.h" +#include "renderer.h" + + +int +main() +{ + render_state* rs = renInit("simple mesh"); + + if (rs == nullptr) { + LOG(Error) << "Error Initialzing renderer\n"; + return 1; + } + + // TODO: this needs to be more convenient + shader_wrapper sw = { SIMPLE_SHADER, nullptr, rs->simple_shader }; + rs->render_groups = renAllocateGroup(1, sw); + rs->render_group_count = 1; + + entity& e = rs->render_groups->entities[0]; + // manually construct a simple mesh + simple_mesh mesh = {0}; + mesh.num_vertices = 4; + mesh.vertices = UTIL_ALLOC(mesh.num_vertices, glm::vec3); + mesh.vertices[0] = glm::vec3(-200, 0, 200); + mesh.vertices[1] = glm::vec3(-200, 0, -200); + mesh.vertices[2] = glm::vec3(200, 0, -200); + mesh.vertices[3] = glm::vec3(200, 0, 200); + mesh.vert_colors = UTIL_ALLOC(mesh.num_vertices, glm::vec3); + mesh.vert_colors[0] = glm::vec3(255, 0, 0); + mesh.vert_colors[1] = glm::vec3(255, 0, 0); + mesh.vert_colors[2] = glm::vec3(255, 0, 0); + mesh.vert_colors[3] = glm::vec3(255, 0, 0); + //initialize entity with new mesh + entInitSimpleMesh(e, mesh, GL_LINE_LOOP); + utilSafeFree(mesh.vertices); + utilSafeFree(mesh.vert_colors); + + cameraInitPerspective( + rs->cam, + glm::vec3(0, -500, 0), + glm::vec3(0, 0, 0), + glm::vec3(0,0,1) + ); + + renDoRenderLoop(rs); + + renShutdown(rs); + return 0; +} diff --git a/include/entity.h b/include/entity.h index 0e3f268..81ffb8b 100644 --- a/include/entity.h +++ b/include/entity.h @@ -7,19 +7,32 @@ #include "render_object.h" +enum mesh_group_type +{ + DEFAULT_MESHES = 0, + SIMPLE_MESH = 1 +}; + struct entity { glm::mat4 world_transform; + mesh_group_type mesh_type; + + simple_mesh mesh; + simple_render_object simple_ro; + GLenum draw_mode; + // TODO: should be a pointer into a global array of mesh_info(s) or // mesh_groups stored on the render_state object mesh_group meshes; - render_object* render_objs; uint ro_count; }; -bool entInit(entity& e, const char* model_path); +bool entInitModel(entity& e, const char* model_path); + +bool entInitSimpleMesh(entity& e, simple_mesh& mesh, GLenum draw_mode); void entFree(entity& e); diff --git a/include/lights.h b/include/lights.h index cb36ba5..e5cc141 100644 --- a/include/lights.h +++ b/include/lights.h @@ -30,5 +30,5 @@ void lightsOut(light_group* lights); bool lightsAdd(light_group* lights, glm::vec3 pos, glm::vec3 color, float intensity); -void lightsUpdate(light_group* lights, shader_program* shader); +void lightsUpdate(light_group* lights, default_shader_program* shader); diff --git a/include/mesh.h b/include/mesh.h index 06aa5c4..43bab56 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -34,6 +34,13 @@ struct mesh_group uint num_meshes; }; +struct simple_mesh +{ + glm::vec3* vertices; + glm::vec3* vert_colors; + uint num_vertices; +}; + bool meInitAssimp(); @@ -43,5 +50,7 @@ bool meLoadFromFile(mesh_group& mesh_group, const char* filepath); void meFreeMeshGroup(mesh_group& mesh_group); +void meFreeSimpleMesh(simple_mesh& mesh); + void meShutdownAssimp(); diff --git a/include/render_object.h b/include/render_object.h index 8db5b69..4a0fb2d 100644 --- a/include/render_object.h +++ b/include/render_object.h @@ -19,14 +19,31 @@ struct render_object GLuint normal_buffer_id; GLuint uv_buffer_id; GLuint index_buffer_id; - GLuint index_buffer_count; + uint index_buffer_count; +}; + +struct simple_render_object +{ + GLuint vertex_buffer_id; + GLuint vertex_color_buffer_id; + uint vertex_count; }; bool roInit(mesh_info* mi_in, render_object& ro_out); +bool roInitSimpleMesh(simple_mesh& mesh_in, simple_render_object& ro_out); + void roFree(render_object& ro); +void roFreeSimple(simple_render_object& ro); + void roDraw(render_object& ro, camera& cam, - shader_program& shader, + default_shader_program& shader, light_group* lights); + +void roDrawSimple(simple_render_object& ro, + camera& cam, + simple_shader_program& shader, + GLenum draw_mode); + diff --git a/include/renderer.h b/include/renderer.h index 91e0821..08dd84a 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -26,10 +26,11 @@ struct SDL_Handles // NOTE: array of entities rendered with the same shader program struct render_group { + // TODO: also needs to be resizable entity* entities; uint entity_count; - shader_program shader; + shader_wrapper shader; }; struct render_state @@ -44,7 +45,9 @@ struct render_state render_group* render_groups; uint render_group_count; - shader_program* default_shader; + default_shader_program* default_shader; + simple_shader_program* simple_shader; + light_group* lights; }; @@ -55,15 +58,13 @@ renInit(const char* title = "Tangerine", void renShutdown(render_state* rs); render_group* -renAllocateGroup(uint entity_count, shader_program shader); +renAllocateGroup(uint entity_count, shader_wrapper shader); -// typedef void (*frame_callback_fn) (render_state*); void renDoRenderLoop(render_state* rs, uint framerate = 60, frame_callback_fn cb_func = nullptr); -// void renRenderFrame(render_state* rs); diff --git a/include/shader_program.h b/include/shader_program.h index bf02fd6..5b95638 100644 --- a/include/shader_program.h +++ b/include/shader_program.h @@ -4,7 +4,7 @@ #include -struct shader_program +struct default_shader_program { GLuint program_id; @@ -18,6 +18,36 @@ struct shader_program GLuint num_lights_id; }; -shader_program* shaderInit(const char* vertex_code, const char* frag_code); +struct simple_shader_program +{ + GLuint program_id; + GLuint MVP_id; + GLuint vertex_array_id; +}; + +enum shader_type +{ + SIMPLE_SHADER = 0, + DEFAULT_SHADER = 1 +}; + +struct shader_wrapper +{ + shader_type type; + default_shader_program* default_shader; + simple_shader_program* simple_shader; +}; + + +// TODO: find a way to initialize different shaders with different +// uniform layouts with a single function +// look at using uniform blocks and retrieving locations with +// glGetUniformBlockIndex() and their size with glGetActiveUniformBlockiv() +// see chapter 2 in the red book +simple_shader_program* +shaderInitSimple(const char* vertex_code, const char* frag_code); + +default_shader_program* +shaderInitDefault(const char* vertex_code, const char* frag_code); -void shaderFree(shader_program* shader); +void shaderFree(uint program_id); diff --git a/src/default_shaders.cpp b/src/default_shaders.cpp index cdd38d4..c348848 100644 --- a/src/default_shaders.cpp +++ b/src/default_shaders.cpp @@ -13,6 +13,7 @@ uniform mat4 model; uniform mat4 view; uniform mat4 projection; + void main() { fragNormal = normal; @@ -62,3 +63,34 @@ void main() } )FS"; +const char* SIMPLE_VERTEX_SHADER = R"SVS( +#version 330 core + +layout (location = 0) in vec3 position; +layout (location = 1) in vec3 color; + +out vec3 frag_color; + +uniform mat4 MVP; + + +void main() +{ + frag_color = color; + gl_Position = MVP * vec4(position, 1); +} +)SVS"; + +const char* SIMPLE_FRAGMENT_SHADER = R"SFS( +#version 330 core + +in vec3 frag_color; + +out vec4 color; + + +void main() +{ + color = vec4(frag_color.rgb, 1); +} +)SFS"; diff --git a/src/entity.cpp b/src/entity.cpp index a461ce9..dafc092 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -10,23 +10,24 @@ // forward declarations -bool loadMeshIntoGL(entity& e); +void initDefaults(entity& e); +bool loadMeshesIntoGL(entity& e); +bool loadSimpleMeshIntoGL(entity& e); // interface bool -entInit(entity& e, const char* model_path) +entInitModel(entity& e, const char* model_path) { - e.world_transform = glm::mat4(1.0); - entScale(e, glm::vec3(1.0)); - entSetWorldPosition(e, glm::vec3(0, 0, 0)); + initDefaults(e); + e.mesh_type = DEFAULT_MESHES; if (meLoadFromFile(e.meshes, model_path)) { e.ro_count = e.meshes.num_meshes; e.render_objs = UTIL_ALLOC(e.ro_count, render_object); - if (loadMeshIntoGL(e)) + if (loadMeshesIntoGL(e)) return true; } @@ -34,10 +35,40 @@ entInit(entity& e, const char* model_path) return false; } +bool +entInitSimpleMesh(entity& e, simple_mesh& mesh, GLenum draw_mode) +{ + assert(mesh.num_vertices > 0); + initDefaults(e); + e.mesh_type = SIMPLE_MESH; + e.draw_mode = draw_mode; + + e.mesh.num_vertices = mesh.num_vertices; + e.mesh.vertices = UTIL_ALLOC(mesh.num_vertices, glm::vec3); + e.mesh.vert_colors = UTIL_ALLOC(mesh.num_vertices, glm::vec3); + + for (uint i = 0; i < mesh.num_vertices; i++) { + e.mesh.vertices[i] = mesh.vertices[i]; + e.mesh.vert_colors[i] = mesh.vert_colors[i]; + } + + if (loadSimpleMeshIntoGL(e)) + return true; + + entFree(e); + return false; +} + void entFree(entity& e) { - meFreeMeshGroup(e.meshes); + if (e.mesh_type == DEFAULT_MESHES) + meFreeMeshGroup(e.meshes); + + if (e.mesh_type == SIMPLE_MESH) { + meFreeSimpleMesh(e.mesh); + roFreeSimple(e.simple_ro); + } for (uint i = 0; i < e.ro_count; i++) roFree(e.render_objs[i]); @@ -75,8 +106,16 @@ entScale(entity& e, glm::vec3 v) // internal +void +initDefaults(entity& e) +{ + e.world_transform = glm::mat4(1.0); + entScale(e, glm::vec3(1.0)); + entSetWorldPosition(e, glm::vec3(0, 0, 0)); +} + bool -loadMeshIntoGL(entity& e) +loadMeshesIntoGL(entity& e) { for (uint i = 0; i < e.meshes.num_meshes; i++) { assert(e.render_objs != nullptr); @@ -94,3 +133,15 @@ loadMeshIntoGL(entity& e) return true; } +bool +loadSimpleMeshIntoGL(entity& e) +{ + assert(e.mesh.num_vertices > 0); + + if (roInitSimpleMesh(e.mesh, e.simple_ro)) + return true; + + LOG(Error) << "Error initializing render object\n"; + entFree(e); + return false; +} diff --git a/src/lights.cpp b/src/lights.cpp index c6bc9a3..340689a 100644 --- a/src/lights.cpp +++ b/src/lights.cpp @@ -37,7 +37,7 @@ lightsAdd(light_group* lights, glm::vec3 pos, glm::vec3 color, float intensity) } void -lightsUpdate(light_group* lights, shader_program* shader) +lightsUpdate(light_group* lights, default_shader_program* shader) { glUniform1ui(shader->num_lights_id, lights->num_lights); diff --git a/src/mesh.cpp b/src/mesh.cpp index 58c5113..2b3bf30 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -78,6 +78,16 @@ meFreeMeshGroup(mesh_group& mesh_group) mesh_group.meshes = nullptr; } +void +meFreeSimpleMesh(simple_mesh& mesh) +{ + utilSafeFree(mesh.vertices); + mesh.vertices = nullptr; + utilSafeFree(mesh.vert_colors); + mesh.vert_colors = nullptr; + mesh.num_vertices = 0; +} + void meShutdownAssimp() { diff --git a/src/render_object.cpp b/src/render_object.cpp index ab3d1df..8262daa 100644 --- a/src/render_object.cpp +++ b/src/render_object.cpp @@ -11,7 +11,8 @@ bool initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id); bool initGLIndexBuffer(uint* buffer, uint num_indices, GLuint& buffer_id); bool initGLTexture(const util_image image, GLuint& tex_id); inline void -updateMatrices(shader_program& shader, camera& cam, glm::mat4 node_xform); +updateMatrices(default_shader_program& shader, camera& cam, + glm::mat4 node_xform); inline void enableGLFloatBuffer(uint buffer_id, uint location); @@ -44,6 +45,25 @@ roInit(mesh_info* mi_in, render_object& ro_out) return false; } +bool +roInitSimpleMesh(simple_mesh& mesh_in, simple_render_object& ro_out) +{ + if (initGLFloatBuffer(mesh_in.vertices, + mesh_in.num_vertices, + ro_out.vertex_buffer_id) && + initGLFloatBuffer(mesh_in.vert_colors, + mesh_in.num_vertices, + ro_out.vertex_color_buffer_id)) + { + ro_out.vertex_count = mesh_in.num_vertices; + return true; + } + + LOG(Error) << "Failed to initialize render_object\n"; + roFreeSimple(ro_out); + return false; +} + void roFree(render_object& ro) { @@ -54,10 +74,17 @@ roFree(render_object& ro) glDeleteTextures(1, &ro.tex_id); } +void +roFreeSimple(simple_render_object& ro) +{ + glDeleteBuffers(1, &ro.vertex_buffer_id); + glDeleteBuffers(1, &ro.vertex_color_buffer_id); +} + void roDraw(render_object& ro, camera& cam, - shader_program& shader, + default_shader_program& shader, light_group* lights) { glUseProgram(shader.program_id); @@ -82,6 +109,22 @@ roDraw(render_object& ro, glUseProgram(0); } +void +roDrawSimple(simple_render_object& ro, + camera& cam, + simple_shader_program& shader, + GLenum draw_mode) +{ + glUseProgram(shader.program_id); + glUniformMatrix4fv(shader.MVP_id, 1, GL_FALSE, &cam.MVP[0][0]); + enableGLFloatBuffer(ro.vertex_buffer_id, 0); + enableGLFloatBuffer(ro.vertex_color_buffer_id, 1); + glDrawArrays(draw_mode, 0, ro.vertex_count); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glUseProgram(0); +} + // internal bool @@ -129,14 +172,18 @@ initGLTexture(const util_image image, GLuint& tex_id) // frame, maybe add another interface function in render_object to call from // renRenderFrame inline void -updateMatrices(shader_program& shader, camera& cam, glm::mat4 node_xform) +updateMatrices(default_shader_program& shader, + camera& cam, + glm::mat4 node_xform) { glUniformMatrix4fv(shader.model_matrix_id, 1, GL_FALSE, &node_xform[0][0]); glUniformMatrix4fv(shader.view_matrix_id, 1, GL_FALSE, &cam.view[0][0]); - glUniformMatrix4fv(shader.projection_matrix_id, 1, GL_FALSE, &cam.projection[0][0]); - - glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(cam.model))); - glUniformMatrix3fv(shader.normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); + glUniformMatrix4fv(shader.projection_matrix_id, 1, GL_FALSE, + &cam.projection[0][0]); + glm::mat3 normal_matrix = glm::transpose( + glm::inverse(glm::mat3(cam.model))); + glUniformMatrix3fv(shader.normal_matrix_id, 1, GL_FALSE, + &normal_matrix[0][0]); } inline void diff --git a/src/renderer.cpp b/src/renderer.cpp index 8e862e0..de2c761 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -25,14 +25,15 @@ // forward declarations -void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar* message, const void* userParam); -bool initSDL(SDL_Handles& handles); bool createWindow(const char* title, SDL_Handles& handles, glm::vec2& viewport_dims); bool initContext(SDL_Handles& handles); bool initGlOptions(); +bool initSDL(SDL_Handles& handles); +bool initShaders(render_state* rs); +void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message, const void* userParam); void setDefaults(render_state* rs, glm::vec2 viewport_dims); @@ -48,17 +49,10 @@ renInit(const char* title, glm::vec2 viewport_dims) createWindow(title, rs->handles, rs->viewport_dims) && initContext(rs->handles) && initGlOptions() && + initShaders(rs) && meInitAssimp()) { - rs->default_shader = - shaderInit(DEFAULT_VERTEX_SHADER, DEFAULT_FRAGMENT_SHADER); - - if (rs->default_shader != nullptr) { - return rs; - } else { - LOG(Error) << "shader loading failed\n"; - return nullptr; - } + return rs; } LOG(Error) << "renderer initialization failed, aborting\n"; @@ -68,23 +62,15 @@ renInit(const char* title, glm::vec2 viewport_dims) void renShutdown(render_state* rs) { - // TODO: need a nicer way to loop over entities and render_objects for (uint i = 0; i < rs->render_group_count; i++) { - render_group& rg = rs->render_groups[i]; - - for (uint j = 0; j < rg.entity_count; j++) { - entity& e = rg.entities[j]; - - for (uint k = 0; k < e.ro_count; k++) - roFree(e.render_objs[k]); - - utilSafeFree(e.render_objs); - } + for (uint j = 0; j < rs->render_groups[i].entity_count; j++) + entFree(rs->render_groups[i].entities[j]); - utilSafeFree(rg.entities); + utilSafeFree(rs->render_groups[i].entities); } - shaderFree(rs->default_shader); + shaderFree(rs->default_shader->program_id); + shaderFree(rs->simple_shader->program_id); lightsOut(rs->lights); utilSafeFree(rs->render_groups); utilSafeFree(rs->default_shader); @@ -95,7 +81,7 @@ renShutdown(render_state* rs) } render_group* -renAllocateGroup(uint entity_count, shader_program shader) +renAllocateGroup(uint entity_count, shader_wrapper shader) { assert(entity_count > 0); render_group* rg = UTIL_ALLOC(1, render_group); @@ -137,20 +123,34 @@ renDoRenderLoop(render_state* rs, uint framerate, frame_callback_fn cb_func) void renRenderFrame(render_state* rs) { - glClearColor(rs->clear_col.R, rs->clear_col.G, rs->clear_col.B, rs->clear_col.A); + glClearColor(rs->clear_col.R, + rs->clear_col.G, + rs->clear_col.B, + rs->clear_col.A); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + // TODO: need a nicer way to loop over entities and render_objects + // eg) entDraw() for (uint i = 0; i < rs->render_group_count; i++) { render_group& rg = rs->render_groups[i]; for (uint j = 0; j < rg.entity_count; j++) { entity& e = rg.entities[j]; - for (uint k = 0; k < e.ro_count; k++) { - roDraw(e.render_objs[k], + if (rg.shader.type == SIMPLE_SHADER) { + roDrawSimple(e.simple_ro, rs->cam, - rg.shader, - rs->lights); + *rg.shader.simple_shader, + e.draw_mode); + } + + if (rg.shader.type == DEFAULT_SHADER) { + for (uint k = 0; k < e.ro_count; k++) { + roDraw(e.render_objs[k], + rs->cam, + *rg.shader.default_shader, + rs->lights); + } } } } @@ -170,37 +170,6 @@ renAddLight(render_state* rs, glm::vec3 pos, glm::vec3 color, float intensity) // internal -void -openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar* message, const void* userParam) -{ - LOG((type == GL_DEBUG_TYPE_ERROR) ? Error : Debug) - << (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "") - << ", type: " << type - << ", severity: " << severity - << ", message: " << message << "\n"; -} - -bool -initSDL(SDL_Handles& handles) -{ - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - LOG(Error) << "Error, SDL_Init: " << SDL_GetError() << "\n"; - return false; - } - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - 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_GetCurrentDisplayMode(0, &handles.currentDisplayMode); - - return true; -} - bool createWindow(const char* title, SDL_Handles& handles, glm::vec2& viewport_dims) { @@ -275,6 +244,55 @@ initGlOptions() return true; } +bool +initSDL(SDL_Handles& handles) +{ + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + LOG(Error) << "Error, SDL_Init: " << SDL_GetError() << "\n"; + return false; + } + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + 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_GetCurrentDisplayMode(0, &handles.currentDisplayMode); + + return true; +} + +bool +initShaders(render_state* rs) +{ + rs->default_shader = + shaderInitDefault(DEFAULT_VERTEX_SHADER, DEFAULT_FRAGMENT_SHADER); + rs->simple_shader = + shaderInitSimple(SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER); + + if (rs->default_shader == nullptr || + rs->simple_shader == nullptr) + { + LOG(Error) << "shader loading failed\n"; + return false; + } else { + return true; + } +} + +void +openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message, const void* userParam) +{ + LOG((type == GL_DEBUG_TYPE_ERROR) ? Error : Debug) + << (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "") + << ", type: " << type + << ", severity: " << severity + << ", message: " << message << "\n"; +} + void setDefaults(render_state* rs, glm::vec2 viewport_dims) { diff --git a/src/shader_program.cpp b/src/shader_program.cpp index a75c407..0f11f7b 100644 --- a/src/shader_program.cpp +++ b/src/shader_program.cpp @@ -4,58 +4,130 @@ #include "util.h" -shader_program* -shaderInit(const char* vertex_code, const char* frag_code) +// forward declarations +bool checkShaderErrors(GLuint program_id); +void cleanUpShader(GLuint program_id, GLuint vs_id, GLuint fs_id); +bool compileProgram(GLuint& program_id_out, + GLuint& vs_id_out, + GLuint& fs_id_out, + const char* vertex_code, + const char* frag_code); + + +//interface + +default_shader_program* +shaderInitDefault(const char* vertex_code, const char* frag_code) { - shader_program* sp = UTIL_ALLOC(1, shader_program); + default_shader_program* sp = UTIL_ALLOC(1, default_shader_program); + GLuint vs_id = 0; + GLuint fs_id = 0; + + compileProgram(sp->program_id, vs_id, fs_id, vertex_code, frag_code); 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); - - glShaderSource(vertex_shader_id, 1, &vertex_code, NULL); - glShaderSource(fragment_shader_id, 1, &frag_code, NULL); - glCompileShader(vertex_shader_id); - glCompileShader(fragment_shader_id); - - sp->program_id = glCreateProgram(); - glAttachShader(sp->program_id, vertex_shader_id); - glAttachShader(sp->program_id, fragment_shader_id); - glLinkProgram(sp->program_id); + // assign uniforms 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"); + sp->projection_matrix_id = + glGetUniformLocation(sp->program_id, "projection"); + sp->normal_matrix_id = + glGetUniformLocation(sp->program_id, "normal_matrix"); sp->num_lights_id = glGetUniformLocation(sp->program_id, "num_lights"); sp->sampler_id = glGetUniformLocation(sp->program_id, "sampler"); - glDetachShader(sp->program_id, vertex_shader_id); - glDetachShader(sp->program_id, fragment_shader_id); - glDeleteShader(vertex_shader_id); - glDeleteShader(fragment_shader_id); + cleanUpShader(sp->program_id, vs_id, fs_id); + + if (!checkShaderErrors(sp->program_id)) { + glDeleteProgram(sp->program_id); + return nullptr; + } + + return sp; +} + +simple_shader_program* +shaderInitSimple(const char* vertex_code, const char* frag_code) +{ + simple_shader_program* sp = UTIL_ALLOC(1, simple_shader_program); + GLuint vs_id = 0; + GLuint fs_id = 0; + compileProgram(sp->program_id, vs_id, fs_id, vertex_code, frag_code); + // TODO: add to compile program? + glGenVertexArrays(1, &sp->vertex_array_id); + glBindVertexArray(sp->vertex_array_id); + + if (!checkShaderErrors(sp->program_id)) { + glDeleteProgram(sp->program_id); + return nullptr; + } + + return sp; +} +void +shaderFree(uint program_id) +{ + // TODO: can check for valid id here + glDeleteProgram(program_id); +} + + +// internal + +bool +checkShaderErrors(uint program_id) +{ GLint isLinked = 0; - glGetProgramiv(sp->program_id, GL_LINK_STATUS, &isLinked); - if (isLinked == GL_FALSE) { - GLint info_len = 0; - glGetProgramiv(sp->program_id, GL_INFO_LOG_LENGTH, &info_len); + GLint info_len = 0; + glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) { + glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_len); char* infoLog = UTIL_ALLOC(info_len, char); - glGetProgramInfoLog(sp->program_id, info_len, &info_len, &infoLog[0]); + glGetProgramInfoLog(program_id, info_len, &info_len, &infoLog[0]); LOG(Error) << infoLog << "\n"; utilSafeFree(infoLog); + glDeleteProgram(program_id); - glDeleteProgram(sp->program_id); - return nullptr; + return false; } - return sp; + return true; } void -shaderFree(shader_program* shader) +cleanUpShader(GLuint program_id, GLuint vs_id, GLuint fs_id) +{ + glDetachShader(program_id, vs_id); + glDetachShader(program_id, fs_id); + glDeleteShader(vs_id); + glDeleteShader(fs_id); +} + +bool +compileProgram(GLuint& program_id_out, + GLuint& vs_id_out, + GLuint& fs_id_out, + const char* vertex_code, + const char* frag_code) { - glDeleteProgram(shader->program_id); + vs_id_out = glCreateShader(GL_VERTEX_SHADER); + fs_id_out = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vs_id_out, 1, &vertex_code, NULL); + glShaderSource(fs_id_out, 1, &frag_code, NULL); + glCompileShader(vs_id_out); + glCompileShader(fs_id_out); + // TODO: can check for error here + + program_id_out = glCreateProgram(); + glAttachShader(program_id_out, vs_id_out); + glAttachShader(program_id_out, fs_id_out); + glLinkProgram(program_id_out); + // TODO: can check for error here + + return true; }