obj reader sort-of works

This commit is contained in:
Seth Alves 2015-03-06 13:15:53 -08:00
parent 7a2977446a
commit 858d15d0ba
7 changed files with 233 additions and 41 deletions

View file

@ -0,0 +1,190 @@
#include <QBuffer>
#include <QIODevice>
#include "FBXReader.h"
#include "OBJReader.h"
class OBJTokenizer {
public:
OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { }
enum SpecialToken { DATUM_TOKEN = 0x100 };
int nextToken();
const QByteArray& getDatum() const { return _datum; }
void skipLine() { _device->readLine(); }
void pushBackToken(int token) { _pushedBackToken = token; }
void ungetChar(char ch) { _device->ungetChar(ch); }
private:
QIODevice* _device;
QByteArray _datum;
int _pushedBackToken;
};
int OBJTokenizer::nextToken() {
if (_pushedBackToken != -1) {
int token = _pushedBackToken;
_pushedBackToken = -1;
return token;
}
char ch;
while (_device->getChar(&ch)) {
if (QChar(ch).isSpace()) {
continue; // skip whitespace
}
switch (ch) {
case '#':
_device->readLine(); // skip the comment
break;
case '\"':
_datum = "";
while (_device->getChar(&ch)) {
if (ch == '\"') { // end on closing quote
break;
}
if (ch == '\\') { // handle escaped quotes
if (_device->getChar(&ch) && ch != '\"') {
_datum.append('\\');
}
}
_datum.append(ch);
}
return DATUM_TOKEN;
default:
_datum = "";
_datum.append(ch);
while (_device->getChar(&ch)) {
if (QChar(ch).isSpace() || ch == '\"') {
ungetChar(ch); // read until we encounter a special character, then replace it
break;
}
_datum.append(ch);
}
return DATUM_TOKEN;
}
}
return -1;
}
bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry, int& indexStart) {
FBXMesh mesh;
FBXMeshPart meshPart;
bool sawG = false;
bool meshHasData = true;
bool result = true;
try { // XXX move this out/up
while (true) {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
result = false;
break;
}
QByteArray token = tokenizer.getDatum();
if (token == "g") {
if (sawG) {
// we've encountered the beginning of the next group.
tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN);
break;
}
sawG = true;
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
QByteArray groupName = tokenizer.getDatum();
meshPart.materialID = groupName;
meshHasData = true;
} else if (token == "v") {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
float x = std::stof(tokenizer.getDatum().data());
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
float y = std::stof(tokenizer.getDatum().data());
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
float z = std::stof(tokenizer.getDatum().data());
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
// float w = 1.0;
try{
// w =
std::stof(tokenizer.getDatum().data());
}
catch(const std::exception& e){
// next token wasn't a number (the w field is optional), push it back
tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN);
}
mesh.vertices.append(glm::vec3(x, y, z));
meshHasData = true;
} else if (token == "f") {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
int p0 = std::stoi(tokenizer.getDatum().data());
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
int p1 = std::stoi(tokenizer.getDatum().data());
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; }
int p2 = std::stoi(tokenizer.getDatum().data());
// obj indexes is 1 based and index over the entire file. mesh indexes are 0 based
// and index within the mesh.
meshPart.triangleIndices.append(p0 - 1 - indexStart); // obj index is 1 based
meshPart.triangleIndices.append(p1 - 1 - indexStart);
meshPart.triangleIndices.append(p2 - 1 - indexStart);
meshHasData = true;
} else {
// something we don't (yet) care about
qDebug() << "skipping line with" << token;
tokenizer.skipLine();
}
}
}
catch(const std::exception& e) {
// something went wrong, stop here.
qDebug() << "something went wrong";
return false;
}
if (meshHasData) {
mesh.parts.append(meshPart);
geometry.meshes.append(mesh);
}
indexStart += mesh.vertices.count();
return result;
}
FBXGeometry extractOBJGeometry(const FBXNode& node, const QVariantHash& mapping) {
FBXGeometry geometry;
return geometry;
}
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) {
QBuffer buffer(const_cast<QByteArray*>(&model));
buffer.open(QIODevice::ReadOnly);
return readOBJ(&buffer, mapping);
}
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) {
FBXGeometry geometry;
OBJTokenizer tokenizer(device);
int indexStart = 0;
while (true) {
if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) {
break;
}
}
return geometry;
}

View file

@ -0,0 +1,6 @@
#include "FBXReader.h"
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping);

View file

