bgfx/3rdparty/openctm/tools/off.cpp

253 lines
7.3 KiB
C++

//-----------------------------------------------------------------------------
// Product: OpenCTM tools
// File: off.cpp
// Description: Implementation of the OFF file format importer/exporter.
//-----------------------------------------------------------------------------
// Copyright (c) 2009-2010 Marcus Geelnard
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// The "Object File Format" (OFF) is, among other things, used by the Princeton
// Shape Benchmark data set (http://shape.cs.princeton.edu/benchmark). The file
// format specification can be found here:
// http://people.sc.fsu.edu/~burkardt/data/off/off.html
//-----------------------------------------------------------------------------
#include "common.h"
#include <fstream>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
#include <list>
#include "off.h"
#include "common.h"
using namespace std;
// Read the next line in a file (skip comments and empty lines)
static void ReadNextLine(ifstream &aStream, string &aResult, string &aComment)
{
while(true)
{
// Read another line from the file
string line;
getline(aStream, line);
// Check for comment
size_t commentPos = line.find('#');
if(commentPos != string::npos)
{
string lineComment = TrimString(line.substr(commentPos + 1));
if(lineComment.size() > 0)
{
if(aComment.size() > 0)
aComment = aComment + string(" ") + lineComment;
else
aComment = lineComment;
}
line = line.substr(0, commentPos);
}
// Trim the string
aResult = TrimString(line);
// Non-empty line?
if((aResult.size() > 0) || aStream.eof())
return;
}
}
// Parse a 7 x float string as a Vector3 and a Vector4 element
static void ParseVeretex(const string aString, Vector3 * aCoord, Vector4 * aColor)
{
istringstream sstr(aString);
sstr >> aCoord->x;
sstr >> aCoord->y;
sstr >> aCoord->z;
sstr >> aColor->x;
sstr >> aColor->y;
sstr >> aColor->z;
sstr >> aColor->w;
}
/// Import a mesh from an OFF file.
void Import_OFF(const char * aFileName, Mesh * aMesh)
{
// Clear the mesh
aMesh->Clear();
// Open the input file
ifstream f(aFileName, ios::in);
if(f.fail())
throw_runtime_error("Could not open input file.");
// Some state variables that we need...
unsigned int numVertices;
unsigned int numFaces;
string line, comment;
istringstream sstr;
// Read header
ReadNextLine(f, line, comment);
if(line != string("OFF"))
throw_runtime_error("Not a valid OFF format file (missing OFF signature).");
ReadNextLine(f, line, comment);
sstr.clear();
sstr.str(line);
sstr >> numVertices;
sstr >> numFaces;
if(numVertices < 1)
throw_runtime_error("Not a valid OFF format file (bad vertex count).");
if(numFaces < 1)
throw_runtime_error("Not a valid OFF format file (bad face count).");
// Read vertices
aMesh->mVertices.resize(numVertices);
aMesh->mColors.resize(numVertices);
for(unsigned int i = 0; i < numVertices; ++ i)
{
ReadNextLine(f, line, comment);
ParseVeretex(line, &aMesh->mVertices[i], &aMesh->mColors[i]);
}
// Check if there were vertex colors
bool hasVertexColors = false;
Vector4 firstColor = aMesh->mColors[0];
for(unsigned int i = 1; i < numVertices; ++ i)
{
if((aMesh->mColors[i].x != firstColor.x) || (aMesh->mColors[i].y != firstColor.y) ||
(aMesh->mColors[i].z != firstColor.z) || (aMesh->mColors[i].w != firstColor.w))
{
hasVertexColors = true;
break;
}
}
if(!hasVertexColors)
aMesh->mColors.clear();
// Read faces
list<unsigned int> indices;
unsigned int idx[3];
for(unsigned int i = 0; i < numFaces; ++ i)
{
ReadNextLine(f, line, comment);
sstr.clear();
sstr.str(line);
int nodeCount;
sstr >> nodeCount;
if(nodeCount >= 3)
{
sstr >> idx[0];
sstr >> idx[1];
sstr >> idx[2];
nodeCount -= 3;
while(nodeCount >= 0)
{
indices.push_back(idx[0]);
indices.push_back(idx[1]);
indices.push_back(idx[2]);
if(nodeCount > 0)
{
idx[1] = idx[2];
sstr >> idx[2];
}
-- nodeCount;
}
}
}
// Copy triangle indices from the read index list to the mesh index vector
aMesh->mIndices.resize(indices.size());
unsigned int j = 0;
for(list<unsigned int>::iterator i = indices.begin(); i != indices.end(); ++ i)
{
aMesh->mIndices[j] = (*i);
++ j;
}
// Close the input file
f.close();
// Did we get a comment?
if(comment.size() > 0)
aMesh->mComment = comment;
}
/// Export a mesh to an OFF file.
void Export_OFF(const char * aFileName, Mesh * aMesh, Options &aOptions)
{
// Open the output file
ofstream f(aFileName, ios::out);
if(f.fail())
throw_runtime_error("Could not open output file.");
// Mesh information
unsigned int numVertices = (unsigned int) aMesh->mVertices.size();
unsigned int numFaces = (unsigned int) aMesh->mIndices.size() / 3;
// Set floating point precision
f << setprecision(8);
// Write OFF file header ID
f << "OFF" << endl;
// Write comment
if(aMesh->mComment.size() > 0)
{
stringstream sstr(aMesh->mComment);
sstr.seekg(0);
while(!sstr.eof())
{
string line;
getline(sstr, line);
line = TrimString(line);
if(line.size() > 0)
f << "# " << line << endl;
}
}
f << endl;
// Write mesh information
f << numVertices << " " << numFaces << " 0" << endl;
// Write vertices
bool exportVertexColors = !aOptions.mNoColors && aMesh->HasColors();
for(unsigned int i = 0; i < numVertices; ++ i)
{
f << aMesh->mVertices[i].x << " " << aMesh->mVertices[i].y << " " << aMesh->mVertices[i].z;
if(exportVertexColors)
f << " " << aMesh->mColors[i].x << " " << aMesh->mColors[i].y << " " << aMesh->mColors[i].z << " " << aMesh->mColors[i].w;
f << endl;
}
// Write faces
for(unsigned int i = 0; i < numFaces; ++ i)
{
f << "3 " << aMesh->mIndices[i * 3] << " " <<
aMesh->mIndices[i * 3 + 1] << " " <<
aMesh->mIndices[i * 3 + 2] << endl;
}
// Close the output file
f.close();
}