#include #include #include #include #include #include #include #include #include #include "shader_testing.h" #include "dumpShader.inl" SDL_Window *g_window = 0; SDL_GLContext g_glContext; SDL_DisplayMode g_display_mode; transforms g_xforms; mesh g_cube_mesh; const u32 NUM_CUBES = 4; gl_mesh g_gl_cubes[NUM_CUBES]; glm::vec3 g_cube_locs[NUM_CUBES] = { glm::vec3(-10, 10, 0), glm::vec3(-10, -10, 0), glm::vec3( 10, 10, 0), glm::vec3( 10, -10, 0), }; 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 init() { 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; } bool loadShaderProgram(const char* vs, const char* fs, shader* s) { 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); 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); glDetachShader(s->prog_id, vs_id); glDetachShader(s->prog_id, fs_id); glDeleteShader(vs_id); glDeleteShader(fs_id); GLint is_linked = 0; glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked); return (is_linked == GL_TRUE); } return false; } transforms initXformUBO(shader* s, float fov, float near_clip_plane, float aspect_ratio, glm::vec3 cam_pos, glm::vec3 look_pos) { transforms xforms; 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); xforms.normal_xform = glm::mat4(1); glGenBuffers(1, &s->xforms_ubo_id); glBindBufferBase(GL_UNIFORM_BUFFER, 0, s->xforms_ubo_id); glBindBuffer(GL_UNIFORM_BUFFER, s->xforms_ubo_id); glBufferData(GL_UNIFORM_BUFFER, sizeof(xforms), &xforms, GL_STATIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); return xforms; }; 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 = (u32*) std::calloc(m.num_indices, sizeof(u32)); u32 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(u32)); return m; } gl_mesh loadGLMesh(shader* 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; 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); gm.model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); glUniformMatrix4fv( gm.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; } void loop(shader* s, gl_mesh* mesh_arr, u32 num_meshes) { 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); glUseProgram(s->prog_id); glBindBuffer(GL_UNIFORM_BUFFER, s->xforms_ubo_id); for (u32 i = 0; i < num_meshes; i++) { const gl_mesh& m = mesh_arr[i]; *m.model_xform = glm::rotate( *m.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0)); glBindVertexArray(m.vao_id); glUniformMatrix4fv( m.model_xform_id, 1, GL_FALSE, (float*) m.model_xform); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.idx_buf_id); glDrawElements(m.draw_mode, m.num_indices, GL_UNSIGNED_INT, 0); glBindVertexArray(0); } SDL_GL_SwapWindow(g_window); glUseProgram(0); frame_time = SDL_GetTicks() - frame_start; if (delay > frame_time) SDL_Delay(delay - frame_time); } } void quit(shader* s) { glDeleteProgram(s->prog_id); SDL_GL_DeleteContext(g_glContext); SDL_DestroyWindow(g_window); SDL_Quit(); for (u32 i = 0; i < NUM_CUBES; i++) { gl_mesh& c = g_gl_cubes[i]; if (c.model_xform != nullptr) free(c.model_xform); } mesh& cm = g_cube_mesh; if (cm.vertices != nullptr) free(cm.vertices); if (cm.normals != nullptr) free(cm.normals); if (cm.uvs != nullptr) free(cm.uvs); if (cm.colors != nullptr) free(cm.colors); if (cm.indices != nullptr) free(cm.indices); } int main() { if (!init()) return 1; shader s = {0}; if (loadShaderProgram("data/shader.vert", "data/shader.frag", &s)) { dumpShader(s.prog_id); g_xforms = initXformUBO(&s); g_cube_mesh = initCubeMesh(); for (u32 i = 0; i < NUM_CUBES; i++) { g_gl_cubes[i] = loadGLMesh(&s, g_cube_mesh, GL_TRIANGLES, g_cube_locs[i]); assert(g_gl_cubes[i].vao_id != 0); } loop(&s, g_gl_cubes, NUM_CUBES); quit(&s); return 0; } std::cout << "error loading shader program\n"; quit(&s); return 1; }