#include "App.hpp" #include #include #include #include #include #include #include "LogUtils.hpp" #include "ShaderProgramBuilder.hpp" #include "stb_image.h" #include "TimestampLog.hpp" 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{} { glfwSetWindowUserPointer(mpWindow, this); glfwSetKeyCallback(mpWindow, key_callback_s); float vertices[] = { // Position(3), Color(3), TexCoord(2) -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-left 1.0f, 1.0f, 0.0f, 0.f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-right 1.0f, -1.0f, 0.0f, 0.f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-right 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-right -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, // Bottom-left -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f // Top-left }; GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); GLuint shaderProgram = ShaderProgramBuilder{} .attachFromFile(GL_VERTEX_SHADER, "assets/shaders/shader.vert") .attachFromFile(GL_FRAGMENT_SHADER, "assets/shaders/shader.frag") .link(); glUseProgram(shaderProgram); mShaderProgram = shaderProgram; GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); int x, y, n; auto data = stbi_load("assets/textures/bliss.jpg", &x, &y, &n, 3); if(data == nullptr) { log("stbi_load() failed!"); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); stbi_image_free(data); GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); GLint posAttrib = glGetAttribLocation(shaderProgram, "inPos"); GLint colorAttrib = glGetAttribLocation(shaderProgram, "inColor"); GLint coordAttrib = glGetAttribLocation(shaderProgram, "inCoord"); glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), 0); glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void*)(3*sizeof(float))); glVertexAttribPointer(coordAttrib, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void*)(6*sizeof(float))); glEnableVertexAttribArray(posAttrib); glEnableVertexAttribArray(colorAttrib); glEnableVertexAttribArray(coordAttrib); } void App::game_loop() { GLint timeUniform = glGetUniformLocation(mShaderProgram, "time"); GLint modelUniform = glGetUniformLocation(mShaderProgram, "model"); GLint viewUniform = glGetUniformLocation(mShaderProgram, "view"); GLint projUniform = glGetUniformLocation(mShaderProgram, "proj"); int width, height; glfwGetWindowSize(mpWindow, &width, &height); auto projMatrix = glm::perspective(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} ); auto modelMatrix = glm::identity(); modelMatrix = glm::translate(modelMatrix, glm::vec3{0.f, 0.f, -.2f}); glUniformMatrix4fv(viewUniform, 1, GL_FALSE, glm::value_ptr(viewMatrix)); glUniformMatrix4fv(projUniform, 1, GL_FALSE, glm::value_ptr(projMatrix)); glUniformMatrix4fv(modelUniform, 1, GL_FALSE, glm::value_ptr(modelMatrix)); glEnable(GL_DEPTH_TEST); auto prevTime = glfwGetTime(); auto elapsed = 0.0; while(!glfwWindowShouldClose(mpWindow)) { glfwPollEvents(); auto now = glfwGetTime(); auto dt = now - prevTime; elapsed += dt; prevTime = now; modelMatrix = glm::rotate(modelMatrix, glm::radians(float(dt) * 18.0f), glm::vec3{0.08f, 0.05f, 1.f}); glUniformMatrix4fv(modelUniform, 1, GL_FALSE, glm::value_ptr(modelMatrix)); glUniform1f(timeUniform, 4.f * elapsed); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, 6); 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); } } }