#include "VisibilitySolutionConverter.h" #include "SimpleTri.h" #include "SimpleVec.h" #include "gzstream.h" #include using namespace std; // MAGIC of all bin exports #ifndef MAGIC #define MAGIC 0x827923 #endif #define BVH_VERSION 2.1 static void LoadIndices(char *str, const VertexArray &vertices, const VertexArray &normals, const vector > &texCoords, VertexArray &faceVertices, VertexArray &faceNormals, vector &faceTexCoords ) { vector triples; char *next_token; // extract the triples of the form v/t/n v/t/n ... char *pch = strtok_s(str + 1, " ", &next_token); while (pch) { string s(pch); //s += "\n", triples.push_back(s); pch = strtok_s(NULL, " ", &next_token); } vector indices; vector nIndices; vector tIndices; char seps[] = " /\t\n"; for (size_t i = 0; i < triples.size(); ++ i) { static int dummy = 0; size_t found; found = triples[i].find_first_of(seps); size_t prevfound = 0; // vertex, normal, texture indices string str = triples[i].substr(prevfound, found); int index = (int)strtol(str.c_str(), NULL, 10) - 1; int tIndex = index; int nIndex = index; prevfound = found; found = triples[i].find_first_of(seps, found + 1); if (found != string::npos) { str = triples[i].substr(prevfound, found); int idx = (int)strtol(str.c_str(), NULL, 10) - 1; if (idx > 0) tIndex = idx; } if ((found + 1) < triples[i].size()) { str = triples[i].substr(found + 1); int idx = (int)strtol(str.c_str(), NULL, 10) - 1; if (idx > 0) nIndex = idx; } // store indices if (index >= 0) { indices.push_back(index); nIndices.push_back(nIndex); tIndices.push_back(tIndex); } // new triangle found if (indices.size() > 2) { // change orientation of faces? #if 1 int idx1 = 0; int idx2 = (int)indices.size() - 2; int idx3 = (int)indices.size() - 1; #else int idx3 = 0; int idx2 = (int)indices.size() - 2; int idx1 = (int)indices.size() - 1; #endif faceVertices.push_back(vertices[indices[idx1]]); faceVertices.push_back(vertices[indices[idx2]]); faceVertices.push_back(vertices[indices[idx3]]); if (!normals.empty()) { faceNormals.push_back(normals[nIndices[idx1]]); faceNormals.push_back(normals[nIndices[idx2]]); faceNormals.push_back(normals[nIndices[idx3]]); } else { // no face normals? => create normals const SimpleTri tri(vertices[indices[idx1]], vertices[indices[idx2]], vertices[indices[idx3]]); const SimpleVec n = tri.GetNormal(); faceNormals.push_back(n); faceNormals.push_back(n); faceNormals.push_back(n); } if (!texCoords.empty()) { faceTexCoords.push_back(texCoords[tIndices[idx1]]); faceTexCoords.push_back(texCoords[tIndices[idx2]]); faceTexCoords.push_back(texCoords[tIndices[idx3]]); } } } } VisibilitySolutionConverter::VisibilitySolutionConverter() {} VisibilitySolutionConverter::~VisibilitySolutionConverter() { for (size_t i = 0; i < mGeometry.size(); ++ i) { delete [] mGeometry[i]->mVertices; delete [] mGeometry[i]->mNormals; delete [] mGeometry[i]->mTexCoords; delete mGeometry[i]; } mGeometry.clear(); } void VisibilitySolutionConverter::LoadShape(const VertexArray &vertices, const VertexArray &normals, const vector &texCoords) { int numElements = (int)vertices.size(); Geometry *geom = new Geometry(); // convert the triangles to geometry geom->mVertices = new SimpleVec[numElements]; geom->mNormals = new SimpleVec[numElements]; geom->mTexCoords = new TexCoord[numElements]; geom->mVertexCount = numElements; geom->mTexcoordCount = (int)texCoords.size(); cout << "number of vertices=" << numElements << endl; for (int i = 0; i < numElements; ++ i) { #if 1 // convert to our camera system: change y and z geom->mVertices[i].x = vertices[i].x; geom->mVertices[i].y = -vertices[i].z; geom->mVertices[i].z = vertices[i].y; geom->mNormals[i].x = normals[i].x; geom->mNormals[i].y = -normals[i].z; geom->mNormals[i].z = normals[i].y; #else geom->mVertices[i].x = vertices[i].x; geom->mVertices[i].y = vertices[i].y; geom->mVertices[i].z = vertices[i].z; geom->mNormals[i].x = normals[i].x; geom->mNormals[i].y = normals[i].y; geom->mNormals[i].z = normals[i].z; #endif if (i < geom->mTexcoordCount) { geom->mTexCoords[i].first = texCoords[i].first; geom->mTexCoords[i].second = texCoords[i].second; } } mGeometry.push_back(geom); } bool VisibilitySolutionConverter::Convert(const std::string &sceneInputFilename, const std::string &sceneOutputFilename, const std::string &bvhInputFilename, const std::string &bvhOutputFilename) { mNumShapes = 0; // delete previous geometry for (size_t i = 0; i < mGeometry.size(); ++ i) { delete [] mGeometry[i]->mVertices; delete [] mGeometry[i]->mNormals; delete [] mGeometry[i]->mTexCoords; delete mGeometry[i]; } mGeometry.clear(); if (!LoadSolution(bvhInputFilename)) { cerr << "could not read file" << endl; return false; } if (!ReadScene(sceneInputFilename)) { cerr << "could not read file" << endl; return false; } if (!WriteScene(sceneOutputFilename)) { cerr << "could not write file" << endl; return false; } /*if (!WriteBvh(bvhOutputFilename)) { cerr << "could not write file" << endl; return false; }*/ return true; } bool VisibilitySolutionConverter::ReadScene(const string &filename) { FILE *file; if ((file = fopen(filename.c_str(), "r")) == NULL) { return false; } VertexArray faceVertices; VertexArray faceNormals; vector faceTexcoords; VertexArray vertices; VertexArray normals; vector texcoords; vector indices; int line = 0; const int len = 10000; char str[len]; while (fgets(str, len, file) != NULL) { if (line % 1000000 == 0) cout << line << " " << str << endl; ++ line; switch (str[0]) { case 'v': // vertex or normal { float x, y, z; if (vertices.size() >= 1000000 * 3) continue; switch (str[1]) { case 'n' : sscanf(str + 2, "%f %f %f", &x, &y, &z); normals.push_back(SimpleVec(x, y, z)); break; case 't': sscanf(str + 2, "%f %f", &x, &y); texcoords.push_back(pair(x, y)); break; default: sscanf(str + 1, "%f %f %f", &x, &y, &z); //const float scale = 5e-3f; const float scale = 0.1f; vertices.push_back(SimpleVec(x * scale, y * scale, z * scale)); //cout <<"v " << x << " " << y << " "<< z << " "; } break; } case 'f': { ////////// //-- indices in the current line if (faceVertices.size() >= 1000000 * 3) continue; LoadIndices(str, vertices, normals, texcoords, faceVertices, faceNormals, faceTexcoords); break; } break; default: // throw away line break; } } if (!faceVertices.empty()) { ++ mNumShapes; ConstructBvhObjects(faceVertices, faceNormals, faceTexcoords); faceVertices.clear(); faceNormals.clear(); faceTexcoords.clear(); } fclose(file); return true; } static inline float RandomColor(float x) { return x + (1.0f - x) * (float)rand() / RAND_MAX; } void VisibilitySolutionConverter::WriteGeometry(ogzstream &str, Geometry *geom) { int vertexCount = geom->mVertexCount; str.write(reinterpret_cast(&vertexCount), sizeof(int)); str.write(reinterpret_cast(geom->mVertices), sizeof(SimpleVec) * vertexCount); str.write(reinterpret_cast(geom->mNormals), sizeof(SimpleVec) * vertexCount); int texCoordCount = 0;//geom->mTexcoordCount; str.write(reinterpret_cast(&texCoordCount), sizeof(int)); if (texCoordCount) { str.write(reinterpret_cast(geom->mTexCoords), sizeof(float) * texCoordCount * 2); } /////// //-- texture int texId = -1; str.write(reinterpret_cast(&texId), sizeof(int)); bool alphaTestEnabled = false; bool cullFaceEnabled = true; str.write(reinterpret_cast(&alphaTestEnabled), sizeof(bool)); str.write(reinterpret_cast(&cullFaceEnabled), sizeof(bool)); // material bool hasMaterial = true; str.write(reinterpret_cast(&hasMaterial), sizeof(bool)); if (hasMaterial) { SimpleVec ambient, diffuse, spec, emm; ambient.x = ambient.y = ambient.z = 0.2f; //diffuse.x = diffuse.y = diffuse.z = 1.0f; diffuse.x = RandomColor(0.5f); diffuse.y = RandomColor(0.5f); diffuse.z = RandomColor(0.5f); spec.x = spec.y = spec.z = .0f; emm = spec; // only write rgb part of the material str.write(reinterpret_cast(&ambient), sizeof(SimpleVec)); str.write(reinterpret_cast(&diffuse), sizeof(SimpleVec)); str.write(reinterpret_cast(&spec), sizeof(SimpleVec)); str.write(reinterpret_cast(&emm), sizeof(SimpleVec)); } } bool VisibilitySolutionConverter::WriteScene(const string &filename) { ogzstream ofile(filename.c_str()); if (!ofile.is_open()) return false; int textureCount = 0; ofile.write(reinterpret_cast(&textureCount), sizeof(int)); /////////// //-- write shapes int numShapes = (int)mGeometry.size(); ofile.write(reinterpret_cast(&numShapes), sizeof(int)); vector::const_iterator it, it_end = mGeometry.end(); for (it = mGeometry.begin(); it != it_end; ++ it) { WriteGeometry(ofile, *it); } int entityCount = numShapes; ofile.write(reinterpret_cast(&entityCount), sizeof(int)); ////////// //-- write single scene entity for each shape // all shapes belong to this scene entity for (int i = 0; i < numShapes; ++ i) { // no transformation bool hasTrafo = false; ofile.write(reinterpret_cast(&hasTrafo), sizeof(bool)); // a dummy lod int numLODs = 1; ofile.write(reinterpret_cast(&numLODs), sizeof(int)); float dist = 0; ofile.write(reinterpret_cast(&dist), sizeof(float)); int shapesPerEnt = 1; ofile.write(reinterpret_cast(&shapesPerEnt), sizeof(int)); int shapeId = i; ofile.write(reinterpret_cast(&shapeId), sizeof(int)); } return true; } void VisibilitySolutionConverter::ConstructBvhObjects(const VertexArray &vertices, const VertexArray &normals, const vector &texCoords) { cout << "vtx: " << vertices.size() << endl; for (size_t i = 0; i < mBvhNodes.size(); ++ i) { VertexArray _vertices; VertexArray _normals; vector _texCoords; BvhNode *node = mBvhNodes[i]; //for (size_t j = 0; j < node->mTriangleIds.size(); ++ j) for (int j = node->first; j < node->last; ++ j) { const int idx = 3 * mGlobalTriangleIds[j]; //cout << "idx: " << idx << " "; if (idx < 1000000 * 3) { for (int k = 0; k < 3; ++ k) { _vertices.push_back(vertices[idx + k]); _normals.push_back(normals[idx + k]); //_texCoords.push_back(texCoords[idx + k]); } } } if (!_vertices.empty()) { ++ mNumShapes; LoadShape(_vertices, _normals, _texCoords); } } } bool VisibilitySolutionConverter::WriteBvh(const string &filename) { return true; } bool VisibilitySolutionConverter::ReadBvh(FILE *fr) { int buffer[6]; fread(buffer, sizeof(int), 6, fr); if (buffer[0] != MAGIC) { cerr << "Error: Wrong file type" << endl; return false; } if (buffer[1] != (int)(1000 * BVH_VERSION)) { cerr << "Error: Wrong BVH version" << endl; return false; } // load triangle ids size_t numTriangles = buffer[2]; for (size_t i = 0; i < numTriangles; ++i) { int id; fread(&id, sizeof(int), 1, fr); mGlobalTriangleIds.push_back(id); //triangles[i] = scene->triangles[id]; } //if (mRoot) delete mRoot; mNumNodes = 0; // this was set to 1 in constructor! mRoot = LoadNode(fr, 0); if (mNumNodes != buffer[5]) { cerr << "Warning: Loaded " << mNumNodes << " bvh nodes instead of " << buffer[5] << endl; } fclose(fr); return true; } BvhNode *VisibilitySolutionConverter::LoadNode(FILE *fr, int depth) { ++ mNumNodes; int buffer[4]; fread(buffer, sizeof(int), 4, fr); if (buffer[2] != -1) { BvhInterior *interior = new BvhInterior(); interior->first = buffer[0]; interior->last = buffer[1]; interior->axis = buffer[2]; interior->id = buffer[3]; interior->depth = depth; BvhNode *front, *back; front = LoadNode(fr, depth + 1); back = LoadNode(fr, depth + 1); // front->parent = (BvhNode *)interior; // back->parent = (BvhNode *)interior; interior->front = front; interior->back = back; //interior->box = Union(front->box, back->box); return (BvhNode *)interior; } else { // leaf //Debug << "Info: Loading leaf (id: " << numberOfNodes << ", depth: " << depth << ")" << endl; BvhLeaf *leaf = new BvhLeaf(); leaf->first = buffer[0]; leaf->last = buffer[1]; leaf->axis = buffer[2]; leaf->id = buffer[3]; leaf->depth = depth; //UpdateLeafBox(leaf); mBvhNodes.push_back(leaf); // leaf->id = numberOfNodes; return (BvhNode *)leaf; } } bool VisibilitySolutionConverter::ReadDummyTree(FILE *fr) { int buffer[256]; fread(buffer, sizeof(int), 3, fr); // read dummy bounding box float dummy[6]; fread(dummy, sizeof(float) * 6, 1, fr); int stack = 1; // read dummy tree while (stack) { int axis; fread(&axis, sizeof(int), 1, fr); -- stack; if (axis != - 1) { float dummy; fread(&dummy, sizeof(float), 1, fr); stack += 2; } } return true; } bool VisibilitySolutionConverter::LoadSolution(const string &filename) { FILE *fr = fopen(filename.c_str(), "rb"); cerr << "Info: Loading visibility solution from file '" + filename + "'" << endl; if (fr == NULL) { cerr << "Error: Cannot open file for reading" << endl; return false; } float totalSamples, totalTime; fread(&totalSamples, sizeof(float), 1, fr); fread(&totalTime, sizeof(float), 1, fr); //viewCellsTree = new ViewCellsTree; //bool ok = viewCellsTree->_LoadFromFile(fr); bool ok = ReadDummyTree(fr); if (ok) { //AllocateLeafViewCells(); //objectsTree = new Bvh(*scene); //ok = objectsTree->_LoadFromFile(fr); ok = ReadBvh(fr); /*if (ok) { AllocatePvsObjects(); ok = LoadPvs(fr); } */ } fclose(fr); if (ok) cout << "Info: visibility solution loaded" << endl; else cout << "Info: loading visibility solution failed" << endl; return true; } #if 0 bool VisibilitySolution::LoadPvs(FILE *fw) { int number, entries; fread(&number, sizeof(int), 1, fw); if (number == 0) { Message("Info: Warning empty PVSs in visibility solution"); return true; } if (number != viewCells.size()) { Message("Info: Number of view cells does not match when loading PVSs!"); return false; } for (int i=0; i < number; i++) { fread(&entries, sizeof(int), 1, fw); for (int j=0; j < entries; j++) { int objectId; float time; fread(&objectId, sizeof(int), 1, fw); fread(&time, sizeof(float), 1, fw); viewCells[i]->pvs.Insert(objectId, time); } } return true; } bool ViewCellsTree::_LoadFromFile(FILE *fr) { int buffer[256]; fread(buffer, sizeof(int), 3, fr); if (buffer[0] != MAGIC) { Message( "Error: Wrong file type"); return false; } if (buffer[1] != (int)(1000*VIEWCELLS_VERSION)) { Message( "Error: Wrong viewcells version" ); return false; } // get the bounding box fread(&box, sizeof(AxisAlignedBox3), 1, fr); stack nodeStack; nodeStack.push(&root); while(!nodeStack.empty()) { ViewCellsTreeNode *&node = *nodeStack.top(); nodeStack.pop(); node = new ViewCellsTreeNode; fread(&node->axis, sizeof(int), 1, fr); if (!node->IsLeaf()) { fread(&node->position, sizeof(float), 1, fr); nodeStack.push(&node->front); nodeStack.push(&node->back); } } return true; } #endif