mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2024-12-01 11:56:58 -05:00
254 lines
7.3 KiB
C++
254 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 <stdexcept>
|
||
|
#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();
|
||
|
}
|