computer-grafik-1/u08-2/wavefrontobj.c

242 lines
5.2 KiB
C

#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* v2, vec2* vt2,
vec3* v3, vec2* vt3
) {
// 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.x * deltaTex2.y - deltaTex1.y * deltaTex2.x);
vec3Multiply(&deltaPos1, &deltaPos1, deltaTex2.y);
vec3Multiply(&deltaPos2, &deltaPos2, deltaTex1.y);
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].x,
&vertices[curVertex].y,
&vertices[curVertex].z
);
curVertex++;
} else if (buf[1] == 't') {
int readValues = sscanf(buf,
"vt %f %f",
&textures[curTexture].x,
&textures[curTexture].y
);
if (readValues != 2) {
textures[curTexture].y = 0;
}
curTexture++;
} 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
);
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],
&vertices[v2 - 1], &textures[vt2 - 1],
&vertices[v3 - 1], &textures[vt3 - 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],
&vertices[v2 - 1], &textures[vt2 - 1],
&vertices[v3 - 1], &textures[vt3 - 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);
}