#include "ObjConverter.h" #include "gzstream.h" #include using namespace std; static void LoadIndices(char *str, const VertexArray &vertices, const VertexArray &normals, const vector > &texcoords, VertexArray &faceVertices, VertexArray &faceNormals, vector &faceTexcoords ) { vector substrings; 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 != NULL) { substrings.push_back(pch); pch = strtok_s(NULL, " ", &next_token); } vector indices; vector nIndices; vector tIndices; for (size_t i = 0; i < substrings.size(); ++ i) { // vertex, normal and texture indices char *str = strtok_s(substrings[i], "/", &next_token); int index = (int)strtol(str, NULL, 10) - 1; int tIndex = index; int nIndex = index; /*str = strtok_s(substrings[i], "/", &next_token); int tIndex = (int)strtol(str, NULL, 10) - 1; str = strtok_s(substrings[i], "/", &next_token); int nIndex = (int)strtol(str, NULL, 10) - 1; */ // store indices if (index >= 0) { indices.push_back(index); nIndices.push_back(nIndex); tIndices.push_back(tIndex); } // new triangle found if (indices.size() > 2) { #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]]); Vector3 dummy(1, 0, 0); faceNormals.push_back(dummy); faceNormals.push_back(dummy); faceNormals.push_back(dummy); /* const Vector3 v2 = mVertices[2] - mVertices[1]; Normalize(CrossProd(v2, v1)); faceNormals.push_back(normals[nIndices[idx1]]); faceNormals.push_back(normals[nIndices[idx2]]); faceNormals.push_back(normals[nIndices[idx3]]); faceTexcoords.push_back(texcoords[tIndices[idx1]]); faceTexcoords.push_back(texcoords[tIndices[idx2]]); faceTexcoords.push_back(texcoords[tIndices[idx3]]); */ } } } ObjConverter::ObjConverter() {} ObjConverter::~ObjConverter() { 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 ObjConverter::LoadShape(const VertexArray &faceVertices, const VertexArray &faceNormals, const vector &faceTexcoords) { int numElements = (int)faceVertices.size(); Geometry *geom = new Geometry(); // convert the triangles to geometry geom->mVertices = new Vector3[numElements]; geom->mNormals = new Vector3[numElements]; geom->mTexcoords = new Texcoord[numElements]; geom->mVertexCount = numElements; geom->mTexcoordCount = (int)faceTexcoords.size(); cout << "number of vertices=" << numElements << endl; for (int i = 0; i < numElements; ++ i) { geom->mVertices[i].x = faceVertices[i].x; geom->mVertices[i].y = -faceVertices[i].z; geom->mVertices[i].z = faceVertices[i].y; geom->mNormals[i].x = faceNormals[i].x; geom->mNormals[i].y = -faceNormals[i].z; geom->mNormals[i].z = faceNormals[i].y; if (i < geom->mTexcoordCount) { geom->mTexcoords[i].first = faceTexcoords[i].first; geom->mTexcoords[i].second = faceTexcoords[i].second; } } mGeometry.push_back(geom); } bool ObjConverter::Convert(const string &filename, const std::string &outputFilename) { mNumShapes = 0; 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 (!ReadFile(filename)) { cerr << "could not read file" << endl; return false; } if (!WriteFile(outputFilename)) { cerr << "could not write file" << endl; return false; } return true; } bool ObjConverter::ReadFile(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) { //cout << str; switch (str[0]) { case 'v': // vertex or normal { float x, y, z; switch (str[1]) { case 'n' : sscanf(str + 2, "%f %f %f", &x, &y, &z); normals.push_back(Vector3(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); vertices.push_back(Vector3(x, y, z)); //cout <<"v " << x << " " << y << " "<< z << " "; } break; } case 'f': { ////////// //-- indices in the current line LoadIndices(str, vertices, normals, texcoords, faceVertices, faceNormals, faceTexcoords); if (((line % 1000) == 999) && !faceVertices.empty()) { ++ mNumShapes; LoadShape(faceVertices, faceNormals, faceTexcoords); faceVertices.clear(); faceNormals.clear(); faceTexcoords.clear(); } break; } // end face case 'g': {/* if (!faceVertices.empty()) { ++ mNumShapes; LoadShape(faceVertices, faceNormals, faceTexcoords); faceVertices.clear(); faceNormals.clear(); faceTexcoords.clear(); }*/ } break; default: break; } ++ line; } if (!faceVertices.empty()) { ++ mNumShapes; LoadShape(faceVertices, faceNormals, faceTexcoords); faceVertices.clear(); faceNormals.clear(); faceTexcoords.clear(); } fclose(file); return true; } void ObjConverter::WriteGeometry(ogzstream &str, Geometry *geom) { int vertexCount = geom->mVertexCount; str.write(reinterpret_cast(&vertexCount), sizeof(int)); str.write(reinterpret_cast(geom->mVertices), sizeof(Vector3) * vertexCount); str.write(reinterpret_cast(geom->mNormals), sizeof(Vector3) * vertexCount); int texCoordCount = 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; //int texId = 0; str.write(reinterpret_cast(&texId), sizeof(int)); bool alphaTestEnabled = false; bool cullFaceEnabled = false; //bool cullFaceEnabled = true; str.write(reinterpret_cast(&alphaTestEnabled), sizeof(bool)); str.write(reinterpret_cast(&cullFaceEnabled), sizeof(bool)); // material //bool hasMaterial = true; bool hasMaterial = false; str.write(reinterpret_cast(&hasMaterial), sizeof(bool)); if (hasMaterial) { Vector3 ambient, diffuse, black; ambient.x = ambient.y = ambient.z = 0.2f; diffuse.x = diffuse.y = diffuse.z = 1.0f; black.x = black.y = black.z = .0f; // only write rgb part of the material str.write(reinterpret_cast(&ambient), sizeof(Vector3)); str.write(reinterpret_cast(&diffuse), sizeof(Vector3)); str.write(reinterpret_cast(&black), sizeof(Vector3)); str.write(reinterpret_cast(&black), sizeof(Vector3)); } } bool ObjConverter::WriteFile(const string &filename) { ogzstream ofile(filename.c_str()); if (!ofile.is_open()) return false; ///////// //-- write textures //int textureCount = 1; int textureCount = 0; ofile.write(reinterpret_cast(&textureCount), sizeof(int)); if (textureCount > 0) { const string texName("wood.jpg"); int texnameSize = (int)texName.length() + 1; ofile.write(reinterpret_cast(&texnameSize), sizeof(int)); ofile.write(texName.c_str(), sizeof(char) * texnameSize); int boundS = 1; int boundT = 1; ofile.write(reinterpret_cast(&boundS), sizeof(int)); ofile.write(reinterpret_cast(&boundT), sizeof(int)); } /////////// //-- write shapes ofile.write(reinterpret_cast(&mNumShapes), sizeof(int)); vector::const_iterator it, it_end = mGeometry.end(); for (it = mGeometry.begin(); it != it_end; ++ it) { WriteGeometry(ofile, *it); } int entityCount = 1; ofile.write(reinterpret_cast(&entityCount), sizeof(int)); ////////// //-- write single scene entity // 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)); ofile.write(reinterpret_cast(&mNumShapes), sizeof(int)); // all shapes belong to this scene entity for (int i = 0; i < mNumShapes; ++ i) { int shapeId = i; ofile.write(reinterpret_cast(&shapeId), sizeof(int)); } return true; }