diff --git a/u07/Makefile b/u07/Makefile new file mode 100644 index 0000000..d0098bc --- /dev/null +++ b/u07/Makefile @@ -0,0 +1,33 @@ +GLEW_LIBS = $(shell pkgconf glew --libs) +GLFW_LIBS = $(shell pkgconf glfw3 --libs) +OTHER_LIBS = -lm + +ALL_LIBS = $(GLEW_LIBS) $(GLFW_LIBS) $(OTHER_LIBS) + +OBJ = matrixMath.o transformation.o wavefrontobj.o +SHADERS = fragmentShader.c vertexShader.c + +cg1.out: main.o $(OBJ) $(SHADERS) + gcc -o $@ main.o $(OBJ) $(ALL_LIBS) + +test.out: test.o $(OBJ) + gcc -o $@ test.o $(OBJ) $(ALL_LIBS) + +%Shader.c: %Shader.glsl + xxd -i $? > $@ + +main.o: $(SHADERS) matrixMath.h transformation.h wavefrontobj.h + +test.o: matrixMath.h transformation.h wavefrontobj.h + +%.o: %.c + gcc -c $< + +run: cg1.out + ./cg1.out + +test: test.out + ./test.out + +clean: + rm $(SHADERS) main.o test.o $(OBJ) cg1.out test.out \ No newline at end of file diff --git a/u07/fragmentShader.glsl b/u07/fragmentShader.glsl new file mode 100644 index 0000000..1a16084 --- /dev/null +++ b/u07/fragmentShader.glsl @@ -0,0 +1,43 @@ +#version 330 core + +in vec3 normal; +in vec3 fragmentPosition; + + +uniform vec4 ambientColor; +uniform vec4 diffusionColor; +uniform vec4 specularColor; + +uniform float shininess; + +uniform vec4 ambientLight; +uniform vec3 lightPosition; +uniform vec4 lightColor; + + +float emissionStrength = 0.0; + + +void main() { + vec3 norm = normalize(normal); + vec3 lightDir = normalize(lightPosition - fragmentPosition); + vec3 eyeDir = -normalize(fragmentPosition); + + float diff = max(dot(norm, lightDir), 0.0); + + vec3 halfway = (lightDir + eyeDir) / length(lightDir + eyeDir); + float specular = pow(max(dot(halfway, norm), 0.0), shininess); + + gl_FragColor = + // EMISSION + diffusionColor * emissionStrength + + + // // AMBIENT + ambientLight * ambientColor + + + // DIFFUSION + diff * lightColor * diffusionColor + + + // SPECULAR + specular * lightColor * specularColor; +} \ No newline at end of file diff --git a/u07/main.c b/u07/main.c new file mode 100644 index 0000000..ea56b66 --- /dev/null +++ b/u07/main.c @@ -0,0 +1,346 @@ +#include + +#include +#include + +#include "vertexShader.c" +#include "fragmentShader.c" + +#include "matrixMath.h" +#include "transformation.h" +#include "wavefrontobj.h" + +#include +#include +#include +#include + +#define RESTART 345678 + +GLuint program; +GLuint vao; + +int numFaces = 0; + +bool exitRequested = false; + +GLFWwindow* window; + +GLfloat aspectRatio = 1.0f; + +double timeBetweenUpdates = 0.2f; + +double timeSinceUpdate = 0.0f; +int framesSinceUpdate = 0; + +GLfloat step = 0.0f; +const GLfloat pi = 3.14159f; + +vec3 cameraPosition = {0.0f, 3.0f, 5.5f}; + +// input handler for camera movement +void handleInputs(double deltaTime) { + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + cameraPosition.z += deltaTime * 10; + } + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + cameraPosition.z -= deltaTime * 10; + } + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { + cameraPosition.y += deltaTime * 10; + } + if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) { + cameraPosition.y -= deltaTime * 10; + } +} + +// input handler to quit with ESC +void keyboardHandler(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (action == GLFW_PRESS) { + if (key == GLFW_KEY_ESCAPE) { + exitRequested = true; + } + } +} + + +void init(void) { + // create and compile vertex shader + const GLchar *vertexTextConst = vertexShader_glsl; + + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexTextConst, &vertexShader_glsl_len); + glCompileShader(vertexShader); + + + GLint status; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); + + if (!status) { + printf("Error compiling vertex shader: "); + GLchar infoLog[1024]; + glGetShaderInfoLog(vertexShader, 1024, NULL, infoLog); + printf("%s",infoLog); + } + + vertexTextConst = NULL; + + + + // create and compile fragment shader + + const GLchar *fragmentTextConst = fragmentShader_glsl; + + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentTextConst, &fragmentShader_glsl_len); + glCompileShader(fragmentShader); + + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status); + + if (!status) { + printf("Error compiling fragment shader: "); + GLchar infoLog[1024]; + glGetShaderInfoLog(fragmentShader, 1024, NULL, infoLog); + printf("%s",infoLog); + } + + // create and link shader program + program = glCreateProgram(); + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + + if (!status) { + printf("Error linking program: "); + GLchar infoLog[1024]; + glGetProgramInfoLog(program, 1024, NULL, infoLog); + printf("%s",infoLog); + } + glValidateProgram(program); + + + glGetProgramiv(program, GL_VALIDATE_STATUS, &status); + + if (!status) { + printf("Error validating program: "); + GLchar infoLog[1024]; + glGetProgramInfoLog(program, 1024, NULL, infoLog); + printf("%s",infoLog); + } + + + // --------------- READ teapot.obj + ParsedObjFile teapot = readObjFile("../obj/monkey.obj"); + numFaces = teapot.length; + + // write teapot faces to buffer + GLuint triangleVertexBufferObject; + glGenBuffers(1, &triangleVertexBufferObject); + glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, teapot.length * sizeof(face), teapot.faces, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + + // create vertex array object + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferObject); + + // vertex positions + glVertexAttribPointer( + 0, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(vertex), + 0 + ); + glEnableVertexAttribArray(0); + + // vertex normals + glVertexAttribPointer( + 1, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(vertex), + (void*) sizeof(vec3) + ); + glEnableVertexAttribArray(1); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + + // ENABLE BACKFACE CULLING + glFrontFace(GL_CCW); + glEnable(GL_CULL_FACE); + + // ENABLE DEPTH BUFFER + glEnable(GL_DEPTH_TEST); + + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); +} + +void updateStats() { + printf("\rFPS: %.1f", framesSinceUpdate / timeSinceUpdate); + printf(" - Camera Position: [%f, %f, %f]", cameraPosition.x, cameraPosition.y, cameraPosition.z); + fflush(stdout); +} + +void draw(void) { + + // FPS Counter + framesSinceUpdate++; + double deltaTime = glfwGetTime(); + timeSinceUpdate += deltaTime; + glfwSetTime(0.0f); + + if (timeSinceUpdate >= timeBetweenUpdates) { + updateStats(); + timeSinceUpdate = 0.0f; + framesSinceUpdate = 0; + } + + // camera movement + handleInputs(deltaTime); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUseProgram(program); + glBindVertexArray(vao); + + // step for rotations + // counts up to 1.0 and then resets back to 0.0 forever + step += deltaTime / 5; + if (step > 1.0f) step -= 1.0f; + + // step multiplied by pi * 2 for use in rotation and trig functions + GLfloat stepi = step * pi * 2; + + + // ------------- MODEL TRANSFORMATION --------------------- + // SCALE -> ROTATE -> TRANSLATE + + mat4 modelTransformation; + identity(&modelTransformation); + + rotateY(&modelTransformation, &modelTransformation, stepi); + + + // ------------- VIEWING TRANSFORMATION ------------------- + vec3 origin = {0.0f, 0.0f, 0.0f}; + vec3 up = {0.0f, 1.0f, 0.0f}; + + mat4 viewingTransformation; + lookAt(&viewingTransformation, &cameraPosition, &origin, &up); + + + + // -------------- PROJECTION TRANSFORMATION ---------------- + mat4 projectionTransformation; + GLfloat near = 0.1f; + GLfloat far = 20.0f; + perspectiveProjection(&projectionTransformation, near, far); + + + + // -------------- NORMALISATION TRANSFORMATION ------------- + mat4 normalisationTransformation; + GLfloat fovy = pi / 2; + normalisedDeviceCoordinatesFov(&normalisationTransformation, fovy, aspectRatio, near, far); + + + mat4 modelView; + identity(&modelView); + multiply(&modelView, &modelTransformation, &modelView); + multiply(&modelView, &viewingTransformation, &modelView); + + mat4 projection; + identity(&projection); + multiply(&projection, &projectionTransformation, &projection); + multiply(&projection, &normalisationTransformation, &projection); + + // calculate matrix for normals + mat3 normalModelView; + mat3From4(&normalModelView, &modelView); + mat3Inverse(&normalModelView, &normalModelView); + mat3Transpose(&normalModelView, &normalModelView); + + // send transformation matrix to shader + glUniformMatrix4fv(glGetUniformLocation(program, "modelView"), 1, GL_FALSE, (GLfloat*)&modelView); + glUniformMatrix3fv(glGetUniformLocation(program, "normalModelView"), 1, GL_FALSE, (GLfloat*)&normalModelView); + glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (GLfloat*)&projection); + + + vec4 lightPosition = {cos(stepi * 2) * 3.0f, 3.0f, sin(stepi * 2) * 3.0f, 1.0f}; + multiplyAny((GLfloat *)&lightPosition, (GLfloat *)&modelView, (GLfloat *)&lightPosition, 4, 4, 1); + + glUniform3f(glGetUniformLocation(program, "lightPosition"), lightPosition.x, lightPosition.y, lightPosition.z); + + // SET MATERIAL DATA + glUniform4f(glGetUniformLocation(program, "ambientColor"), 0.25f, 0.22f, 0.06f, 1.0f); + glUniform4f(glGetUniformLocation(program, "diffusionColor"), 0.35f, 0.31f, 0.09f, 1.0f); + glUniform4f(glGetUniformLocation(program, "specularColor"), 0.80f, 0.72f, 0.21f, 1.0f); + glUniform1f(glGetUniformLocation(program, "shininess"), 83.2f * 4.0f); + + // SET LIGHT DATA + glUniform4f(glGetUniformLocation(program, "lightColor"), 1.0f, 1.0f, 1.0f, 1.0f); + glUniform4f(glGetUniformLocation(program, "ambientLight"), 0.2f, 0.2f, 0.2f, 1.0f); + + // draw!!1 + glDrawArrays(GL_TRIANGLES, 0, numFaces * 3); +} + +// change viewport size and adjust aspect ratio when changing window size +void framebuffer_size_callback(GLFWwindow *window, int width, int height) { + glViewport(0, 0, width, height); + aspectRatio = (float)width / height; +} + +int main(void) { + + // initialise window + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + window = glfwCreateWindow(700, 700, "Computergrafik 1", NULL, NULL); + + if (!window) { + printf("Failed to create window\n"); + glfwTerminate(); + return -1; + } + + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwMakeContextCurrent(window); + + // disable framerate cap + glfwSwapInterval(0); + + // register keyboard event handler + glfwSetKeyCallback(window, keyboardHandler); + + // initialise glew + glewInit(); + + printf("OpenGL version supported by this platform (%s):\n", glGetString(GL_VERSION)); + + init(); + + // exit when window should close or exit is requested (ESC) + while (!glfwWindowShouldClose(window) && !exitRequested) { + draw(); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + + return 0; +} \ No newline at end of file diff --git a/u07/matrixMath.c b/u07/matrixMath.c new file mode 100644 index 0000000..d47fdfd --- /dev/null +++ b/u07/matrixMath.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include + +#include "matrixMath.h" + +// MATRICES IN COLUMN MAJOR + +void vec3Zero(vec3* out) { + for (int i = 0; i < 3; i++) { + ((GLfloat*)out)[i] = 0; + } +} + +void vec3Add(vec3* out, vec3* a, vec3* b) { + for (int i = 0; i < 3; i++) { + ((GLfloat*)out)[i] = ((GLfloat*)a)[i] + ((GLfloat*)b)[i]; + } +} + +void vec3Multiply(vec3* out, vec3* a, GLfloat x) { + for (int i = 0; i < 3; i++) { + ((GLfloat*)out)[i] = ((GLfloat*)a)[i] * x; + } +} + +void vec3Subtract(vec3* out, vec3* a, vec3* b) { + vec3 minusB; + vec3Multiply(&minusB, b, -1); + vec3Add(out, a, &minusB); +} + +void vec3Cross(vec3* out, vec3* a, vec3* b) { + vec3 result; + result.x = a->y * b->z - a->z * b->y; + result.y = a->z * b->x - a->x * b->z; + result.z = a->x * b->y - a->y * b->x; + memcpy(out, &result, sizeof(vec3)); +} + +GLfloat vec3Length(vec3* a) { + return (GLfloat)sqrt(a->x * a->x + a->y * a->y + a->z * a->z); +} + +GLfloat vec3Dot(vec3* a, vec3* b) { + return a->x * b->x + a->y * b->y + a->z * b->z; +} + +void vec3Normalise(vec3* out, vec3* a) { + vec3Multiply(out, a, 1 / vec3Length(a)); +} +// CREATE 4x4 IDENTITY MATRIX +void identity(mat4* out) { + for (int i = 0; i < 16; i++) { + ((GLfloat*)out)[i] = (i % 4 == i / 4); + } +} + +// CREATE 4x4 TRANSLATION MATRIX +void translation(mat4* out, vec3* v) { + identity(out); + out->m03 = v->x; + out->m13 = v->y; + out->m23 = v->z; +} + +// CREATE 4x4 SCALING MATRIX +void scaling(mat4* out, vec3* v) { + identity(out); + out->m00 = v->x; + out->m11 = v->y; + out->m22 = v->z; +} + +// CREATE 4x4 ROTATION MATRIX AROUND Z AXIS +/* cos a -sin a 0 0 + * sin a cos a 0 0 + * 0 0 1 0 + * 0 0 0 1 +*/ +void rotationZ(mat4* out, GLfloat angle) { + identity(out); + out->m00 = cos(angle); + out->m10 = sin(angle); + out->m01 = -sin(angle); + out->m11 = cos(angle); +} + +// CREATE 4x4 ROTATION MATRIX AROUND Y AXIS +void rotationY(mat4* out, GLfloat angle) { + identity(out); + out->m00 = cos(angle); + out->m20 = -sin(angle); + out->m02 = sin(angle); + out->m22 = cos(angle); +} + +// CREATE 4x4 ROTATION MATRIX AROUND Y AXIS +void rotationX(mat4* out, GLfloat angle) { + identity(out); + out->m11 = cos(angle); + out->m21 = sin(angle); + out->m12 = -sin(angle); + out->m22 = cos(angle); +} + +// MULTIPLY ANY TO MATRICES +void multiplyAny(GLfloat* out, GLfloat* A, GLfloat* B, int wA, int hA, int wB) { + int sizeOut = hA * wB; + GLfloat* result = (GLfloat*) malloc(sizeOut * sizeof(GLfloat)); + for (int i = 0; i < sizeOut; i++) { + result[i] = 0; + for (int j = 0; j < wA; j++) { + result[i] += A[j * hA + i % hA] * B[j + i / hA * wB]; + } + } + memcpy(out, result, sizeOut * sizeof(GLfloat)); + free(result); + result = NULL; +} + +// MULTIPLY TWO 4x4 MATRICES +void multiply(mat4* out, mat4* A, mat4* B) { + multiplyAny((GLfloat*)out, (GLfloat*)A, (GLfloat*)B, 4, 4, 4); +} + +// MULTIPLY in WITH TRANSLATION MATRIX OF v +void translate(mat4* out, mat4* in, vec3* v) { + mat4 translationMatrix; + translation(&translationMatrix, v); + multiply(out, &translationMatrix, in); +} + +// MULTIPLY in WITH SCALING MATRIX OF v +void scale(mat4* out, mat4* in, vec3* v) { + mat4 scalingMatrix; + scaling(&scalingMatrix, v); + multiply(out, &scalingMatrix, in); +} + +// MULTIPLY in WITH ROTATION MATRIX OF a AROUND Z AXIS +void rotateZ(mat4* out, mat4* in, GLfloat angle) { + mat4 rotationMatrix; + rotationZ(&rotationMatrix, angle); + multiply(out, &rotationMatrix, in); +} +// MULTIPLY in WITH ROTATION MATRIX OF a AROUND Y AXIS +void rotateY(mat4* out, mat4* in, GLfloat angle) { + mat4 rotationMatrix; + rotationY(&rotationMatrix, angle); + multiply(out, &rotationMatrix, in); +} +// MULTIPLY in WITH ROTATION MATRIX OF a AROUND X AXIS +void rotateX(mat4* out, mat4* in, GLfloat angle) { + mat4 rotationMatrix; + rotationX(&rotationMatrix, angle); + multiply(out, &rotationMatrix, in); +} + +void transposeAny(GLfloat* out, GLfloat* in, int w, int h) { + int size = w * h; + GLfloat* result = (GLfloat*) malloc(size * sizeof(GLfloat)); + + for (int i = 0; i < size; i++) { + result[i] = in[(i % w) * h + i / w]; + } + + memcpy(out, result, size * sizeof(GLfloat)); + free(result); + result = NULL; +} + + +void transpose(mat4* out, mat4* in) { + transposeAny((GLfloat*)out, (GLfloat*)in, 4, 4); +} + +void printAny(GLfloat* M, int w, int h) { + GLfloat* transposed = (GLfloat*) malloc(w * h * sizeof(GLfloat)); + transposeAny(transposed, M, w, h); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + printf("%.4f ", transposed[i * w + j]); + } + printf("\n"); + } + free(transposed); + transposed = NULL; +} + +void vec3Print(vec3* a) { + printAny((GLfloat*)a, 1, 3); +} + +void mat4Print(mat4* m) { + printAny((GLfloat*)m, 4, 4); +} + +void mat3Print(mat3* m) { + printAny((GLfloat*)m, 3, 3); +} + +void mat3From4(mat3* out, mat4* in) { + memcpy(&out->m00, &in->m00, sizeof(vec3)); + memcpy(&out->m01, &in->m01, sizeof(vec3)); + memcpy(&out->m02, &in->m02, sizeof(vec3)); +} + +void mat3Adjoint(mat3* out, mat3* in) { + mat3 result; + + result.m00 = in->m11 * in->m22 - in->m21 * in->m12; + result.m01 = in->m10 * in->m22 - in->m20 * in->m12; + result.m02 = in->m10 * in->m21 - in->m20 * in->m11; + + result.m10 = in->m01 * in->m22 - in->m21 * in->m02; + result.m11 = in->m00 * in->m22 - in->m20 * in->m02; + result.m12 = in->m00 * in->m21 - in->m20 * in->m01; + + result.m20 = in->m01 * in->m12 - in->m11 * in->m02; + result.m21 = in->m00 * in->m12 - in->m10 * in->m02; + result.m22 = in->m00 * in->m11 - in->m10 * in->m01; + + memcpy(out, &result, sizeof(mat3)); +} + +void mat3MultiplyScalar(mat3* out, mat3* in, GLfloat x) { + for (int i = 0; i < 9; i++) { + ((GLfloat*)out)[i] = ((GLfloat*)in)[i] * x; + } +} + +GLfloat mat3Determinant(mat3* M) { + return + M->m00 * M->m11 * M->m22 + + M->m01 * M->m12 * M->m20 + + M->m02 * M->m10 * M->m21 + + - M->m20 * M->m11 * M->m02 + - M->m21 * M->m12 * M->m00 + - M->m22 * M->m10 * M->m01 + ; +} + +void mat3Transpose(mat3* out, mat3* in) { + transposeAny((GLfloat*)out, (GLfloat*)in, 3, 3); +} + +void mat3Inverse(mat3* out, mat3* in) { + mat3 result; + mat3Adjoint(&result, in); + mat3MultiplyScalar(&result, &result, 1 / mat3Determinant(in)); + + memcpy(out, &result, sizeof(mat3)); +} + +GLfloat sumDiffAny(GLfloat* A, GLfloat* B, int w, int h) { + GLfloat result = 0; + for (int i = 0; i < w * h; i++) { + result += abs(A[i] - B[i]); + } + return result; +} + +GLfloat mat3SumDiff(mat3* A, mat3* B) { + return sumDiffAny((GLfloat*)A, (GLfloat*)B, 3, 3); +} \ No newline at end of file diff --git a/u07/matrixMath.h b/u07/matrixMath.h new file mode 100644 index 0000000..78bc07b --- /dev/null +++ b/u07/matrixMath.h @@ -0,0 +1,97 @@ +#ifndef MATRIX_MATH +#define MATRIX_MATH + +#include + +typedef struct { + GLfloat x; + GLfloat y; + GLfloat z; +} vec3; + +typedef struct { + GLfloat x; + GLfloat y; + GLfloat z; + GLfloat w; +} vec4; + +typedef struct { + GLfloat m00; + GLfloat m10; + GLfloat m20; + GLfloat m30; + + GLfloat m01; + GLfloat m11; + GLfloat m21; + GLfloat m31; + + GLfloat m02; + GLfloat m12; + GLfloat m22; + GLfloat m32; + + GLfloat m03; + GLfloat m13; + GLfloat m23; + GLfloat m33; +} mat4; + +typedef struct { + GLfloat m00; + GLfloat m10; + GLfloat m20; + + GLfloat m01; + GLfloat m11; + GLfloat m21; + + GLfloat m02; + GLfloat m12; + GLfloat m22; +} mat3; + +extern void vec3Zero(vec3* out); +extern void vec3Add(vec3* out, vec3* a, vec3* b); +extern void vec3Multiply(vec3* out, vec3* a, GLfloat x); +extern void vec3Subtract(vec3* out, vec3* a, vec3* b); +extern void vec3Cross(vec3* out, vec3* a, vec3* b); +extern void vec3Normalise(vec3* out, vec3* a); +extern GLfloat vec3Length(vec3* a); +extern GLfloat vec3Dot(vec3* a, vec3* b); + +extern void identity(mat4* out); +extern void translation(mat4* out, vec3* v); +extern void scaling(mat4* out, vec3* v); +extern void rotationZ(mat4* out, GLfloat angle); +extern void rotationY(mat4* out, GLfloat angle); +extern void rotationX(mat4* out, GLfloat angle); + +extern void multiplyAny(GLfloat* out, GLfloat* A, GLfloat* B, int wA, int hA, int wB); +extern void multiply(mat4* out, mat4* A, mat4* B); + +extern void translate(mat4* out, mat4* in, vec3* v); +extern void scale(mat4* out, mat4* in, vec3* v); +extern void rotateZ(mat4* out, mat4* in, GLfloat angle); +extern void rotateY(mat4* out, mat4* in, GLfloat angle); +extern void rotateX(mat4* out, mat4* in, GLfloat angle); + +extern void transposeAny(GLfloat* out, GLfloat* in, int w, int h); +extern void transpose(mat4* out, mat4* in); + +extern void printAny(GLfloat* M, int w, int h); +extern void vec3Print(vec3* a); +extern void mat4Print(mat4* m); +extern void mat3Print(mat3* m); + +extern void mat3From4(mat3* out, mat4* in); +extern void mat3Adjoint(mat3* out, mat3* in); +extern void mat3MultiplyScalar(mat3* out, mat3* in, GLfloat x); +extern GLfloat mat3Determinant(mat3* m); +extern void mat3Transpose(mat3* out, mat3* in); +extern void mat3Inverse(mat3* out, mat3* in); + +extern GLfloat sumDiffAny(GLfloat* A, GLfloat* B, int w, int h); +extern GLfloat mat3SumDiff(mat3* A, mat3* B); +#endif \ No newline at end of file diff --git a/u07/test.c b/u07/test.c new file mode 100644 index 0000000..eb61b70 --- /dev/null +++ b/u07/test.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +#include "matrixMath.h" + +#define EPSILON 0.001f + +void printTest(char* name, bool result) { + if (result) { + printf(" PASSED - "); + } else { + printf("!!! FAILED - "); + } + printf("%s", name); + printf("\n"); +} + +void testSumDiff() { + mat3 A = {1.0f, 0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 1.0f, -1.0f, 9.0f}; + mat3 B = {0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 8.0f}; + GLfloat target = 7.0f; + + GLfloat value = mat3SumDiff(&A, &B); + + bool result = fabs(value - target) < EPSILON; + + if (!result) { + printf("\nA:\n"); + mat3Print(&A); + printf("\nB:\n"); + mat3Print(&B); + printf("target: %f\n", target); + printf("value: %f\n", value); + } + + printTest("mat3SumDiff", result); +} + +void testMat3Adjoint() { + mat3 M = {2.0f, 0.0f, 1.0f, -1.0f, 5.0f, -1.0f, 3.0f, 2.0f, -2.0f}; + mat3 target = {-8.0f, 5.0f, -17.0f, -2.0f, -7.0f, 4.0f, -5.0f, -1.0f, 10.0f}; + + mat3Adjoint(&M, &M); + + printTest("mat3Adjoint", mat3SumDiff(&M, &target) < EPSILON); +} + +void testMat3MultiplyScalar() { + mat3 M = {1.0f, 2.0f, 3.0f, 4.0f, 0.0f, -1.5f, -2.5f, -3.5f, -4.5f}; + GLfloat x = 0.9f; + mat3 target = {0.9f, 1.8f, 2.7f, 3.6f, 0.0f, -1.35f, -2.25f, -3.15f, -4.05f}; + + mat3MultiplyScalar(&M, &M, x); + + printTest("mat3MultiplyScalar", mat3SumDiff(&M, &target) < EPSILON); +} + +void testMat3Determinant() { + mat3 M = {1.0f, -3.0f, 2.0f, 3.0f, -1.0f, 3.0f, 2.0f, -3.0f, 1.0f}; + GLfloat target = -15.0f; + + printTest("mat3Determinant", fabs(mat3Determinant(&M) - target) < EPSILON); +} + +void testMat3Inverse() { + mat3 M = {1.0f, 2.0f, -1.0f, 2.0f, 1.0f, 2.0f, -1.0f, 2.0f, 1.0f}; + mat3 target = {0.1875f, 0.25f, -0.3125f, 0.2f, 0.0f, 0.25f, -0.3125f, 0.25f, 0.1875f}; + + mat3Inverse(&M, &M); + + printTest("mat3Inverse", mat3SumDiff(&M, &target) < EPSILON); +} + +int main(void) { + testSumDiff(); + testMat3Adjoint(); + testMat3MultiplyScalar(); + testMat3Determinant(); + testMat3Inverse(); +} \ No newline at end of file diff --git a/u07/transformation.c b/u07/transformation.c new file mode 100644 index 0000000..b914ab6 --- /dev/null +++ b/u07/transformation.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +#include "matrixMath.h" +#include "transformation.h" + +void lookAt(mat4* out, vec3* eye, vec3* look, vec3* up) { + + + vec3 n; + vec3Subtract(&n, eye, look); + + vec3 u; + vec3Cross(&u, up, &n); + + vec3 v; + vec3Cross(&v, &n, &u); + + + vec3Normalise(&n, &n); + vec3Normalise(&u, &u); + vec3Normalise(&v, &v); + + + mat4 Mr; + identity(&Mr); + + memcpy(&Mr.m00, &u, sizeof(vec3)); + memcpy(&Mr.m01, &v, sizeof(vec3)); + memcpy(&Mr.m02, &n, sizeof(vec3)); + transpose(&Mr, &Mr); + + + vec3 t; + vec3Multiply(&u, &u, -1); + vec3Multiply(&v, &v, -1); + vec3Multiply(&n, &n, -1); + + + + t.x = vec3Dot(&u, eye); + t.y = vec3Dot(&v, eye); + t.z = vec3Dot(&n, eye); + + + memcpy(&Mr.m03, &t, sizeof(vec3)); + + memcpy(out, &Mr, sizeof(mat4)); +} + +void perspectiveProjection(mat4* out, GLfloat near, GLfloat far) { + identity(out); + + out->m22 = 1 + (far / near); + out->m32 = - 1.0f / near; + out->m23 = far; + out->m33 = 0; +} + +void normalisedDeviceCoordinates(mat4* out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, GLfloat n, GLfloat f) { + identity(out); + + out->m00 = 2 / (r - l); + out->m11 = 2 / (t - b); + out->m22 = -2 / (f - n); + + out->m03 = - (r + l) / (r - l); + out->m13 = - (t + b) / (t - b); + out->m23 = - (f + n) / (f - n); +} + +void normalisedDeviceCoordinatesFov(mat4* out, GLfloat fovy, GLfloat aspectRatio, GLfloat n, GLfloat f) { + GLfloat t = tan(fovy / 2) * n; + GLfloat r = t * aspectRatio; + normalisedDeviceCoordinates(out, r, -r, t, -t, n, f); +} \ No newline at end of file diff --git a/u07/transformation.h b/u07/transformation.h new file mode 100644 index 0000000..9bbc03d --- /dev/null +++ b/u07/transformation.h @@ -0,0 +1,11 @@ +#ifndef TRANSFORMATION_H +#define TRANSFORMATION_H + +#include + +extern void lookAt(mat4* out, vec3* eye, vec3* look, vec3* up); +extern void perspectiveProjection(mat4* out, GLfloat near, GLfloat far); +extern void normalisedDeviceCoordinates(mat4* out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, GLfloat n, GLfloat f); +extern void normalisedDeviceCoordinatesFov(mat4* out, GLfloat fovy, GLfloat aspectRatio, GLfloat n, GLfloat f); + +#endif \ No newline at end of file diff --git a/u07/vertexShader.glsl b/u07/vertexShader.glsl new file mode 100644 index 0000000..fe5716a --- /dev/null +++ b/u07/vertexShader.glsl @@ -0,0 +1,17 @@ +#version 330 core +layout (location = 0) in vec3 aPosition; +layout (location = 1) in vec3 aNormal; + +uniform mat4 modelView; +uniform mat3 normalModelView; +uniform mat4 projection; + + +out vec3 normal; +out vec3 fragmentPosition; +void main() { + normal = normalModelView * aNormal; + + gl_Position = projection * modelView * vec4(aPosition, 1.0); + fragmentPosition = vec3(modelView * vec4(aPosition, 1.0)); +} \ No newline at end of file diff --git a/u07/wavefrontobj.c b/u07/wavefrontobj.c new file mode 100644 index 0000000..2f79ced --- /dev/null +++ b/u07/wavefrontobj.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include + +#include "wavefrontobj.h" + +#define OBJ_LINE_BUFFER_SIZE 256 + +/** + * + * ADJUSTMENT NEEDED FOR + * - Textures + * - Face Definitions other than vertex/texture/normal + * - Vertex positions including w + * - Any faces using vertices yet to be defined + * (File is read top to bottom. A face using a vertex + * defined underneath it in the file will not work) + * + */ + +ParsedObjFile readObjFile(char* path) { + ParsedObjFile parsedFile; + + FILE* fp = fopen(path, "r"); + + if (fp == NULL) { + fprintf(stderr, "File could not be opened: %s", path); + parsedFile.faces = NULL; + parsedFile.length = 0; + } + + uint numVertices = 0; + uint numVertexNormals = 0; + uint numFaces = 0; + uint numTextureCoords = 0; + + char buf[OBJ_LINE_BUFFER_SIZE]; + + while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) { + if (buf[0] == 'v') { + if (buf[1] == ' ') { + numVertices++; + } else if (buf[1] == 't') { + numTextureCoords++; + } else if (buf[1] == 'n') { + numVertexNormals++; + } + } + if (buf[0] == 'f') { + int numSpaces = 0; + for (int i = 0; i < strlen(buf); i++) { + if (buf[i] == ' ') { + numSpaces++; + } + } + numFaces += numSpaces - 2; + } + } + + // printf("Vertices: %d\nFaces: %d\nNormals:%d\nTextures:%d\n", numVertices, numFaces, numVertexNormals, numTextureCoords); + + vec3* vertices = (vec3*) malloc(sizeof(vec3) * numVertices); + vec3* normals = (vec3*) malloc(sizeof(vec3) * numVertexNormals); + + face* faces = (face*) malloc(sizeof(face) * numFaces); + + parsedFile.faces = faces; + parsedFile.length = numFaces; + + rewind(fp); + + uint curVertex = 0; + uint curNormal = 0; + uint curFace = 0; + + while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) { + if (buf[0] == 'v') { + if (buf[1] == ' ') { + + sscanf(buf, + "v %f %f %f", + &vertices[curVertex].x, + &vertices[curVertex].y, + &vertices[curVertex].z + ); + curVertex++; + + } else if (buf[1] == 't') { + continue; + } else if (buf[1] == 'n') { + + sscanf(buf, + "vn %f %f %f", + &normals[curNormal].x, + &normals[curNormal].y, + &normals[curNormal].z + ); + curNormal++; + + } + } + + if (buf[0] == 'f') { + int v1, v2, v3; + int vt1, vt2, vt3; + int vn1, vn2, vn3; + + sscanf(buf, + "f %d/%d/%d %d/%d/%d %d/%d/%d", + &v1, &vt1, &vn1, + &v2, &vt2, &vn2, + &v3, &vt3, &vn3 + ); + + memcpy(&faces[curFace].v1.position, &vertices[v1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.position, &vertices[v2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.position, &vertices[v3 - 1], sizeof(vec3)); + + memcpy(&faces[curFace].v1.normal, &normals[vn1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.normal, &normals[vn2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.normal, &normals[vn3 - 1], sizeof(vec3)); + + curFace++; + + int numSpaces = 0; + for (int i = 0; i < strlen(buf); i++) { + if (buf[i] == ' ') { + numSpaces++; + } + } + + if (numSpaces == 4) { + sscanf(buf, + "f %d/%d/%d %*d/%*d/%*d %d/%d/%d %d/%d/%d", + &v1, &vt1, &vn1, + &v2, &vt2, &vn2, + &v3, &vt3, &vn3 + ); + + memcpy(&faces[curFace].v1.position, &vertices[v1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.position, &vertices[v2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.position, &vertices[v3 - 1], sizeof(vec3)); + + memcpy(&faces[curFace].v1.normal, &normals[vn1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.normal, &normals[vn2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.normal, &normals[vn3 - 1], sizeof(vec3)); + + curFace++; + } + + + // TODO: textures + } + + } + + free(vertices); + free(normals); + fclose(fp); + + return parsedFile; +} + +void clearParsedFile(ParsedObjFile file) { + free(file.faces); +} \ No newline at end of file diff --git a/u07/wavefrontobj.h b/u07/wavefrontobj.h new file mode 100644 index 0000000..72a59b6 --- /dev/null +++ b/u07/wavefrontobj.h @@ -0,0 +1,28 @@ +#ifndef WAVEFRONTOBJ_H +#define WAVEFRONTOBJ_H + +#include +#include "matrixMath.h" + +typedef struct { + vec3 position; + vec3 normal; +} vertex; + +typedef struct { + vertex v1; + vertex v2; + vertex v3; +} face; + +typedef struct { + face* faces; + GLuint length; +} ParsedObjFile; + + +extern ParsedObjFile readObjFile(char* path); +extern void clearParsedFile(ParsedObjFile file); + + +#endif \ No newline at end of file