diff --git a/src/main.c b/src/main.c index d7f8ac4..a252231 100644 --- a/src/main.c +++ b/src/main.c @@ -15,17 +15,27 @@ #define STATUS_INTERVAL 0.5 #define PI 3.14159f +GLFWwindow* window; + GLuint program; +GLuint originProgram; +GLuint floorProgram; GLuint vertexArrayObject; +GLuint originVAO; + GLuint indexBuffer; +GLuint lineIndexBuffer; +GLuint floorIndexBuffer; GLuint initialWindowWidth = 800; GLuint initialWindowHeight = 600; GLfloat aspect; -mat4 projectionMatrix; +mat4 realProjectionMatrix; + +GLfloat currentHue = 0.0f; int frameCount = 0; struct timespec last_time, current_time; @@ -77,19 +87,19 @@ void updateStatusDisplay() { double fps = frameCount / elapsed; frameCount = 0; last_time = current_time; - printf("\rFPS: %.2f ", fps); + printf("\rFPS: %5.2f - currentValue: %5.2f", fps, currentHue); fflush(stdout); } } void recalculateProjectionMatrix() { - mat4BuildPerspective(projectionMatrix, 60 * M_PI / 180, aspect, 0.1, 10); + mat4BuildPerspective(realProjectionMatrix, 90 * M_PI / 180, aspect, 0.1, 50); DEBUG("Recalculating Projection Matrix"); } void init(void) { - INFO("Building Programs..."); + INFO("Building main program..."); ProgramLinkResult linkResult = buildShaderProgram("src/shaders/vertex.glsl", "src/shaders/fragment.glsl"); if (!linkResult.success) { FATAL("Failed to link Program"); @@ -98,6 +108,25 @@ void init(void) { program = linkResult.program; + + INFO("Building origin program..."); + linkResult = buildShaderProgram("src/shaders/origin-vertex.glsl", "src/shaders/origin-fragment.glsl"); + if (!linkResult.success) { + FATAL("Failed to link Program"); + exit(1); + } + + originProgram = linkResult.program; + + INFO("Building floor program..."); + linkResult = buildShaderProgram("src/shaders/floor-vertex.glsl", "src/shaders/floor-fragment.glsl"); + if (!linkResult.success) { + FATAL("Failed to link Program"); + exit(1); + } + + floorProgram = linkResult.program; + INFO("Shader Program Done."); // create triangle buffer @@ -158,6 +187,32 @@ void init(void) { 7, 3, 6 }; + GLuint lineIndices[] = { + 0, 1, + 0, 2, + 0, 4, + + 1, 3, + 1, 5, + + 2, 3, + 2, 6, + + 3, 7, + + 4, 5, + 4, 6, + + 5, 7, + + 6, 7 + }; + + GLuint floorIndices[] = { + 2, 3, 6, + 3, 7, 6 + }; + DEBUG("Creating vertext buffer"); GLuint vertexBuffer; glGenBuffers(1, &vertexBuffer); @@ -181,24 +236,79 @@ void init(void) { 0 // start offset ); glEnableVertexAttribArray(0); + glVertexAttribPointer( + 1, // 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(1); + + DEBUG("Creating index buffers"); + - 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); + + + + glGenBuffers(1, &lineIndexBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lineIndexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineIndices), lineIndices, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + + + glGenBuffers(1, &floorIndexBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, floorIndexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(floorIndices), floorIndices, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(0); - glClearColor(0.0f, 0.0f, 0.0f, 0.3f); + + glClearColor(0.3f, 0.3f, 0.4f, 1.0f); glViewport(0, 0, initialWindowWidth, initialWindowHeight); - glEnable(GL_CULL_FACE); + // glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + DEBUG("Creating origin vertex buffer"); + GLfloat originVertices[] = { + // X Y Z R G B + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f + }; + GLuint originVBO; + glGenBuffers(1, &originVBO); + glBindBuffer(GL_ARRAY_BUFFER, originVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(originVertices), originVertices, GL_STATIC_DRAW); + + glGenVertexArrays(1, &originVAO); + glBindVertexArray(originVAO); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat))); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, 0); + initialiseStatusDisplay(); recalculateProjectionMatrix(); @@ -206,15 +316,8 @@ void init(void) { INFO("--- Initialisation done ---"); } -GLfloat currentHue = 0.0f; - -void drawCube(vec3 position, mat4 initialModelMatrix, mat4 viewMatrix) { - mat4 modelMatrix; +void drawCube(mat4 modelMatrix, mat4 viewMatrix) { mat4 modelViewMatrix; - - mat4Translate(modelMatrix, initialModelMatrix, position); - - // combine model and view matrix to model-view matrix mat4Multiply(modelViewMatrix, viewMatrix, modelMatrix); // send modelView and projection matrix to shader @@ -227,52 +330,196 @@ void drawCube(vec3 position, mat4 initialModelMatrix, mat4 viewMatrix) { glDrawElements(GL_TRIANGLES, 48, GL_UNSIGNED_INT, 0); } +GLfloat clamp(GLfloat d, GLfloat min, GLfloat max) { + const GLfloat t = d < min ? min : d; + return t > max ? max : t; +} + +GLfloat mapTo01(GLfloat d, GLfloat min, GLfloat max) { + return (clamp(d, min, max) - min) * (1 / (max - min)); +} + void draw(void) { + // 0.0: virtual view + // 0.1 transition to real view + // 0.15 done + // 0.3 start view transformation + // 0.35 done + // 0.4 start projection + // 0.45 done updateStatusDisplay(); + mat4 identity; + mat4Identity(identity); + + mat4 projectionMatrix; + // mat4Interpolate(projectionMatrix, identity, projectionMatrix, mapTo01(currentHue, 0.0f, 0.1f)); + // counter for animation - currentHue += 0.0005f; + currentHue += 0.0001f; + int state = glfwGetKey(window, GLFW_KEY_SPACE); + if (state == GLFW_PRESS) + { + currentHue += 0.001f; + } if (currentHue > 1.0) currentHue = 0.0f; // clear colour and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // select program - glUseProgram(program); // build view matrix mat4 viewMatrix; // mat4Identity(viewMatrix); - vec3 cameraPos = {0.0f, 1.0f, 1.3f}; - vec3 cameraLookAt = {0.0f, 0.2f, 0.0f}; + vec3 cameraPos = {cos(currentHue * 6 * M_PI) * 3.0f, 3.0f + sin(currentHue * 12 * M_PI) * 0.5, sin(currentHue * 6 * M_PI) * 3.0f}; + vec3 cameraLookAt = {0.0f, 0.0f, 0.0f}; vec3 cameraUp = {0.0f, 1.0f, 0.0f}; mat4BuildLookAt(viewMatrix, cameraPos, cameraLookAt, cameraUp); + + vec3 virtualCameraPosition = {1.5f, 1.0f, 1.0f}; + vec3 virtualCameraLookAt = {0.0f, 0.0f, -1.0f}; + + // calculate virtual lookAt and projection + mat4 virtualCameraMatrix; + mat4 virtualProjectionMatrix; + mat4BuildLookAt(virtualCameraMatrix, virtualCameraPosition, virtualCameraLookAt, cameraUp); + mat4BuildPerspective(virtualProjectionMatrix, 60 * M_PI / 180, aspect, 1, 4); + + mat4 viewFrustumModelView; + mat4Inverse(viewFrustumModelView, virtualProjectionMatrix); + + mat3 mat3CameraRotationMatrix; + mat3From4(mat3CameraRotationMatrix, virtualCameraMatrix); + mat3Inverse(mat3CameraRotationMatrix, mat3CameraRotationMatrix); + mat4 cameraRotationMatrix; + mat4From3(cameraRotationMatrix, mat3CameraRotationMatrix); + + mat4Interpolate(projectionMatrix, virtualProjectionMatrix, realProjectionMatrix, mapTo01(currentHue, 0.1f, 0.15f)); + mat4Interpolate(viewMatrix, virtualCameraMatrix, viewMatrix, mapTo01(currentHue, 0.1f, 0.15f)); + + mat4Interpolate(projectionMatrix, projectionMatrix, virtualProjectionMatrix, mapTo01(currentHue, 0.7f, 0.75f)); + mat4Interpolate(viewMatrix, viewMatrix, virtualCameraMatrix, mapTo01(currentHue, 0.7f, 0.75f)); + + mat4Interpolate(virtualCameraMatrix, identity, virtualCameraMatrix, mapTo01(currentHue, 0.3f, 0.35f)); + mat4Interpolate(virtualProjectionMatrix, identity, virtualProjectionMatrix, mapTo01(currentHue, 0.4f, 0.45f) * mapTo01(currentHue, 0.4f, 0.45f)); + + mat4Interpolate(virtualCameraMatrix, virtualCameraMatrix, identity, mapTo01(currentHue, 0.7f, 0.75f)); + mat4Interpolate(virtualProjectionMatrix, virtualProjectionMatrix, identity, mapTo01(currentHue, 0.7f, 0.75f)); + + + + glUseProgram(program); + + GLuint brightnessLocation = glGetUniformLocation(program, "uBrightness"); + GLuint projectionLocation = glGetUniformLocation(program, "uProjection"); glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix); - - // build model Matrix + // cubes. mat4 modelMatrix; vec3 scale; vec3 position; - float scales[] = {0.5f, 0.4f, 0.3f, 0.2f, 0.1f, 0.09f, 0.08f, 0.07f, 0.06f, 0.05f}; - for (int i = 0; i < 10; i++) { - mat4Identity(modelMatrix); + // cube 1 + mat4Identity(modelMatrix); - vec3Set(scale, scales[i], 0.05f, scales[i]); - mat4Scale(modelMatrix, modelMatrix, scale); + vec3Set(scale, 0.5f, 0.5f, 0.5f); + mat4Scale(modelMatrix, modelMatrix, scale); - mat4RotateY(modelMatrix, modelMatrix, currentHue * 2 * M_PI + (i / 5.0f * M_PI)); + mat4RotateY(modelMatrix, modelMatrix, 0.5f); - vec3Set(position, 0.0f, i * 0.05f, 0.0f); - mat4Translate(modelMatrix, modelMatrix, position); + vec3Set(position, -0.3f, 0.5f, -0.4f); + mat4Translate(modelMatrix, modelMatrix, position); - drawCube(position, modelMatrix, viewMatrix); - } + mat4Multiply(modelMatrix, virtualCameraMatrix, modelMatrix); + mat4Multiply(modelMatrix, virtualProjectionMatrix, modelMatrix); + + glUniform1f(brightnessLocation, 1.0f); + drawCube(modelMatrix, viewMatrix); + + // cube 2 + mat4Identity(modelMatrix); + + vec3Set(scale, 0.3f, 0.3f, 0.3f); + mat4Scale(modelMatrix, modelMatrix, scale); + + mat4RotateY(modelMatrix, modelMatrix, 0.5f); + + vec3Set(position, -0.9f, 0.3f, -3.8f); + mat4Translate(modelMatrix, modelMatrix, position); + + mat4Multiply(modelMatrix, virtualCameraMatrix, modelMatrix); + mat4Multiply(modelMatrix, virtualProjectionMatrix, modelMatrix); + + glUniform1f(brightnessLocation, 1.0f); + drawCube(modelMatrix, viewMatrix); + + + // draw virtual camera + mat4Identity(modelMatrix); + + vec3Set(scale, 0.2f, 0.15f, 0.05f); + mat4Scale(modelMatrix, modelMatrix, scale); + + // apply rotations to camera + + mat4Multiply(modelMatrix, cameraRotationMatrix, modelMatrix); + + mat4Translate(modelMatrix, modelMatrix, virtualCameraPosition); + mat4Multiply(modelMatrix, virtualCameraMatrix, modelMatrix); + + glUniform1f(brightnessLocation, 0.0f); + if (currentHue < 0.37f) { + drawCube(modelMatrix, viewMatrix); + } + + + + glUseProgram(originProgram); + + projectionLocation = glGetUniformLocation(originProgram, "uProjection"); + glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix); + + GLuint modelViewLocation = glGetUniformLocation(originProgram, "uModelView"); + glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, viewMatrix); + + glBindVertexArray(originVAO); + glLineWidth(5.0f); + glDrawArrays(GL_LINES, 0, 6); + + if (currentHue > 0.35f && currentHue < 0.65) { + mat4Multiply(viewFrustumModelView, virtualProjectionMatrix, viewFrustumModelView); + mat4Multiply(viewFrustumModelView, viewMatrix, viewFrustumModelView); + + glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, viewFrustumModelView); + + glBindVertexArray(vertexArrayObject); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lineIndexBuffer); + glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); + } + + // draw floor + glUseProgram(floorProgram); + glBindVertexArray(vertexArrayObject); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, floorIndexBuffer); + + glUniformMatrix4fv(glGetUniformLocation(floorProgram, "uView"), 1, GL_FALSE, viewMatrix); + glUniformMatrix4fv(glGetUniformLocation(floorProgram, "uProjection"), 1, GL_FALSE, projectionMatrix); + + mat4 floorModelMatrix; + vec3 floorScale; + mat4Identity(floorModelMatrix); + vec3Set(floorScale, 10.0f, 0.01f, 10.0f); + mat4Scale(floorModelMatrix, floorModelMatrix, floorScale); + + glUniformMatrix4fv(glGetUniformLocation(floorProgram, "uModel"), 1, GL_FALSE, floorModelMatrix); + + glDepthMask(GL_FALSE); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glDepthMask(GL_TRUE); } @@ -303,9 +550,7 @@ int main(int argc, char const *argv[]) 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); + window = glfwCreateWindow(initialWindowWidth, initialWindowHeight, "CG1", NULL, NULL); aspect = (float)initialWindowWidth / initialWindowHeight; if (!window) { diff --git a/src/shaders/floor-fragment.glsl b/src/shaders/floor-fragment.glsl new file mode 100644 index 0000000..dc3a49e --- /dev/null +++ b/src/shaders/floor-fragment.glsl @@ -0,0 +1,8 @@ +#version 330 core + +in vec4 vPosition; + +void main() { + gl_FragColor = mix(vec4(1,1,1,0.5), vec4(0.8,0.8,0.8,0.5), step(0, sin(vPosition.x * 3.14159) * sin(vPosition.z * 3.14159))); + // gl_FragColor = vec4(1,0,0,1); +} \ No newline at end of file diff --git a/src/shaders/floor-vertex.glsl b/src/shaders/floor-vertex.glsl new file mode 100644 index 0000000..bb2d09a --- /dev/null +++ b/src/shaders/floor-vertex.glsl @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec3 aPosition; + +uniform mat4 uModel; +uniform mat4 uView; +uniform mat4 uProjection; + +out vec4 vPosition; + +void main() { + vPosition = uModel * vec4(aPosition, 1); + gl_Position = uProjection * uView * vPosition; +} \ No newline at end of file diff --git a/src/shaders/fragment.glsl b/src/shaders/fragment.glsl index 4d85599..4923ad7 100644 --- a/src/shaders/fragment.glsl +++ b/src/shaders/fragment.glsl @@ -8,8 +8,10 @@ vec3 colors[6] = vec3[6]( vec3(0.5, 1.0, 1.0) ); +uniform float uBrightness; + void main() { // hacky solution to give each side a different colour int side = gl_PrimitiveID / 2; - gl_FragColor = vec4(colors[side], 1.0); + gl_FragColor = vec4(colors[side] * uBrightness, 1.0); } \ No newline at end of file diff --git a/src/shaders/origin-fragment.glsl b/src/shaders/origin-fragment.glsl new file mode 100644 index 0000000..ce9466e --- /dev/null +++ b/src/shaders/origin-fragment.glsl @@ -0,0 +1,7 @@ +#version 330 core + +in vec3 vertexColor; + +void main() { + gl_FragColor = vec4(vertexColor, 1.0); +} \ No newline at end of file diff --git a/src/shaders/origin-vertex.glsl b/src/shaders/origin-vertex.glsl new file mode 100644 index 0000000..d49c4af --- /dev/null +++ b/src/shaders/origin-vertex.glsl @@ -0,0 +1,13 @@ +#version 330 core +layout (location = 0) in vec3 aPosition; +layout (location = 1) in vec3 aColor; + +uniform mat4 uModelView; +uniform mat4 uProjection; + +out vec3 vertexColor; + +void main() { + vertexColor = aColor; + gl_Position = uProjection * uModelView * vec4(aPosition, 1.0); +} \ No newline at end of file