#include #include #include #include #include #include #include #include #include "shader.h" #include "log.h" #include "shader.h" #include "matrix-math.h" #define STATUS_INTERVAL 0.5 #define PI 3.14159f GLuint program; GLuint vertexArrayObject; GLuint indexBuffer; GLuint initialWindowWidth = 800; GLuint initialWindowHeight = 600; GLfloat aspect; mat4 projectionMatrix; int frameCount = 0; struct timespec last_time, current_time; typedef struct ColorRGB { GLfloat r; GLfloat g; GLfloat b; } ColorRGB; // Color Conversion Functions from https://gist.github.com/ciembor/1494530 GLfloat hueToRgb(GLfloat p, GLfloat q, GLfloat t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1./6) return p + (q - p) * 6 * t; if (t < 1./2) return q; if (t < 2./3) return p + (q - p) * (2./3 - t) * 6; return p; } // Color Conversion Functions from https://gist.github.com/ciembor/1494530 ColorRGB hslToRgb(GLfloat h, GLfloat s, GLfloat l) { ColorRGB result = {0, 0, 0}; if(0 == s) { result.r = result.g = result.b = l; // achromatic } else { float q = l < 0.5 ? l * (1 + s) : l + s - l * s; float p = 2 * l - q; result.r = hueToRgb(p, q, h + 1./3); result.g = hueToRgb(p, q, h); result.b = hueToRgb(p, q, h - 1./3); } return result; } void initialiseStatusDisplay() { clock_gettime(CLOCK_MONOTONIC, &last_time); } void updateStatusDisplay() { frameCount++; clock_gettime(CLOCK_MONOTONIC, ¤t_time); double elapsed = (current_time.tv_sec - last_time.tv_sec) + (current_time.tv_nsec - last_time.tv_nsec) / 1e9; if (elapsed >= STATUS_INTERVAL) { double fps = frameCount / elapsed; frameCount = 0; last_time = current_time; printf("\rFPS: %.2f ", fps); fflush(stdout); } } void recalculateProjectionMatrix() { mat4BuildPerspective(projectionMatrix, 60 * M_PI / 180, aspect, 0.1, 10); DEBUG("Recalculating Projection Matrix"); } void init(void) { INFO("Compiling Shaders..."); // create and compile vertex shader INFO("Compiling Vertex Shader..."); ShaderCompileResult vertexShader = readAndCompileShaderFromFile("src/shaders/vertex.glsl", GL_VERTEX_SHADER); if (!vertexShader.success) { FATAL("Failed to compile Vertex Shader"); exit(1); } // create and compile fragment shader INFO("Compiling Fragment Shader..."); ShaderCompileResult fragmentShader = readAndCompileShaderFromFile("src/shaders/fragment.glsl", GL_FRAGMENT_SHADER); if (!fragmentShader.success) { FATAL("Failed to compile Fragment Shader"); exit(1); } // create and link shader program INFO("Linking Shader Program..."); ProgramLinkResult linkResult = linkShaderProgram(vertexShader.shader, fragmentShader.shader); if (!linkResult.success) { FATAL("Failed to link Program"); exit(1); } program = linkResult.program; INFO("Shader Program Done."); // create triangle buffer /** * -0.35 0.35 * | -0.2 0.2 | * | | | | * * 0----1 4----5 --- 0.6 * | | | | * | | | | * | 2--------3 | --- 0.1 * | | * | 9--------8 | --- -0.1 * | | | | * | | | | * 11---10 7----6 --- -0.6 * * 12-----------------13 --- -0.7 * | | * 15-----------------14 --- -0.9 * */ GLfloat vertices[] = { // X // Y 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, }; GLuint restart = 128; glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(restart); GLuint indices[] = { 1, 0, 2, 1, 2, 3, 4, 0, 1, 5, 4, 1, 5, 1, 7, 1, 3, 7, 5, 7, 6, 4, 5, 6, 0, 4, 6, 2, 0, 6, 3, 2, 6, 7, 3, 6 }; DEBUG("Creating vertext buffer"); GLuint vertexBuffer; glGenBuffers(1, &vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); DEBUG("Creating vertex array object"); // create vertex array object glGenVertexArrays(1, &vertexArrayObject); glBindVertexArray(vertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); // vertex position data glVertexAttribPointer( 0, // shader location 3, // number of values to read GL_FLOAT, // type of value GL_FALSE, // if values are normalised 3 * sizeof(GLfloat), // stride - distance between vertices 0 // start offset ); glEnableVertexAttribArray(0); DEBUG("Creating index buffer"); glGenBuffers(1, &indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glClearColor(0.0f, 0.0f, 0.0f, 0.3f); glViewport(0, 0, initialWindowWidth, initialWindowHeight); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_DEPTH_TEST); initialiseStatusDisplay(); recalculateProjectionMatrix(); INFO("--- Initialisation done ---"); } GLfloat currentHue = 0.0f; void draw(void) { updateStatusDisplay(); currentHue += 0.0005f; if (currentHue > 1.0) currentHue = 0.0f; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(program); mat4 transformMatrix; vec3 scale = {0.2f, 0.2f, 0.2f}; vec3 position = {0.0f, 0.0f, -1.0f}; mat4Identity(transformMatrix); mat4Scale(transformMatrix, transformMatrix, scale); mat4RotateZ(transformMatrix, transformMatrix, currentHue * PI * 2); mat4RotateY(transformMatrix, transformMatrix, currentHue * PI * 2); mat4Translate(transformMatrix, transformMatrix, position); mat4 viewMatrix; mat4Identity(viewMatrix); vec3 cameraPos = {0.0f, 0.0f, 0.0f}; vec3 cameraLookAt = {0.0f, 0.0f, -1.0f}; vec3 cameraUp = {0.0f, 1.0f, 0.0f}; mat4BuildLookAt(viewMatrix, cameraPos, cameraLookAt, cameraUp); mat4 modelViewMatrix; mat4Multiply(modelViewMatrix, viewMatrix, transformMatrix); GLuint modelViewLocation = glGetUniformLocation(program, "uModelView"); glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, modelViewMatrix); GLuint projectionLocation = glGetUniformLocation(program, "uProjection"); glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix); glBindVertexArray(vertexArrayObject); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glDrawElements(GL_TRIANGLES, 48, GL_UNSIGNED_INT, 0); } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); aspect = (float)width / height; recalculateProjectionMatrix(); } int main(int argc, char const *argv[]) { for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-v") == 0) { logLevel = LOG_LEVEL_INFO; } if (strcmp(argv[i], "-vv") == 0) { logLevel = LOG_LEVEL_DEBUG; } } INFO("Creating GLFW Window"); glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER , GLFW_TRUE); GLFWwindow* window = glfwCreateWindow(initialWindowWidth, initialWindowHeight, "CG1", NULL, NULL); aspect = (float)initialWindowWidth / initialWindowHeight; if (!window) { FATAL("Failed to open window"); glfwTerminate(); return 1; } glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwMakeContextCurrent(window); glewInit(); init(); while (!glfwWindowShouldClose(window)) { draw(); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; }