#include #include #include #include #include using namespace std; #include "Vector3.h" #include "Mesh.h" #include "SceneGraph.h" #include "ObjParser.h" //#include "Material.h" #include "Triangle3.h" #include "Environment.h" #include "ResourceManager.h" #include "IntersectableWrapper.h" namespace GtpVisibilityPreprocessor { #define CONNECT_SEQUENTIAL_FACES 0 #define ROTATE_SCENE 0 // hack: define this as in the intel ray tracer #define FLT_EPSILON 1.192092896e-07f // HACK static void RotateMesh(Mesh *mesh) { VertexContainer::iterator it, it_end = mesh->mVertices.end(); const float angle = 30.0f * PI / 180.0f; const Matrix4x4 rot = RotationYMatrix(angle); for (it = mesh->mVertices.begin(); it != it_end; ++ it) { (*it) = rot * (*it); } } struct ltstr { bool operator()(const string s1, const string s2) const { return s1 < s2; } }; static Face *LoadFace(char *str, const VertexContainer &vertices, map &hashTable) { char *pch = strtok(str + 1, " "); VertexIndexContainer indices; while (pch != NULL) { const int index = (int)strtol(pch, NULL, 10) - 1; //Debug << index << " x "; // store vertex in hash table hashTable[index] = vertices[index]; indices.push_back(index); pch = strtok(NULL, " "); } return new Face(indices); } static void LoadTriangles(char *str, const VertexContainer &vertices, map &hashTable, vector &triangles) { char *pch = strtok(str + 1, " "); VertexIndexContainer indices; int i = 0; while (pch != NULL) { const int index = (int)strtol(pch, NULL, 10) - 1; ++ i; // store vertex in hash table //hashTable[index] = vertices[index]; indices.push_back(index); pch = strtok(NULL, " "); // problem: don't know how intel ray tracer tesselates if ((int)indices.size() > 2) { int index_2 = (int)indices.size() - 2; int index_3 = (int)indices.size() - 1; triangles.push_back(Triangle3(vertices[indices[0]], vertices[indices[index_2]], vertices[indices[index_3]])); } } } static Mesh *CreateMesh(FaceContainer &faces, const map &hashTable) { Mesh *mesh = MeshManager::GetSingleton()->CreateResource(); FaceContainer::const_iterator fit, fit_end = faces.end(); for (fit = faces.begin(); fit != fit_end; ++ fit) { Face *face = *fit; VertexIndexContainer::iterator vit, vit_end = face->mVertexIndices.end(); for (vit = face->mVertexIndices.begin(); vit != vit_end; ++ vit) { // go through indices const int index = *vit; //Debug << "old idx: " << (*vit) << endl; map::const_iterator hit = hashTable.find(index); // correct face index (nust be relative to start of verices) (*vit) = (int)distance(hashTable.begin(), hit); //Debug << "new idx: " << (*vit) << endl; } } VertexContainer vertices; map::const_iterator hit, hit_end = hashTable.end(); // store vertices in given order for (hit = hashTable.begin(); hit != hit_end; ++ hit) { mesh->mVertices.push_back((*hit).second); } mesh->mFaces = faces; // can't do cleanup because coupling with kdf file for intel ray tracer mesh->Preprocess(false); return mesh; } // HACK: associate mesh instances with triangles static void AssociateFacesWithInstance(MeshInstance *mi, vector &parents) { Mesh *mesh = mi->GetMesh(); int i = 0; FaceContainer::const_iterator fit, fit_end = mesh->mFaces.end(); for (fit = mesh->mFaces.begin(); fit != fit_end; ++ fit, i++) { parents.push_back(FaceParentInfo(mi, i)); } } static void ProcessMesh(FaceContainer &faces, map &hashTable, SceneGraphNode *root, vector *parents) { Mesh *mesh = CreateMesh(faces, hashTable); // make an instance of this mesh MeshInstance *mi = new MeshInstance(mesh); if (parents) { AssociateFacesWithInstance(mi, *parents); } root->mGeometry.push_back(mi); // reset tables hashTable.clear(); faces.clear(); } bool TriangleValid(const Triangle3 &triangle) { const Vector3 a = triangle.mVertices[0] - triangle.mVertices[1]; const Vector3 b = triangle.mVertices[0] - triangle.mVertices[2]; const Vector3 cross_a_b = CrossProd(a, b); if (SqrMagnitude(cross_a_b) <= 0.000001 * FLT_EPSILON * FLT_EPSILON) { // v0, v1 & v2 lays on a line (area == 0) return false; } return true; } bool ObjParser::ParseFile(const string filename, SceneGraphNode *root, const bool loadMeshes, vector *parents) { FILE *file; if ((file = fopen(filename.c_str(), "rt")) == NULL) { return false; } map hashTable; // table associating indices with vectors VertexContainer vertices; // table for vertices FaceContainer faces; char str[100]; int meshGrouping; Environment::GetSingleton()->GetIntValue("ObjParser.meshGrouping", meshGrouping); int nMaxFaces = meshGrouping; while (fgets(str, 80, file) != NULL) { switch (str[0]) { case 'v': // vertex or normal { switch (str[1]) { case 'n' : // normal do nothing break; default: float x, y, z; //cout << "v"; sscanf(str + 1, "%f %f %f", &x, &y, &z); vertices.push_back(Vector3(x,y,z)); //cout << "vertex: " << vertices.back() << endl; } break; } case 'f': { // cout << "f"; if (loadMeshes) { Face *face = LoadFace(str, vertices, hashTable); if (!face) break; faces.push_back(face); if (faces.size() >= nMaxFaces) { ProcessMesh(faces, hashTable, root, parents); } } else { vector triangles; LoadTriangles(str, vertices, hashTable, triangles); vector::const_iterator tit, tit_end = triangles.end(); for (tit = triangles.begin(); tit != tit_end; ++ tit) { if (!TriangleValid(*tit)) continue; TriangleIntersectable *obj = new TriangleIntersectable(*tit); root->mGeometry.push_back(obj); // matt: we don't really need to keep an additional data structure // if working with triangles => remove this if (0 && parents) { FaceParentInfo info(obj, 0); parents->push_back(info); } } } break; } // end face default: break; } } if (loadMeshes) { // there could be faces remaining if (!faces.empty()) { ProcessMesh(faces, hashTable, root, parents); } } // reset tables hashTable.clear(); faces.clear(); fclose(file); return true; } }