diff --git a/Makefile b/Makefile index efa10f0..525e661 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SHELL = /bin/sh CXX = g++ -CXXFLAGS = -std=c++11 -g -ggdb3 -Wall -Isrc/ -I/usr/include/SDL2 +CXXFLAGS = -std=c++11 -g -ggdb3 -Og -Wall -Isrc/ -I/usr/include/SDL2 LDFLAGS = -lSDL2 -lGLEW -lGL OBJDIR = build SRCDIR = src diff --git a/src/dumpShader.inl b/src/dumpShader.inl index a84d0b0..0935dac 100644 --- a/src/dumpShader.inl +++ b/src/dumpShader.inl @@ -1,7 +1,7 @@ #include -#include "shader_testing.h" +#include "shader.h" const char* gl_enum_to_string(GLenum e); diff --git a/src/main.cpp b/src/main.cpp index 6e2dfae..3555da5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,198 +1,13 @@ -#include -#include -#include #include -#include -#include #include #include -#include #include #include "asset.h" -#include "shader_testing.h" +#include "shader.h" -#include "dumpShader.inl" - - -const float DEFAULT_FOV = 60.f; -const float NEAR_CLIP_PLANE = 5.f; -const float DEFAULT_ASPECT_RATIO = 16.f / 9.f; -const glm::vec3 DEFAULT_CAM_POS = { 0, 0, -30.f }; -const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 }; - -SDL_Window *g_window = 0; -SDL_GLContext g_glContext; -SDL_DisplayMode g_display_mode; - - -void -openglDebugCallback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam) -{ - std::cout << ((type == GL_DEBUG_TYPE_ERROR) ? "Error" : "Debug") - << (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "") - << ", type: " << type - << ", severity: " << severity - << ", message: " << message << "\n"; -} - -bool -initGraphics() -{ - g_window = SDL_CreateWindow( - "shader_testing", - SDL_WINDOWPOS_CENTERED_DISPLAY(0), - SDL_WINDOWPOS_CENTERED_DISPLAY(0), - 1280, - 720, - SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); - - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - std::cout << "error, sdl init: " << SDL_GetError() << "\n"; - return false; - } - - SDL_GL_SetSwapInterval(1); - 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, &g_display_mode); - - g_glContext = SDL_GL_CreateContext(g_window); - - if (!g_glContext) { - std::cout << "error creating context\n"; - return false; - } - - if (glewInit()) { - std::cout << "error initializing opengl\n"; - return false; - } - - std::cout << "opengl vendor: " << glGetString(GL_VENDOR) << "\n"; - std::cout << "opengl renderer: " << glGetString(GL_RENDERER) << "\n"; - std::cout << "opengl version: " << glGetString(GL_VERSION) << "\n"; - - glEnable(GL_DEPTH_TEST); - glEnable(GL_LINE_SMOOTH); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glEnable (GL_DEBUG_OUTPUT); - glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0); - - return g_window != nullptr; -} - -const std::string -dumpTextFile(const char* filepath) -{ - std::ifstream fs { filepath }; - std::string s { - std::istreambuf_iterator(fs), - std::istreambuf_iterator()}; - - if (!fs || !fs.good()) - std::cout << "error reading file, " << filepath << "\n"; - - return s; -} - -void -parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx) -{ - GLint unif_count; - glGetProgramiv(s->prog_id, GL_ACTIVE_UNIFORMS, &unif_count); - s->num_uniforms = unif_count; - s->uniforms = (gl_uniform*) arenaAllocateBlock( - arena, s->num_uniforms * sizeof(gl_uniform)); - - for (u32 i = 0; i < s->num_uniforms; i++) { - GLchar unif_name[256] = {0}; - GLsizei length; - GLint size; - GLenum type; - - glGetActiveUniform(s->prog_id, i, sizeof(unif_name), - &length, &size, &type, unif_name); - - s->uniforms[i].data_type = type; - s->uniforms[i].name = (char*) arenaAllocateBlock( - arena, (length + 1) * sizeof(char)); - std::strncpy(s->uniforms[i].name, unif_name, length); - - glGetActiveUniformsiv(s->prog_id, 1, &i, - GL_UNIFORM_BLOCK_INDEX, &s->uniforms[i].block_idx); - - // FIXME: testing idx == unif location - s->uniforms[i].idx = i; - GLuint location = glGetUniformLocation(s->prog_id, s->uniforms[i].name); - printf("idx: %d, loc: %d, block idx: %d \n", - i, location, s->uniforms[i].block_idx); - - - // TODO: get uniform.data_size from data_type - //printf("i: %d, uniform name: %s, l: %d \n", i, unif_name, length); - } - - GLint max_vert_ublocks; - GLint max_frag_ublocks; - GLint max_ublock_size; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max_vert_ublocks); - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &max_frag_ublocks); - glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_ublock_size); - printf("max vert uniform blocks: %d, max frag uniform blocks: %d," - "max uniform block size: %d bytes \n", - max_vert_ublocks, max_frag_ublocks, max_ublock_size); - GLint max_ubo_bindings; - glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &max_ubo_bindings); - printf("max uniform buffer object binding points: %d \n", max_ubo_bindings); -} - -gl_buffer -initTransforms(transforms* xforms, - GLContext* gl_ctx, - float fov = DEFAULT_FOV, - float near_clip_plane = NEAR_CLIP_PLANE, - float aspect_ratio = DEFAULT_ASPECT_RATIO, - glm::vec3 cam_pos = DEFAULT_CAM_POS, - glm::vec3 look_pos = DEFAULT_LOOK_POS) -{ - xforms->view_xform = glm::lookAt(cam_pos, look_pos, glm::vec3(0, 1, 0)); - xforms->proj_xform = glm::infinitePerspective( - glm::radians(fov), aspect_ratio, near_clip_plane); - - gl_buffer ubo = {0}; - glGenBuffers(1, &ubo.id); - ubo.target = GL_UNIFORM_BUFFER; - ubo.data_type = GL_FLOAT; - ubo.data_size = sizeof(*xforms); - glBindBuffer(GL_UNIFORM_BUFFER, ubo.id); - glBufferData(GL_UNIFORM_BUFFER, sizeof(*xforms), xforms, GL_DYNAMIC_DRAW); - - // NOTE: need to manually keep track of block bindings - glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &gl_ctx->max_binding_points); - glBindBufferBase(GL_UNIFORM_BUFFER, gl_ctx->binding_count, ubo.id); - ubo.binding_idx = gl_ctx->binding_count; - gl_ctx->binding_count++; - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - return ubo; -} mesh initCubeMesh() @@ -224,48 +39,18 @@ initCubeMesh() return m; } -gl_mesh -loadGLMesh(shader_program* s, - const mesh& m, - GLenum draw_mode, - const glm::vec3& pos) +shader_program* +getShaderByName(const char* name, ShaderArray* s_arr) { - gl_mesh gm = {0}; - gm.num_indices = m.num_indices; - gm.draw_mode = draw_mode; - // NOTE: okay to store shader_program pointer on gl_mesh here because we - // won't ever delete the shader - gm.shader = s; - - glUseProgram(s->prog_id); - glGenVertexArrays(1, &gm.vao_id); - glBindVertexArray(gm.vao_id); - - gm.model_xform = (glm::mat4*) std::calloc(1, sizeof(glm::mat4)); - *gm.model_xform = glm::translate(glm::mat4(1), pos); - glUniformMatrix4fv( - s->model_xform_id, 1, GL_FALSE, (float*) gm.model_xform); - - glGenBuffers(1, &gm.vert_buf_id); - glBindBuffer(GL_ARRAY_BUFFER, gm.vert_buf_id); - glBufferData(GL_ARRAY_BUFFER, - m.num_vertices * 3 * sizeof(GLfloat), - m.vertices, - GL_STATIC_DRAW); - glVertexAttribPointer(POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(POSITION); - - glGenBuffers(1, &gm.idx_buf_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gm.idx_buf_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - m.num_indices * sizeof(GLuint), - m.indices, - GL_STATIC_DRAW); - - glBindVertexArray(0); - glUseProgram(0); - - return gm; + u64 hash = utilFNV64a_str(name); + + for (u32 i = 0; i < s_arr->count; i++) { + if (utilFNV64a_str(s_arr->shaders[i].name) == hash) + return &s_arr->shaders[i]; + } + + std::cout << "shader not found, " << name << "\n"; + return nullptr; } shader_program* @@ -280,74 +65,42 @@ getShaderByID(ShaderArray* sarr, GLuint prog_id) return nullptr; } -void -loop(RenderState* rs) +// NOTE: equivalent to rgAppend() in libTangerine +model* +getModel(RenderState* rs, const char* filepath) { - u32 delay = 60; - u32 frame_start, frame_time; - bool running = true; - SDL_Event e; - - while (running) { - frame_start = SDL_GetTicks(); - - while (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT || - (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) - { - running = false; - break; - } - } - - glClearColor(0.2, 0.2, 0.2, 1); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - - for (u32 i = 0; i < rs->gl_mesh_arr->count; i++) { - gl_mesh& glm = rs->gl_mesh_arr->gl_meshes[i]; - *glm.model_xform = glm::rotate( - *glm.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0)); - - glUseProgram(glm.shader->prog_id); - glBindVertexArray(glm.vao_id); - glUniformMatrix4fv(glm.shader->model_xform_id, 1, GL_FALSE, - (float*) glm.model_xform); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glm.idx_buf_id); - glDrawElements( - glm.draw_mode, glm.num_indices, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); - } + model* mdl = assetGetCached(rs->assets, utilFNV64a_str(filepath)); - SDL_GL_SwapWindow(g_window); - glUseProgram(0); - frame_time = SDL_GetTicks() - frame_start; + if (!mdl) + mdl = assetLoadFromFile(rs->assets, rs->textures, rs->arena, filepath); - if (delay > frame_time) - SDL_Delay(delay - frame_time); - } + return mdl; } -void -quit(RenderState* rs) +bool +addGLMesh(gl_mesh_array* gma, gl_mesh* gm) { - if (rs->arena) - std::free(rs->arena); + if (gma->count < gma->max) { + // FIXME: wtf was I doing here? + gma->count++; - SDL_GL_DeleteContext(g_glContext); - SDL_DestroyWindow(g_window); - SDL_Quit(); + } + + return false; } -// NOTE: equivalent to rgAppend() in libTangerine -model* -getModel(RenderState* rs, const char* filepath) +gl_mesh* +getGLMesh(gl_mesh_array* gma) { - model* mdl = assetGetCached(rs->assets, utilFNV64a_str(filepath)); + if (gma->count < gma->max) { + gl_mesh* glm = &gma->gl_meshes[gma->count]; + gma->count++; - if (!mdl) - mdl = assetLoadFromFile(rs->assets, rs->textures, rs->arena, filepath); + return glm; + } - return mdl; + std::cout << "Error, gl_mesh_array is full\n"; + return nullptr; } ShaderArray* @@ -401,130 +154,82 @@ initRenderState(memory_arena* arena) rs->gl_ctx = initGLContext(arena); rs->xforms = (transforms*) arenaAllocateBlock(arena, sizeof(transforms)); + rs->handles = + (SDLHandles*) arenaAllocateBlock(arena, sizeof(SDLHandles)); rs->gl_mesh_arr = initGLMeshArray(arena, 256); } return rs; } -// TODO: clean up this function -bool -addShaderProgram(memory_arena* arena, - GLContext* gl_ctx, - const char* vs, - const char* fs, - const char* name) +void +openglDebugCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam) { - if (gl_ctx->shader_arr->count >= gl_ctx->shader_arr->max) { - std::cout << "ShaderArray full\n"; - return false; - } - - shader_program* s = &gl_ctx->shader_arr->shaders[gl_ctx->shader_arr->count]; - gl_ctx->shader_arr->count++; - - u32 name_len = std::strlen(name) + 1; - s->name = (char*) arenaAllocateBlock(arena, name_len); - std::strncpy(s->name, name, name_len); - - const u32 max_len = 256; - std::string hash_str = vs; - hash_str += fs; - s->hash = utilFNV64a_str(hash_str.substr(0, max_len).c_str()); - // FIXME: should probably check the hash here against other shaders loaded - - std::string vert = dumpTextFile(vs); - std::string frag = dumpTextFile(fs); - - if (vert.size() > 0 && frag.size() > 0) { - const char* vert_c = vert.c_str(); - const char* frag_c = frag.c_str(); - - GLuint vs_id = glCreateShader(GL_VERTEX_SHADER); - GLuint fs_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(vs_id, 1, &vert_c, NULL); - glShaderSource(fs_id, 1, &frag_c, NULL); - // TODO: both of these can fail - glCompileShader(vs_id); - glCompileShader(fs_id); - s->prog_id = glCreateProgram(); - glAttachShader(s->prog_id, vs_id); - glAttachShader(s->prog_id, fs_id); - - glLinkProgram(s->prog_id); - GLint is_linked = 0; - glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked); - - if (is_linked) { - s->model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); - - // FIXME: testing - // NOTE: set block binding for shader xforms uniform block - GLuint block_idx = glGetUniformBlockIndex(s->prog_id, "matrices"); - glUniformBlockBinding(s->prog_id, - block_idx, - gl_ctx->xform_ubo.binding_idx); - - // FIXME: fill out new shader extra uniforms and buffers here - dumpShader(s->prog_id); - printf("offset of RenderState.xforms: %lu bytes\n", - offsetof(RenderState, xforms)); - parseShaderUniforms(arena, s, gl_ctx); - /// - - glDetachShader(s->prog_id, vs_id); - glDetachShader(s->prog_id, fs_id); - glDeleteShader(vs_id); - glDeleteShader(fs_id); - - return true; - } - - printf("%s(), Error linking shader\n", __FUNCTION__); - return false; - } - - return false; + std::cout << ((type == GL_DEBUG_TYPE_ERROR) ? "Error" : "Debug") + << (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "") + << ", type: " << type + << ", severity: " << severity + << ", message: " << message << "\n"; } bool -addGLMesh(gl_mesh_array* gma, gl_mesh* gm) +initGraphics(SDLHandles* handles) { - if (gma->count < gma->max) { - // FIXME: wtf was I doing here? - gma->count++; + handles->window = SDL_CreateWindow( + "shader_testing", + SDL_WINDOWPOS_CENTERED_DISPLAY(0), + SDL_WINDOWPOS_CENTERED_DISPLAY(0), + 1280, + 720, + SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + std::cout << "error, sdl init: " << SDL_GetError() << "\n"; + return false; } - return false; -} + SDL_GL_SetSwapInterval(1); + 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->display_mode); -shader_program* -getShaderByName(const char* name, ShaderArray* s_arr) -{ - u64 hash = utilFNV64a_str(name); + handles->sdl_gl_ctx = SDL_GL_CreateContext(handles->window); - for (u32 i = 0; i < s_arr->count; i++) { - if (utilFNV64a_str(s_arr->shaders[i].name) == hash) - return &s_arr->shaders[i]; + if (!handles->sdl_gl_ctx) { + std::cout << "error creating context\n"; + return false; } - std::cout << "shader not found, " << name << "\n"; - return nullptr; -} + if (glewInit()) { + std::cout << "error initializing opengl\n"; + return false; + } -gl_mesh* -getGLMesh(gl_mesh_array* gma) -{ - if (gma->count < gma->max) { - gl_mesh* glm = &gma->gl_meshes[gma->count]; - gma->count++; + std::cout << "opengl vendor: " << glGetString(GL_VENDOR) << "\n"; + std::cout << "opengl renderer: " << glGetString(GL_RENDERER) << "\n"; + std::cout << "opengl version: " << glGetString(GL_VERSION) << "\n"; - return glm; - } + glEnable(GL_DEPTH_TEST); + glEnable(GL_LINE_SMOOTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - std::cout << "Error, gl_mesh_array is full\n"; - return nullptr; + glEnable (GL_DEBUG_OUTPUT); + glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0); + + return handles->window != nullptr; } bool @@ -563,15 +268,63 @@ loadScene(RenderState* rs) return true; } +void +loop(RenderState* rs) +{ + u32 delay = 60; + u32 frame_start, frame_time; + bool running = true; + SDL_Event e; + + while (running) { + frame_start = SDL_GetTicks(); + + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT || + (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) + { + running = false; + break; + } + } + + glClearColor(0.2, 0.2, 0.2, 1); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + for (u32 i = 0; i < rs->gl_mesh_arr->count; i++) { + gl_mesh& glm = rs->gl_mesh_arr->gl_meshes[i]; + *glm.model_xform = glm::rotate( + *glm.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0)); + renderVAO(&glm); + } + + SDL_GL_SwapWindow(rs->handles->window); + glUseProgram(0); + frame_time = SDL_GetTicks() - frame_start; + + if (delay > frame_time) + SDL_Delay(delay - frame_time); + } +} + +void +quit(RenderState* rs) +{ + SDL_GL_DeleteContext(rs->handles->sdl_gl_ctx); + SDL_DestroyWindow(rs->handles->window); + SDL_Quit(); + std::free(rs->arena); +} + int main() { - if (!initGraphics()) - return 1; - memory_arena* arena = arenaInit(DEFAULT_ARENA_SIZE); RenderState* rs = initRenderState(arena); + if (!initGraphics(rs->handles)) + return 1; + if (rs) { rs->gl_ctx->xform_ubo = initTransforms(rs->xforms, rs->gl_ctx); diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..1adfce8 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,262 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "asset.h" +#include "shader.h" + +#include "dumpShader.inl" + + +// NOTE: forward declarations + +const std::string dumpTextFile(const char* filepath); +void +parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx); + + +// NOTE: interface + +// TODO: clean up this function +bool +addShaderProgram(memory_arena* arena, + GLContext* gl_ctx, + const char* vs, + const char* fs, + const char* name) +{ + if (gl_ctx->shader_arr->count >= gl_ctx->shader_arr->max) { + std::cout << "ShaderArray full\n"; + return false; + } + + shader_program* s = &gl_ctx->shader_arr->shaders[gl_ctx->shader_arr->count]; + gl_ctx->shader_arr->count++; + + u32 name_len = std::strlen(name) + 1; + s->name = (char*) arenaAllocateBlock(arena, name_len); + std::strncpy(s->name, name, name_len); + + const u32 max_len = 256; + std::string hash_str = vs; + hash_str += fs; + s->hash = utilFNV64a_str(hash_str.substr(0, max_len).c_str()); + // FIXME: should probably check the hash here against other shaders loaded + + std::string vert = dumpTextFile(vs); + std::string frag = dumpTextFile(fs); + + if (vert.size() > 0 && frag.size() > 0) { + const char* vert_c = vert.c_str(); + const char* frag_c = frag.c_str(); + + GLuint vs_id = glCreateShader(GL_VERTEX_SHADER); + GLuint fs_id = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(vs_id, 1, &vert_c, NULL); + glShaderSource(fs_id, 1, &frag_c, NULL); + // TODO: both of these can fail + glCompileShader(vs_id); + glCompileShader(fs_id); + s->prog_id = glCreateProgram(); + glAttachShader(s->prog_id, vs_id); + glAttachShader(s->prog_id, fs_id); + + glLinkProgram(s->prog_id); + GLint is_linked = 0; + glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked); + + if (is_linked) { + s->model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); + + // FIXME: testing + // NOTE: set block binding for shader xforms uniform block + GLuint block_idx = glGetUniformBlockIndex(s->prog_id, "matrices"); + glUniformBlockBinding(s->prog_id, + block_idx, + gl_ctx->xform_ubo.binding_idx); + + // FIXME: fill out new shader extra uniforms and buffers here + dumpShader(s->prog_id); + printf("offset of RenderState.xforms: %lu bytes\n", + offsetof(RenderState, xforms)); + parseShaderUniforms(arena, s, gl_ctx); + /// + + glDetachShader(s->prog_id, vs_id); + glDetachShader(s->prog_id, fs_id); + glDeleteShader(vs_id); + glDeleteShader(fs_id); + + return true; + } + + printf("%s(), Error linking shader\n", __FUNCTION__); + return false; + } + + return false; +} + +void +renderVAO(gl_mesh* glmesh) +{ + glUseProgram(glmesh->shader->prog_id); + glBindVertexArray(glmesh->vao_id); + glUniformMatrix4fv(glmesh->shader->model_xform_id, 1, GL_FALSE, + (float*) glmesh->model_xform); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glmesh->idx_buf_id); + glDrawElements( + glmesh->draw_mode, glmesh->num_indices, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); +} + + +// NOTE: internal + +const std::string +dumpTextFile(const char* filepath) +{ + std::ifstream fs { filepath }; + std::string s { + std::istreambuf_iterator(fs), + std::istreambuf_iterator()}; + + if (!fs || !fs.good()) + std::cout << "error reading file, " << filepath << "\n"; + + return s; +} + +void +parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx) +{ + GLint unif_count; + glGetProgramiv(s->prog_id, GL_ACTIVE_UNIFORMS, &unif_count); + s->num_uniforms = unif_count; + s->uniforms = (gl_uniform*) arenaAllocateBlock( + arena, s->num_uniforms * sizeof(gl_uniform)); + + for (u32 i = 0; i < s->num_uniforms; i++) { + GLchar unif_name[256] = {0}; + GLsizei length; + GLint size; + GLenum type; + + glGetActiveUniform(s->prog_id, i, sizeof(unif_name), + &length, &size, &type, unif_name); + + s->uniforms[i].data_type = type; + s->uniforms[i].name = (char*) arenaAllocateBlock( + arena, (length + 1) * sizeof(char)); + std::strncpy(s->uniforms[i].name, unif_name, length); + + glGetActiveUniformsiv(s->prog_id, 1, &i, + GL_UNIFORM_BLOCK_INDEX, &s->uniforms[i].block_idx); + + // FIXME: testing idx == unif location + s->uniforms[i].idx = i; + GLuint location = glGetUniformLocation(s->prog_id, s->uniforms[i].name); + printf("idx: %d, loc: %d, block idx: %d \n", + i, location, s->uniforms[i].block_idx); + + + // TODO: get uniform.data_size from data_type + //printf("i: %d, uniform name: %s, l: %d \n", i, unif_name, length); + } + + GLint max_vert_ublocks; + GLint max_frag_ublocks; + GLint max_ublock_size; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max_vert_ublocks); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &max_frag_ublocks); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_ublock_size); + printf("max vert uniform blocks: %d, max frag uniform blocks: %d," + "max uniform block size: %d bytes \n", + max_vert_ublocks, max_frag_ublocks, max_ublock_size); + GLint max_ubo_bindings; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &max_ubo_bindings); + printf("max uniform buffer object binding points: %d \n", max_ubo_bindings); +} + +gl_buffer +initTransforms(transforms* xforms, + GLContext* gl_ctx, + float fov, + float near_clip_plane, + float aspect_ratio, + glm::vec3 cam_pos, + glm::vec3 look_pos) +{ + xforms->view_xform = glm::lookAt(cam_pos, look_pos, glm::vec3(0, 1, 0)); + xforms->proj_xform = glm::infinitePerspective( + glm::radians(fov), aspect_ratio, near_clip_plane); + + gl_buffer ubo = {0}; + glGenBuffers(1, &ubo.id); + ubo.target = GL_UNIFORM_BUFFER; + ubo.data_type = GL_FLOAT; + ubo.data_size = sizeof(*xforms); + glBindBuffer(GL_UNIFORM_BUFFER, ubo.id); + glBufferData(GL_UNIFORM_BUFFER, sizeof(*xforms), xforms, GL_DYNAMIC_DRAW); + + // NOTE: need to manually keep track of block bindings + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &gl_ctx->max_binding_points); + glBindBufferBase(GL_UNIFORM_BUFFER, gl_ctx->binding_count, ubo.id); + ubo.binding_idx = gl_ctx->binding_count; + gl_ctx->binding_count++; + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + return ubo; +} + +gl_mesh +loadGLMesh(shader_program* s, + const mesh& m, + GLenum draw_mode, + const glm::vec3& pos) +{ + gl_mesh gm = {0}; + gm.num_indices = m.num_indices; + gm.draw_mode = draw_mode; + // NOTE: okay to store shader_program pointer on gl_mesh here because we + // won't ever delete the shader + gm.shader = s; + + glUseProgram(s->prog_id); + glGenVertexArrays(1, &gm.vao_id); + glBindVertexArray(gm.vao_id); + + gm.model_xform = (glm::mat4*) std::calloc(1, sizeof(glm::mat4)); + *gm.model_xform = glm::translate(glm::mat4(1), pos); + glUniformMatrix4fv( + s->model_xform_id, 1, GL_FALSE, (float*) gm.model_xform); + + glGenBuffers(1, &gm.vert_buf_id); + glBindBuffer(GL_ARRAY_BUFFER, gm.vert_buf_id); + glBufferData(GL_ARRAY_BUFFER, + m.num_vertices * 3 * sizeof(GLfloat), + m.vertices, + GL_STATIC_DRAW); + glVertexAttribPointer(POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(POSITION); + + glGenBuffers(1, &gm.idx_buf_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gm.idx_buf_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + m.num_indices * sizeof(GLuint), + m.indices, + GL_STATIC_DRAW); + + glBindVertexArray(0); + glUseProgram(0); + + return gm; +} + diff --git a/src/shader_testing.h b/src/shader.h similarity index 70% rename from src/shader_testing.h rename to src/shader.h index d0dd985..3162c03 100644 --- a/src/shader_testing.h +++ b/src/shader.h @@ -1,6 +1,7 @@ #pragma once +#include #include #include @@ -115,6 +116,13 @@ struct light_array point_light* lights; }; +struct SDLHandles +{ + SDL_Window* window; + SDL_GLContext sdl_gl_ctx; + SDL_DisplayMode display_mode; +}; + struct RenderState { memory_arena* arena; @@ -122,6 +130,7 @@ struct RenderState texture_assets* textures; transforms* xforms; // NOTE: would be part of camera in libTangerine + SDLHandles* handles; GLContext* gl_ctx; gl_mesh_array* gl_mesh_arr; @@ -132,3 +141,29 @@ struct node; struct entity; struct animation; + +const float DEFAULT_FOV = 60.f; +const float NEAR_CLIP_PLANE = 5.f; +const float DEFAULT_ASPECT_RATIO = 16.f / 9.f; +const glm::vec3 DEFAULT_CAM_POS = { 0, 0, -30.f }; +const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 }; + + +bool addShaderProgram(memory_arena* arena, + GLContext* gl_ctx, + const char* vs, + const char* fs, + const char* name); +void renderVAO(gl_mesh* glmesh); +gl_mesh loadGLMesh(shader_program* s, + const mesh& m, + GLenum draw_mode, + const glm::vec3& pos); +gl_buffer initTransforms(transforms* xforms, + GLContext* gl_ctx, + float fov = DEFAULT_FOV, + float near_clip_plane = NEAR_CLIP_PLANE, + float aspect_ratio = DEFAULT_ASPECT_RATIO, + glm::vec3 cam_pos = DEFAULT_CAM_POS, + glm::vec3 look_pos = DEFAULT_LOOK_POS); +