GLUSboolean GLUSAPIENTRY glusLoadObjFile(const GLUSchar* filename, GLUSshape* shape) { GLUSboolean result; FILE* f; GLUSchar buffer[GLUS_BUFFERSIZE]; GLUSchar identifier[3]; GLUSfloat x, y, z; GLUSfloat s, t; GLUSfloat* vertices = 0; GLUSfloat* normals = 0; GLUSfloat* texCoords = 0; GLUSuint numberVertices = 0; GLUSuint numberNormals = 0; GLUSuint numberTexCoords = 0; GLUSfloat* triangleVertices = 0; GLUSfloat* triangleNormals = 0; GLUSfloat* triangleTexCoords = 0; GLUSuint totalNumberVertices= 0; GLUSuint totalNumberNormals= 0; GLUSuint totalNumberTexCoords= 0; GLUSuint facesEncoding = 0; if (!filename || !shape) { return GLUS_FALSE; } memset(shape, 0, sizeof(GLUSshape)); f = fopen(filename, "r"); if (!f) { return GLUS_FALSE; } if (!glusMallocTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords)) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } while (!feof(f)) { if (fgets(buffer, GLUS_BUFFERSIZE, f) == 0) { if (ferror(f)) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } } if (strncmp(buffer, "vt", 2) == 0) { if (numberTexCoords == GLUS_MAX_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } sscanf(buffer, "%s %f %f", identifier, &s, &t); texCoords[2 * numberTexCoords + 0] = s; texCoords[2 * numberTexCoords + 1] = t; numberTexCoords++; } else if (strncmp(buffer, "vn", 2) == 0) { if (numberNormals == GLUS_MAX_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } sscanf(buffer, "%s %f %f %f", identifier, &x, &y, &z); normals[3 * numberNormals + 0] = x; normals[3 * numberNormals + 1] = y; normals[3 * numberNormals + 2] = z; numberNormals++; } else if (strncmp(buffer, "v", 1) == 0) { if (numberVertices == GLUS_MAX_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } sscanf(buffer, "%s %f %f %f", identifier, &x, &y, &z); vertices[4 * numberVertices + 0] = x; vertices[4 * numberVertices + 1] = y; vertices[4 * numberVertices + 2] = z; vertices[4 * numberVertices + 3] = 1.0f; numberVertices++; } else if (strncmp(buffer, "f", 1) == 0) { GLUSchar* token; GLUSint vIndex, vtIndex, vnIndex; GLUSuint edgeCount = 0; token = strtok(buffer, " \t"); token = strtok(0, " \n"); if (!token) { continue; } // Check faces if (strstr(token, "//") != 0) { facesEncoding = 2; } else if (strstr(token, "/") == 0) { facesEncoding = 0; } else if (strstr(token, "/") != 0) { GLUSchar* c = strstr(token, "/"); c++; if (!c) { continue; } if (strstr(c, "/") == 0) { facesEncoding = 1; } else { facesEncoding = 3; } } while (token != 0) { vIndex = -1; vtIndex = -1; vnIndex = -1; switch (facesEncoding) { case 0: sscanf(token, "%d", &vIndex); break; case 1: sscanf(token, "%d/%d", &vIndex, &vtIndex); break; case 2: sscanf(token, "%d//%d", &vIndex, &vnIndex); break; case 3: sscanf(token, "%d/%d/%d", &vIndex, &vtIndex, &vnIndex); break; } vIndex--; vtIndex--; vnIndex--; if (vIndex >= 0) { if (edgeCount < 3) { if (totalNumberVertices >= GLUS_MAX_TRIANGLE_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleVertices[4*totalNumberVertices], &vertices[4*vIndex], 4*sizeof(GLUSfloat)); totalNumberVertices++; } else { if (totalNumberVertices >= GLUS_MAX_TRIANGLE_ATTRIBUTES - 2) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleVertices[4*(totalNumberVertices)], &triangleVertices[4*(totalNumberVertices-edgeCount)], 4*sizeof(GLUSfloat)); memcpy(&triangleVertices[4*(totalNumberVertices+1)], &triangleVertices[4*(totalNumberVertices-1)], 4*sizeof(GLUSfloat)); memcpy(&triangleVertices[4*(totalNumberVertices+2)], &vertices[4*vIndex], 4*sizeof(GLUSfloat)); totalNumberVertices += 3; } } if (vnIndex >= 0) { if (edgeCount < 3) { if (totalNumberNormals >= GLUS_MAX_TRIANGLE_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleNormals[3*totalNumberNormals], &normals[3*vnIndex], 3*sizeof(GLUSfloat)); totalNumberNormals++; } else { if (totalNumberNormals >= GLUS_MAX_TRIANGLE_ATTRIBUTES - 2) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleNormals[3*(totalNumberNormals)], &triangleNormals[3*(totalNumberNormals-edgeCount)], 3*sizeof(GLUSfloat)); memcpy(&triangleNormals[3*(totalNumberNormals+1)], &triangleNormals[3*(totalNumberNormals-1)], 3*sizeof(GLUSfloat)); memcpy(&triangleNormals[3*(totalNumberNormals+2)], &normals[3*vnIndex], 3*sizeof(GLUSfloat)); totalNumberNormals += 3; } } if (vtIndex >= 0) { if (edgeCount < 3) { if (totalNumberTexCoords >= GLUS_MAX_TRIANGLE_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleTexCoords[2*totalNumberTexCoords], &texCoords[2*vtIndex], 2*sizeof(GLUSfloat)); totalNumberTexCoords++; } else { if (totalNumberTexCoords >= GLUS_MAX_TRIANGLE_ATTRIBUTES - 2) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleTexCoords[2*(totalNumberTexCoords)], &triangleTexCoords[2*(totalNumberTexCoords-edgeCount)], 2*sizeof(GLUSfloat)); memcpy(&triangleTexCoords[2*(totalNumberTexCoords+1)], &triangleTexCoords[2*(totalNumberTexCoords-1)], 2*sizeof(GLUSfloat)); memcpy(&triangleTexCoords[2*(totalNumberTexCoords+2)], &texCoords[2*vtIndex], 2*sizeof(GLUSfloat)); totalNumberTexCoords += 3; } } edgeCount++; token = strtok(0, " \n"); } } } fclose(f); result = glusCopyObjData(shape, totalNumberVertices, triangleVertices, totalNumberNormals, triangleNormals, totalNumberTexCoords, triangleTexCoords); glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); if (result) { glusCalculateTangentSpacef(shape); } return result; }
static GLUSboolean glusParseObjFile(const GLUSchar* filename, GLUSshape* shape, GLUSwavefront* wavefront) { GLUSboolean result; FILE* f; GLUSchar buffer[GLUS_BUFFERSIZE]; GLUSchar identifier[7]; GLUSfloat x, y, z; GLUSfloat s, t; GLUSfloat* vertices = 0; GLUSfloat* normals = 0; GLUSfloat* texCoords = 0; GLUSuint numberVertices = 0; GLUSuint numberNormals = 0; GLUSuint numberTexCoords = 0; GLUSfloat* triangleVertices = 0; GLUSfloat* triangleNormals = 0; GLUSfloat* triangleTexCoords = 0; GLUSuint totalNumberVertices = 0; GLUSuint totalNumberNormals = 0; GLUSuint totalNumberTexCoords = 0; GLUSuint facesEncoding = 0; // Material and groups GLUSchar name[GLUS_MAX_STRING]; GLUSuint numberIndicesGroup = 0; GLUSuint numberMaterials = 0; GLUSuint numberGroups = 0; GLUSgroupList* currentGroupList = 0; // Objects GLUSuint numberObjects = 0; if (!filename || !shape) { return GLUS_FALSE; } memset(shape, 0, sizeof(GLUSshape)); f = fopen(filename, "r"); if (!f) { return GLUS_FALSE; } if (!glusMallocTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords)) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } while (!feof(f)) { if (fgets(buffer, GLUS_BUFFERSIZE, f) == 0) { if (ferror(f)) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } } if (wavefront) { if (strncmp(buffer, "mtllib", 6) == 0) { sscanf(buffer, "%s %s", identifier, name); if (numberMaterials == 0) { wavefront->materials = 0; } if (!glusLoadMaterial(name, &wavefront->materials)) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } numberMaterials++; } else if (strncmp(buffer, "usemtl", 6) == 0) { if (!currentGroupList || currentGroupList->group.materialName[0] != '\0') { GLUSgroupList* newGroupList; newGroupList = (GLUSgroupList*)malloc(sizeof(GLUSgroupList)); if (!newGroupList) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } memset(newGroupList, 0, sizeof(GLUSgroupList)); strcpy(newGroupList->group.name, name); if (numberGroups == 0) { wavefront->groups = newGroupList; } else { if (!currentGroupList) { free(newGroupList); glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } currentGroupList->next = newGroupList; currentGroupList->group.numberIndices = numberIndicesGroup; numberIndicesGroup = 0; } currentGroupList = newGroupList; numberGroups++; } // sscanf(buffer, "%s %s", identifier, name); strcpy(currentGroupList->group.materialName, name); } else if (strncmp(buffer, "g", 1) == 0) { GLUSgroupList* newGroupList; sscanf(buffer, "%s %s", identifier, name); newGroupList = (GLUSgroupList*)malloc(sizeof(GLUSgroupList)); if (!newGroupList) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } memset(newGroupList, 0, sizeof(GLUSgroupList)); strcpy(newGroupList->group.name, name); if (numberGroups == 0) { wavefront->groups = newGroupList; } else { if (!currentGroupList) { free(newGroupList); glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } currentGroupList->next = newGroupList; currentGroupList->group.numberIndices = numberIndicesGroup; numberIndicesGroup = 0; } currentGroupList = newGroupList; numberGroups++; } } if (strncmp(buffer, "o", 1) == 0) { if (numberObjects == GLUS_MAX_OBJECTS) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } numberObjects++; } else if (strncmp(buffer, "vt", 2) == 0) { if (numberTexCoords == GLUS_MAX_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } sscanf(buffer, "%s %f %f", identifier, &s, &t); texCoords[2 * numberTexCoords + 0] = s; texCoords[2 * numberTexCoords + 1] = t; numberTexCoords++; } else if (strncmp(buffer, "vn", 2) == 0) { if (numberNormals == GLUS_MAX_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } sscanf(buffer, "%s %f %f %f", identifier, &x, &y, &z); normals[3 * numberNormals + 0] = x; normals[3 * numberNormals + 1] = y; normals[3 * numberNormals + 2] = z; numberNormals++; } else if (strncmp(buffer, "v", 1) == 0) { if (numberVertices == GLUS_MAX_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GLUS_FALSE; } sscanf(buffer, "%s %f %f %f", identifier, &x, &y, &z); vertices[4 * numberVertices + 0] = x; vertices[4 * numberVertices + 1] = y; vertices[4 * numberVertices + 2] = z; vertices[4 * numberVertices + 3] = 1.0f; numberVertices++; } else if (strncmp(buffer, "f", 1) == 0) { GLUSchar* token; GLUSint vIndex, vtIndex, vnIndex; GLUSuint edgeCount = 0; token = strtok(buffer, " \t"); token = strtok(0, " \n"); if (!token) { continue; } // Check faces if (strstr(token, "//") != 0) { facesEncoding = 2; } else if (strstr(token, "/") == 0) { facesEncoding = 0; } else if (strstr(token, "/") != 0) { GLUSchar* c = strstr(token, "/"); c++; if (!c) { continue; } if (strstr(c, "/") == 0) { facesEncoding = 1; } else { facesEncoding = 3; } } while (token != 0) { vIndex = -1; vtIndex = -1; vnIndex = -1; switch (facesEncoding) { case 0: sscanf(token, "%d", &vIndex); break; case 1: sscanf(token, "%d/%d", &vIndex, &vtIndex); break; case 2: sscanf(token, "%d//%d", &vIndex, &vnIndex); break; case 3: sscanf(token, "%d/%d/%d", &vIndex, &vtIndex, &vnIndex); break; } vIndex--; vtIndex--; vnIndex--; if (vIndex >= 0) { if (edgeCount < 3) { if (totalNumberVertices >= GLUS_MAX_TRIANGLE_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleVertices[4 * totalNumberVertices], &vertices[4 * vIndex], 4 * sizeof(GLUSfloat)); totalNumberVertices++; numberIndicesGroup++; } else { if (totalNumberVertices >= GLUS_MAX_TRIANGLE_ATTRIBUTES - 2) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleVertices[4 * (totalNumberVertices)], &triangleVertices[4 * (totalNumberVertices - edgeCount)], 4 * sizeof(GLUSfloat)); memcpy(&triangleVertices[4 * (totalNumberVertices + 1)], &triangleVertices[4 * (totalNumberVertices - 1)], 4 * sizeof(GLUSfloat)); memcpy(&triangleVertices[4 * (totalNumberVertices + 2)], &vertices[4 * vIndex], 4 * sizeof(GLUSfloat)); totalNumberVertices += 3; numberIndicesGroup += 3; } } if (vnIndex >= 0) { if (edgeCount < 3) { if (totalNumberNormals >= GLUS_MAX_TRIANGLE_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleNormals[3 * totalNumberNormals], &normals[3 * vnIndex], 3 * sizeof(GLUSfloat)); totalNumberNormals++; } else { if (totalNumberNormals >= GLUS_MAX_TRIANGLE_ATTRIBUTES - 2) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleNormals[3 * (totalNumberNormals)], &triangleNormals[3 * (totalNumberNormals - edgeCount)], 3 * sizeof(GLUSfloat)); memcpy(&triangleNormals[3 * (totalNumberNormals + 1)], &triangleNormals[3 * (totalNumberNormals - 1)], 3 * sizeof(GLUSfloat)); memcpy(&triangleNormals[3 * (totalNumberNormals + 2)], &normals[3 * vnIndex], 3 * sizeof(GLUSfloat)); totalNumberNormals += 3; } } if (vtIndex >= 0) { if (edgeCount < 3) { if (totalNumberTexCoords >= GLUS_MAX_TRIANGLE_ATTRIBUTES) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleTexCoords[2 * totalNumberTexCoords], &texCoords[2 * vtIndex], 2 * sizeof(GLUSfloat)); totalNumberTexCoords++; } else { if (totalNumberTexCoords >= GLUS_MAX_TRIANGLE_ATTRIBUTES - 2) { glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); fclose(f); return GL_FALSE; } memcpy(&triangleTexCoords[2 * (totalNumberTexCoords)], &triangleTexCoords[2 * (totalNumberTexCoords - edgeCount)], 2 * sizeof(GLUSfloat)); memcpy(&triangleTexCoords[2 * (totalNumberTexCoords + 1)], &triangleTexCoords[2 * (totalNumberTexCoords - 1)], 2 * sizeof(GLUSfloat)); memcpy(&triangleTexCoords[2 * (totalNumberTexCoords + 2)], &texCoords[2 * vtIndex], 2 * sizeof(GLUSfloat)); totalNumberTexCoords += 3; } } edgeCount++; token = strtok(0, " \n"); } } } fclose(f); if (wavefront && currentGroupList) { currentGroupList->group.numberIndices = numberIndicesGroup; numberIndicesGroup = 0; } result = glusCopyObjData(shape, totalNumberVertices, triangleVertices, totalNumberNormals, triangleNormals, totalNumberTexCoords, triangleTexCoords); glusFreeTempMemory(&vertices, &normals, &texCoords, &triangleVertices, &triangleNormals, &triangleTexCoords); if (result) { glusCalculateTangentSpacef(shape); } return result; }