#include #include #include #include #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.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], &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); }