#include "App.hpp" #include #include #include #include #include #include #include #include "LogUtils.hpp" #include "ShaderProgramBuilder.hpp" #include "stb_image.h" #include "TimestampLog.hpp" constexpr std::array, 36> getCubeVertices(); namespace ugly { int App::main(std::vector &args) { // Initialize global log. auto cerrLog = TimestampLog{"ugly::log", std::cerr}; log = LogAlias{&cerrLog}; log("hello, world! app started."); // Initialize GLFW. glfwSetErrorCallback(error_callback_s); glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Create GLFW window and OpenGL context for GLEW. auto window = glfwCreateWindow(640, 480, "uGLy", NULL, NULL); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; if(glewInit() != GLEW_OK) { log("glewInit() failed!"); } // Run app. auto app = App{window}; app.game_loop(); // Clean up. glfwTerminate(); glfwSetErrorCallback(NULL); log("app quitting."); return 0; } void App::error_callback_s(int error, const char *description) { log("(glfw error): {}", description); } void App::key_callback_s(GLFWwindow *window, int key, int scancode, int action, int mods) { auto app = static_cast(glfwGetWindowUserPointer(window)); app->key_callback(key, scancode, action, mods); } App::App(GLFWwindow *window): mpWindow{window}, mShaderProgram{} { // To allow key_callback_s to access member functions glfwSetWindowUserPointer(mpWindow, this); glfwSetKeyCallback(mpWindow, key_callback_s); // Prepare shader mShaderProgram = ShaderProgramBuilder{} .attachFromFile(GL_VERTEX_SHADER, "assets/shaders/shader.vert") .attachFromFile(GL_FRAGMENT_SHADER, "assets/shaders/shader.frag") .link(); GLint posAttrib = glGetAttribLocation(mShaderProgram, "inPosition"); GLint colorAttrib = glGetAttribLocation(mShaderProgram, "inColor"); glCreateVertexArrays(1, &mVAO); glBindVertexArray(mVAO); // Upload vertice attributes (position and color) const auto vertices = getCubeVertices(); GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), (void*)(&vertices), GL_STATIC_DRAW); // Vertex format = { x, y, z, r, g, b } glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), 0); glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float))); glEnableVertexAttribArray(posAttrib); glEnableVertexAttribArray(colorAttrib); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void App::game_loop() { // Generate view and projection tranforms int width, height; glfwGetWindowSize(mpWindow, &width, &height); auto projMatrix = glm::perspective(glm::radians(60.0f), float(width) / height, 0.01f, 1000.f); auto viewMatrix = glm::lookAt( glm::vec3{0.f, 0.f, 0.f}, glm::vec3{0.f, 0.f, 1.f}, glm::vec3{0.f, 1.f, 0.f} ); GLint matrixUniform = glGetUniformLocation(mShaderProgram, "inTransformation"); float startTime = glfwGetTime(); while(!glfwWindowShouldClose(mpWindow)) { glfwPollEvents(); // Rotate the cube each frame float dt = glfwGetTime() - startTime; auto modelMatrix = glm::identity(); modelMatrix = glm::translate(modelMatrix, glm::vec3{0.f, 0.f, 2.f}); modelMatrix = glm::rotate(modelMatrix, glm::radians(20.f * dt), glm::vec3{1.f, 1.f, 0.f}); auto finalMatrix = projMatrix * viewMatrix * modelMatrix; // Draw logic glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glUseProgram(mShaderProgram); glBindVertexArray(mVAO); glUniformMatrix4fv(matrixUniform, 1, GL_FALSE, glm::value_ptr(finalMatrix)); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); glUseProgram(0); glDisable(GL_DEPTH_TEST); glfwSwapBuffers(mpWindow); } } void App::key_callback(int key, int scancode, int action, int mods) { if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { glfwSetWindowShouldClose(mpWindow, GLFW_TRUE); } } } constexpr std::array, 36> getCubeVertices() { // The eight vertices of a cube const float cubeVertices[8][3] = { { -0.5f, -0.5f, -0.5f }, { -0.5f, +0.5f, -0.5f }, { +0.5f, +0.5f, -0.5f }, { +0.5f, -0.5f, -0.5f }, { -0.5f, -0.5f, +0.5f }, { -0.5f, +0.5f, +0.5f }, { +0.5f, +0.5f, +0.5f }, { +0.5f, -0.5f, +0.5f } }; // Color for each of the six faces const float cubeColors[6][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 1.0f } }; // Each face consists of two triangles, so 36 unique vertices total const int vertexIndices[36] = { 0, 1, 2, 2, 3, 0, // B 4, 5, 1, 1, 0, 4, // L 7, 6, 5, 5, 4, 7, // F 3, 2, 6, 6, 7, 3, // R 0, 3, 7, 7, 4, 0, // D 2, 1, 5, 5, 6, 2 // U }; // Construct an array suitable for OpenGL - concatenates position and color for each vertex // { x, y, z, r, g, b } std::array, 36> vertices; for(int i = 0; i < 36; i++) { vertices[i][0] = cubeVertices[vertexIndices[i]][0]; vertices[i][1] = cubeVertices[vertexIndices[i]][1]; vertices[i][2] = cubeVertices[vertexIndices[i]][2]; vertices[i][3] = cubeColors[i/6][0]; vertices[i][4] = cubeColors[i/6][1]; vertices[i][5] = cubeColors[i/6][2]; } return vertices; }