@ -2101,6 +2101,8 @@ void GeometryReader::run() {
lightmapLevel = 3.5f;
}
fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel);
} else if (_url.path().toLower().endsWith(".obj")) {
fbxgeo = readOBJ(_reply, _mapping);
}
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
} else {

View file

@ -22,6 +22,7 @@
#include <ResourceCache.h>
#include <FBXReader.h>
#include <OBJReader.h>
#include <AnimationCache.h>

View file

@ -13,11 +13,6 @@
#include "VHACDUtil.h"
//Read all the meshes from provided FBX file
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) {
@ -29,14 +24,31 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
std::cout << "Reading FBX.....\n";
QByteArray fbxContents = fbx.readAll();
FBXGeometry geometry = readFBX(fbxContents, QVariantHash());
FBXGeometry geometry;
if (filename.toLower().endsWith(".obj")) {
geometry = readOBJ(fbxContents, QVariantHash());
} else if (filename.toLower().endsWith(".fbx")) {
geometry = readFBX(fbxContents, QVariantHash());
} else {
qDebug() << "unknown file extension";
return false;
}
//results->meshCount = geometry.meshes.count();
qDebug() << "read in" << geometry.meshes.count() << "meshes";
int count = 0;
foreach(FBXMesh mesh, geometry.meshes){
foreach(FBXMesh mesh, geometry.meshes) {
//get vertices for each mesh
QVector<glm::vec3> vertices = mesh.vertices;
qDebug() << "vertex count is" << vertices.count();
//get the triangle indices for each mesh
QVector<int> triangles;
foreach(FBXMeshPart part, mesh.parts){
@ -45,9 +57,9 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
}
//only read meshes with triangles
if (triangles.count() <= 0){
continue;
}
if (triangles.count() <= 0){
continue;
}
results->perMeshVertices.append(vertices);
results->perMeshTriangleIndices.append(triangles);
count++;

View file

@ -19,6 +19,7 @@
#include <chrono> //c++11 feature
#include <QFile>
#include <FBXReader.h>
#include <OBJReader.h>
#include <VHACD.h>
namespace vhacd {

View file

@ -32,7 +32,7 @@ QString formatFloat(double n) {
}
bool writeOBJ(QString outFileName, QVector<QVector<VHACD::IVHACD::ConvexHull>>& convexHullList, bool outputOneMesh) {
bool writeOBJ(QString outFileName, QVector<QVector<VHACD::IVHACD::ConvexHull>>& meshList, bool outputOneMesh) {
QFile file(outFileName);
if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "Unable to write to " << outFileName;
@ -41,52 +41,32 @@ bool writeOBJ(QString outFileName, QVector<QVector<VHACD::IVHACD::ConvexHull>>&
QTextStream out(&file);
// if (meshList.size() != 1) {
// qDebug() << "unexpected number of meshes --" << meshList.size();
// exit(1);
// }
// QVector<VHACD::IVHACD::ConvexHull> hulls = meshList[0];
if (convexHullList.size() != 1) {
qDebug() << "unexpected number of meshes --" << convexHullList.size();
exit(1);
}
unsigned int pointStartOffset = 0;
QVector<VHACD::IVHACD::ConvexHull> hulls = convexHullList[0];
if (outputOneMesh) {
foreach (QVector<VHACD::IVHACD::ConvexHull> hulls, meshList) {
unsigned int nth = 0;
foreach (VHACD::IVHACD::ConvexHull hull, hulls) {
out << "g hull-" << nth++ << "\n";
for (unsigned int i = 0; i < hull.m_nPoints; i++) {
out << "v ";
out << formatFloat(hull.m_points[i*3]) << " ";
out << formatFloat(hull.m_points[i*3+1]) << " ";
out << formatFloat(hull.m_points[i*3+2]) << " 1\n";
}
}
unsigned int pointStartOffset = 0;
foreach (VHACD::IVHACD::ConvexHull hull, hulls) {
for (unsigned int i = 0; i < hull.m_nTriangles; i++) {
out << "f ";
out << hull.m_triangles[i*3] + 1 + pointStartOffset << " ";
out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " ";
out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n";
}
pointStartOffset += hull.m_nPoints;
}
} else {
unsigned int nth = 0;
foreach (VHACD::IVHACD::ConvexHull hull, hulls) {
out << "o hull-" << nth++ << "\n";
for (unsigned int i = 0; i < hull.m_nPoints; i++) {
out << "v ";
out << formatFloat(hull.m_points[i*3]) << " ";
out << formatFloat(hull.m_points[i*3+1]) << " ";
out << formatFloat(hull.m_points[i*3+2]) << " 1\n";
}
for (unsigned int i = 0; i < hull.m_nTriangles; i++) {
out << "f ";
out << hull.m_triangles[i*3] + 1 << " ";
out << hull.m_triangles[i*3+1] + 1 << " ";
out << hull.m_triangles[i*3+2] + 1 << "\n";
}
out << "\n";
pointStartOffset += hull.m_nPoints;
}
}