| 56 | } |
| 57 | |
| 58 | std::vector<CarModel> NFS4::LoadFCE(const std::string &fce_path) { |
| 59 | std::cout << "- Parsing FCE File: " << fce_path << std::endl; |
| 60 | glm::quat rotationMatrix = glm::normalize(glm::quat(glm::vec3(-SIMD_PI / 2, 0, 0))); // All Vertices are stored so that the model is rotated 90 degs on X. Remove this at Vert load time. |
| 61 | std::vector<CarModel> meshes; |
| 62 | bool isTraffic = fce_path.find("TRAFFIC") != std::string::npos; |
| 63 | |
| 64 | ifstream fce(fce_path, ios::in | ios::binary); |
| 65 | |
| 66 | auto *fceHeader = new FCE::NFS4::HEADER(); |
| 67 | fce.read((char *) fceHeader, sizeof(FCE::NFS4::HEADER)); |
| 68 | |
| 69 | |
| 70 | for (uint32_t part_Idx = 0; part_Idx < fceHeader->nParts; ++part_Idx) { |
| 71 | float specularDamper = 0.2f; |
| 72 | float specularReflectivity = 0.02f; |
| 73 | float envReflectivity = 0.4f; |
| 74 | |
| 75 | std::vector<uint32_t> indices; |
| 76 | std::vector<uint32_t> polygonFlags; |
| 77 | std::vector<glm::vec3> vertices; |
| 78 | std::vector<glm::vec3> normals; |
| 79 | std::vector<glm::vec2> uvs; |
| 80 | |
| 81 | std::string part_name(fceHeader->partNames[part_Idx]); |
| 82 | glm::vec3 center = rotationMatrix * glm::vec3(fceHeader->partCoords[part_Idx].x / 10, fceHeader->partCoords[part_Idx].y / 10, fceHeader->partCoords[part_Idx].z / 10); |
| 83 | |
| 84 | auto *partVertices = new FLOATPT[fceHeader->partNumVertices[part_Idx]]; |
| 85 | auto *partNormals = new FLOATPT[fceHeader->partNumVertices[part_Idx]]; |
| 86 | auto *partTriangles = new FCE::TRIANGLE[fceHeader->partNumTriangles[part_Idx]]; |
| 87 | |
| 88 | fce.seekg(sizeof(FCE::NFS4::HEADER) + fceHeader->vertTblOffset + (fceHeader->partFirstVertIndices[part_Idx] * sizeof(FLOATPT)), ios_base::beg); |
| 89 | fce.read((char *) partVertices, fceHeader->partNumVertices[part_Idx] * sizeof(FLOATPT)); |
| 90 | for (uint32_t vert_Idx = 0; vert_Idx < fceHeader->partNumVertices[part_Idx]; ++vert_Idx) { |
| 91 | vertices.emplace_back(rotationMatrix * glm::vec3(partVertices[vert_Idx].x / 10, partVertices[vert_Idx].y / 10, partVertices[vert_Idx].z / 10)); |
| 92 | } |
| 93 | |
| 94 | fce.seekg(sizeof(FCE::NFS4::HEADER) + fceHeader->normTblOffset + (fceHeader->partFirstVertIndices[part_Idx] * sizeof(FLOATPT)), ios_base::beg); |
| 95 | fce.read((char *) partNormals, fceHeader->partNumVertices[part_Idx] * sizeof(FLOATPT)); |
| 96 | for (uint32_t normal_Idx = 0; normal_Idx < fceHeader->partNumVertices[part_Idx]; ++normal_Idx) { |
| 97 | normals.emplace_back(rotationMatrix * glm::vec3(partNormals[normal_Idx].x, partNormals[normal_Idx].y, partNormals[normal_Idx].z)); |
| 98 | } |
| 99 | |
| 100 | fce.seekg(sizeof(FCE::NFS4::HEADER) + fceHeader->triTblOffset + (fceHeader->partFirstTriIndices[part_Idx] * sizeof(FCE::TRIANGLE)), ios_base::beg); |
| 101 | fce.read((char *) partTriangles, fceHeader->partNumTriangles[part_Idx] * sizeof(FCE::TRIANGLE)); |
| 102 | for (uint32_t tri_Idx = 0; tri_Idx < fceHeader->partNumTriangles[part_Idx]; ++tri_Idx) { |
| 103 | polygonFlags.emplace_back(partTriangles[tri_Idx].polygonFlags); |
| 104 | polygonFlags.emplace_back(partTriangles[tri_Idx].polygonFlags); |
| 105 | polygonFlags.emplace_back(partTriangles[tri_Idx].polygonFlags); |
| 106 | parsePolygonFlags(tri_Idx, partTriangles[tri_Idx].polygonFlags); |
| 107 | indices.emplace_back(partTriangles[tri_Idx].vertex[0]); |
| 108 | indices.emplace_back(partTriangles[tri_Idx].vertex[1]); |
| 109 | indices.emplace_back(partTriangles[tri_Idx].vertex[2]); |
| 110 | if (isTraffic) { |
| 111 | uvs.emplace_back(glm::vec2(partTriangles[tri_Idx].uvTable[0], partTriangles[tri_Idx].uvTable[3])); |
| 112 | uvs.emplace_back(glm::vec2(partTriangles[tri_Idx].uvTable[1], partTriangles[tri_Idx].uvTable[4])); |
| 113 | uvs.emplace_back(glm::vec2(partTriangles[tri_Idx].uvTable[2], partTriangles[tri_Idx].uvTable[5])); |
| 114 | } else { |
| 115 | uvs.emplace_back(glm::vec2(partTriangles[tri_Idx].uvTable[0], 1.0f - partTriangles[tri_Idx].uvTable[3])); |
nothing calls this directly
no test coverage detected