Compare commits

...

4 Commits

Author SHA1 Message Date
Luca Conte 63c44f9f7a go back I want to be monkey 2025-05-15 15:33:51 +02:00
Luca Conte dd201108e6 load obj files 2025-05-15 15:28:30 +02:00
Luca Conte 6ccfb7e818 fix projection 2025-04-23 17:20:35 +02:00
Luca Conte cced3c5c83 include string.h for memcpy 2025-04-23 11:59:55 +02:00
12 changed files with 2052393 additions and 94 deletions

View File

@ -7,7 +7,8 @@ src_files = [
'./src/main.c',
'./src/shader.c',
'./src/log.c',
'./src/matrix-math.c'
'./src/matrix-math.c',
'./src/wavefrontobj.c'
]
executable('cg1',

34
obj/cube.obj Normal file
View File

@ -0,0 +1,34 @@
# Blender 4.4.3
# www.blender.org
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 1.000000
s 0
f 5/1/1 3/2/1 1/3/1
f 3/1/2 8/2/2 4/3/2
f 7/1/3 6/2/3 8/3/3
f 2/1/4 8/2/4 6/3/4
f 1/1/5 4/2/5 2/3/5
f 5/1/6 2/2/6 6/3/6
f 5/1/1 7/4/1 3/2/1
f 3/1/2 7/4/2 8/2/2
f 7/1/3 5/4/3 6/2/3
f 2/1/4 4/4/4 8/2/4
f 1/1/5 3/4/5 4/2/5
f 5/1/6 1/4/6 2/2/6

2066
obj/monkey.obj Normal file

File diff suppressed because it is too large Load Diff

2033859
obj/smooth_monkey.obj Normal file

File diff suppressed because it is too large Load Diff

16109
obj/teapot.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include "log.h"
#include "shader.h"
#include "matrix-math.h"
#include "wavefrontobj.h"
#define STATUS_INTERVAL 0.5
#define PI 3.14159f
@ -18,8 +19,7 @@
GLuint program;
GLuint vertexArrayObject;
GLuint indexBuffer;
GLuint numVertices;
GLuint initialWindowWidth = 800;
GLuint initialWindowHeight = 600;
@ -122,47 +122,15 @@ void init(void) {
*
*/
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("Loading OBJ File");
ParsedObjFile f = readObjFile("obj/smooth_monkey.obj");
numVertices = f.length * sizeof(face) / sizeof(vertex);
DEBUG("Creating vertext buffer");
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, f.length * sizeof(face), f.faces, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
DEBUG("Creating vertex array object");
@ -177,17 +145,21 @@ void init(void) {
3, // number of values to read
GL_FLOAT, // type of value
GL_FALSE, // if values are normalised
3 * sizeof(GLfloat), // stride - distance between vertices
sizeof(vertex), // 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);
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
sizeof(vertex),
(void*)offsetof(vertex, normal)
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
@ -208,30 +180,11 @@ void init(void) {
GLfloat currentHue = 0.0f;
void drawCube(vec3 position, mat4 initialModelMatrix, mat4 viewMatrix) {
mat4 modelMatrix;
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
GLuint modelViewLocation = glGetUniformLocation(program, "uModelView");
glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, modelViewMatrix);
// draw cube
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, 48, GL_UNSIGNED_INT, 0);
}
void draw(void) {
updateStatusDisplay();
// counter for animation
currentHue += 0.0005f;
currentHue += 0.005f;
if (currentHue > 1.0) currentHue = 0.0f;
// clear colour and depth buffer
@ -244,7 +197,7 @@ void draw(void) {
mat4 viewMatrix;
// mat4Identity(viewMatrix);
vec3 cameraPos = {0.0f, 1.0f, 1.3f};
vec3 cameraPos = {cos(currentHue * M_PI * 2), 0.0f, sin(currentHue * M_PI * 2)};
vec3 cameraLookAt = {0.0f, 0.2f, 0.0f};
vec3 cameraUp = {0.0f, 1.0f, 0.0f};
mat4BuildLookAt(viewMatrix, cameraPos, cameraLookAt, cameraUp);
@ -255,26 +208,18 @@ void draw(void) {
// build model Matrix
mat4 modelMatrix;
vec3 scale;
vec3 position;
mat4 modelViewMatrix;
vec3 scale = {0.2f, 0.2f, 0.2f};
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);
vec3Set(scale, scales[i], 0.05f, scales[i]);
mat4Scale(modelMatrix, modelMatrix, scale);
mat4Multiply(modelViewMatrix, viewMatrix, modelMatrix);
mat4RotateY(modelMatrix, modelMatrix, currentHue * 2 * M_PI + (i / 5.0f * M_PI));
vec3Set(position, 0.0f, i * 0.05f, 0.0f);
mat4Translate(modelMatrix, modelMatrix, position);
drawCube(position, modelMatrix, viewMatrix);
}
glUniformMatrix4fv(glGetUniformLocation(program, "uModelView"), 1, GL_FALSE, modelViewMatrix);
glBindVertexArray(vertexArrayObject);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {

View File

@ -1,6 +1,7 @@
#include "matrix-math.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
/**
* overwrites a 4x4 matrix with the identity matrix
@ -195,6 +196,7 @@ void mat4BuildProjection(mat4 out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, G
out[11] = -1.0f / n;
out[14] = - 2.0f * f / (f - n);
out[15] = 0.0f;
}
/**
@ -420,6 +422,18 @@ void vec3Set(vec3 out, GLfloat x, GLfloat y, GLfloat z) {
out[2] = z;
}
void vec3Multiply(vec3 out, vec3 in, GLfloat x) {
out[0] = in[0] * x;
out[1] = in[1] * x;
out[2] = in[2] * x;
}
void vec2Subtract(vec2 out, vec2 a, vec2 b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
}
void mat3Copy(mat3 src, mat3 dst) {
for (int i = 0; i < 9; i++) {
@ -457,7 +471,6 @@ void mat3Minor(mat3 out, mat3 in) {
result[4] = in[0] * in[8] - in[2] * in[6];
result[5] = in[0] * in[7] - in[1] * in[6];
result[6] = in[1] * in[5] - in[2] * in[4];
result[7] = in[0] * in[5] - in[2] * in[3];
result[8] = in[0] * in[4] - in[1] * in[3];

View File

@ -9,10 +9,12 @@
typedef GLfloat vec4[4];
typedef GLfloat vec3[3];
typedef GLfloat vec2[2];
typedef GLfloat mat4[16];
typedef GLfloat mat3[9];
extern void mat4Identity(mat4 mat);
extern void mat4Copy(mat4 src, mat4 dst);
extern void mat4Empty(mat4 mat);
@ -36,6 +38,9 @@ extern void vec3Normalise(vec3 out, vec3 in);
extern GLfloat vec3Length(vec3 in);
extern GLfloat vec3DotProduct(vec3 a, vec3 b);
extern void vec3Set(vec3 out, GLfloat x, GLfloat y, GLfloat z);
extern void vec3Multiply(vec3 out, vec3 in, GLfloat x);
extern void vec2Subtract(vec2 out, vec2 a, vec2 b);
extern void mat3Copy(mat3 src, mat3 dst);
extern void mat3Inverse(mat3 out, mat3 in);

View File

@ -1,15 +1,6 @@
#version 330 core
vec3 colors[6] = vec3[6](
vec3(1.0, 0.5, 0.5),
vec3(0.5, 1.0, 0.5),
vec3(0.5, 0.5, 1.0),
vec3(1.0, 1.0, 0.5),
vec3(1.0, 0.5, 1.0),
vec3(0.5, 1.0, 1.0)
);
in vec3 vNormal;
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(vNormal * 0.5 + vec3(0.5), 1.0);
}

View File

@ -1,8 +1,12 @@
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
uniform mat4 uModelView;
uniform mat4 uProjection;
out vec3 vNormal;
void main() {
vNormal = aNormal;
gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);
}

242
src/wavefrontobj.c Normal file
View File

@ -0,0 +1,242 @@
#include <GL/glew.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wavefrontobj.h"
#define OBJ_LINE_BUFFER_SIZE 256
/**
*
* ADJUSTMENT NEEDED FOR
* - 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)
*
*/
void storeFace(
face* f,
vec3 v1, vec2 vt1, vec3 vn1,
vec3 v2, vec2 vt2, vec3 vn2,
vec3 v3, vec2 vt3, vec3 vn3
) {
memcpy(&f->v1.position, v1, sizeof(vec3));
memcpy(&f->v2.position, v2, sizeof(vec3));
memcpy(&f->v3.position, v3, sizeof(vec3));
memcpy(&f->v1.normal, vn1, sizeof(vec3));
memcpy(&f->v2.normal, vn2, sizeof(vec3));
memcpy(&f->v3.normal, vn3, sizeof(vec3));
memcpy(&f->v1.texture, vt1, sizeof(vec2));
memcpy(&f->v2.texture, vt2, sizeof(vec2));
memcpy(&f->v3.texture, vt3, sizeof(vec2));
}
// void storeTB(face* f,
// vec3 v1, vec2 vt1, vec3 vn1,
// vec3 v2, vec2 vt2, vec3 vn2,
// vec3 v3, vec2 vt3, vec3 vn3
// ) {
// // https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/
// vec3 deltaPos1;
// vec3 deltaPos2;
// vec3Subtract(deltaPos1, v2, v1);
// vec3Subtract(deltaPos1, v3, v1);
// vec2 deltaTex1;
// vec2 deltaTex2;
// vec2Subtract(deltaTex1, vt2, vt1);
// vec2Subtract(deltaTex2, vt3, vt1);
// GLfloat r = 1.0f / (deltaTex1[0] * deltaTex2[1] - deltaTex1[1] * deltaTex2[0]);
// vec3Multiply(deltaPos1, deltaPos1, deltaTex2[1]);
// vec3Multiply(deltaPos2, deltaPos2, deltaTex1[1]);
// vec3 tangent;
// vec3Subtract(tangent, deltaPos1, deltaPos2);
// vec3Multiply(tangent, tangent, r);
// memcpy(&f->v1.tangent, &tangent, sizeof(vec3));
// memcpy(&f->v2.tangent, &tangent, sizeof(vec3));
// memcpy(&f->v3.tangent, &tangent, sizeof(vec3));
// }
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);
vec2* textures = (vec2*) malloc(sizeof(vec2) * numTextureCoords);
face* faces = (face*) malloc(sizeof(face) * numFaces);
parsedFile.faces = faces;
parsedFile.length = numFaces;
rewind(fp);
uint curVertex = 0;
uint curNormal = 0;
uint curFace = 0;
uint curTexture = 0;
while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) {
if (buf[0] == 'v') {
if (buf[1] == ' ') {
sscanf(buf,
"v %f %f %f",
&vertices[curVertex][0],
&vertices[curVertex][1],
&vertices[curVertex][2]
);
curVertex++;
} else if (buf[1] == 't') {
int readValues = sscanf(buf,
"vt %f %f",
&textures[curTexture][0],
&textures[curTexture][1]
);
if (readValues != 2) {
textures[curTexture][1] = 0;
}
curTexture++;
} else if (buf[1] == 'n') {
sscanf(buf,
"vn %f %f %f",
&normals[curNormal][0],
&normals[curNormal][1],
&normals[curNormal][2]
);
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
);
storeFace(&faces[curFace],
vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
);
// storeTB(&faces[curFace],
// vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
// vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
// vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
// );
curFace++;
int numSpaces = 0;
for (int i = 0; i < strlen(buf); i++) {
if (buf[i] == ' ') {
numSpaces++;
}
}
if (numSpaces == 4) {
// storeTB(&faces[curFace],
// vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
// vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
// vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
// );
sscanf(buf,
"f %d/%d/%d %*d/%*d/%*d %d/%d/%d %d/%d/%d",
&v1, &vt1, &vn1,
&v2, &vt2, &vn2,
&v3, &vt3, &vn3
);
storeFace(&faces[curFace],
vertices[v1 - 1], textures[vt1 - 1], normals[vn1 - 1],
vertices[v2 - 1], textures[vt2 - 1], normals[vn2 - 1],
vertices[v3 - 1], textures[vt3 - 1], normals[vn3 - 1]
);
curFace++;
}
// TODO: textures
}
}
free(vertices);
free(normals);
fclose(fp);
return parsedFile;
}
void clearParsedFile(ParsedObjFile file) {
free(file.faces);
}

30
src/wavefrontobj.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef WAVEFRONTOBJ_H
#define WAVEFRONTOBJ_H
#include <GL/glew.h>
#include "matrix-math.h"
typedef struct {
vec3 position;
vec3 normal;
vec2 texture;
// vec3 tangent;
} 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