#include #include #include #include #include "asset.h" #include "dumbLog.h" #include "GLDebug.h" #include "shader.h" #include "types.h" struct SDLHandles { SDL_Window* window; SDL_GLContext sdl_gl_ctx; SDL_DisplayMode display_mode; }; struct RenderState { memory_arena* arena; // FIXME: revert back to num_/max_(models|textures) model_assets* assets; texture_assets* textures; transforms* xforms; // NOTE: would be part of camera in libTangerine SDLHandles* handles; GLContext* gl_ctx; u32 num_gl_meshes; u32 max_gl_meshes; GLmesh* gl_meshes; u32 num_lights; u32 max_lights; PointLight* lights; }; mesh initCubeMesh() { mesh m = {0}; m.num_vertices = 8; m.vertices = (glm::vec3*) std::calloc(m.num_vertices, sizeof(glm::vec3)); m.vertices[0] = { -1, 1, -1 }; m.vertices[1] = { -1, -1, -1 }; m.vertices[2] = { 1, -1, -1 }; m.vertices[3] = { 1, 1, -1 }; m.vertices[4] = { -1, 1, 1 }; m.vertices[5] = { -1, -1, 1 }; m.vertices[6] = { 1, -1, 1 }; m.vertices[7] = { 1, 1, 1 }; m.num_indices = 36; // 6 sides, 2 tris per side, 3 verts per tri m.indices = (u16*) std::calloc(m.num_indices, sizeof(u16)); u16 indices[36] = { 0, 1, 2, 0, 2, 3, 3, 2, 6, 3, 6, 7, 7, 6, 5, 7, 5, 4, 4, 5, 0, 4, 1, 0, 0, 3, 4, 0, 3, 7, 1, 2, 5, 2, 6, 5 }; std::memcpy(m.indices, indices, m.num_indices * sizeof(u16)); return m; } shader_program* getShaderByName(const char* name, GLContext* gl_ctx) { u64 hash = utilFNV64a_str(name); for (u32 i = 0; i < gl_ctx->num_shaders; i++) { if (utilFNV64a_str(gl_ctx->shaders[i].name) == hash) return &gl_ctx->shaders[i]; } printf("%s(), shader not found, %s\n", __FUNCTION__, name); return nullptr; } shader_program* getShaderByID(GLContext* gl_ctx, GLuint prog_id) { for (u32 i = 0; i < gl_ctx->num_shaders; i++) { if (gl_ctx->shaders[i].prog_id) return &gl_ctx->shaders[i]; } printf("%s(), shader not found, %d\n", __FUNCTION__, prog_id); return nullptr; } // NOTE: equivalent to rgAppend() in libTangerine model* getModel(RenderState* rs, const char* filepath) { model* mdl = assetGetCached(rs->assets, utilFNV64a_str(filepath)); if (!mdl) mdl = assetLoadFromFile(rs->assets, rs->textures, rs->arena, filepath); return mdl; } GLmesh* getFreeGLMesh(RenderState* rs) { if (rs->num_gl_meshes < rs->max_gl_meshes) return &rs->gl_meshes[rs->num_gl_meshes++]; printf("%s(), Error, rs->gl_meshes is full\n", __FUNCTION__); return nullptr; } #define DEFAULT_SHADER_COUNT 64 #define DEFAULT_UBO_COUNT 32 GLContext* initGLContext(memory_arena* arena) { GLContext* gl_ctx = (GLContext*) arenaAllocateBlock(arena, sizeof(GLContext)); gl_ctx->max_shaders = DEFAULT_SHADER_COUNT; gl_ctx->num_shaders = 0; gl_ctx->shaders = (shader_program*) arenaAllocateBlock( arena, DEFAULT_SHADER_COUNT * sizeof(shader_program)); gl_ctx->max_ubos = DEFAULT_UBO_COUNT; gl_ctx->num_ubos = 0; gl_ctx->uniform_buffers = (gl_buffer*) arenaAllocateBlock(arena, gl_ctx->max_ubos * sizeof(gl_buffer)); gl_ctx->binding_count = 0; return gl_ctx; } RenderState* initRenderState(memory_arena* arena) { RenderState* rs = (RenderState*) arenaAllocateBlock(arena, sizeof(RenderState)); if (rs) { rs->arena = arena; rs->assets = assetInitModelBlock(arena, 256); rs->textures = assetInitTextureBlock(arena, 256); rs->gl_ctx = initGLContext(arena); rs->xforms = (transforms*) arenaAllocateBlock(arena, sizeof(transforms)); rs->handles = (SDLHandles*) arenaAllocateBlock(arena, sizeof(SDLHandles)); rs->max_gl_meshes = 256; rs->gl_meshes = (GLmesh*) arenaAllocateBlock( arena, rs->max_gl_meshes * sizeof(GLmesh)); } return rs; } bool initGraphics(SDLHandles* handles) { 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; } 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); handles->sdl_gl_ctx = SDL_GL_CreateContext(handles->window); if (!handles->sdl_gl_ctx) { 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 handles->window != nullptr; } bool loadScene(RenderState* rs) { mesh cube = initCubeMesh(); const u32 NUM_CUBES = 4; glm::vec3 cube_locs[NUM_CUBES] = { glm::vec3(-10, 10, 0), glm::vec3(-10, -10, 0), glm::vec3( 10, 10, 0), glm::vec3( 10, -10, 0), }; // TODO: full lighting model //model* tex_cube = getModel(rs, "data/textured_cube.gltf"); // TODO: load debug shader from libTangerine for textured_cube shader_program* s = getShaderByName("default", rs->gl_ctx); if (!s) return false; for (u32 i = 0; i < NUM_CUBES; i++) { GLmesh* gmesh = getFreeGLMesh(rs); if (!gmesh) return false; *gmesh = loadGLMesh(s, cube, GL_TRIANGLES, cube_locs[i]); if (gmesh->vao_id == 0) return false; } 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->num_gl_meshes; i++) { GLmesh& glm = rs->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() { memory_arena* arena = arenaInit(DEFAULT_ARENA_SIZE); RenderState* rs = initRenderState(arena); if (!initGraphics(rs->handles)) return 1; if (rs) { // FIXME: need to test this with another shader that has another UBO gl_buffer& ubo = rs->gl_ctx->uniform_buffers[rs->gl_ctx->num_ubos++]; initTransforms(arena, rs->xforms, &ubo, rs->gl_ctx); if (!addShaderProgram(arena, rs->gl_ctx, "../data/shader.vert", "../data/shader.frag", "default")) { LOG(Error) << "error loading shaders\n"; return 1; } if (!addShaderProgram(arena, rs->gl_ctx, "../data/colored_vertices.vert", "../data/colored_vertices.frag", "colored_vertices")) { LOG(Error) << "error loading shaders\n"; return 1; } if (!loadScene(rs)) { LOG(Error) << "error loading scene\n"; return 1; } loop(rs); quit(rs); return 0; } std::cout << "error loading scene\n"; return 1; }