don't keep empty mesh-parts. take units hint from a common first-line comment, if it's there.

This commit is contained in:
Seth Alves 2015-03-31 14:34:35 -07:00
parent 95cc8672c0
commit 48144a46b1

View file

@ -27,7 +27,8 @@ public:
enum SpecialToken {
NO_TOKEN = -1,
NO_PUSHBACKED_TOKEN = -1,
DATUM_TOKEN = 0x100
DATUM_TOKEN = 0x100,
COMMENT_TOKEN = 0x101
};
int nextToken();
const QByteArray& getDatum() const { return _datum; }
@ -35,11 +36,13 @@ public:
void skipLine() { _device->readLine(); }
void pushBackToken(int token) { _pushedBackToken = token; }
void ungetChar(char ch) { _device->ungetChar(ch); }
const QString getComment() const { return _comment; }
private:
QIODevice* _device;
QByteArray _datum;
int _pushedBackToken;
QString _comment;
};
@ -56,9 +59,11 @@ int OBJTokenizer::nextToken() {
continue; // skip whitespace
}
switch (ch) {
case '#':
_device->readLine(); // skip the comment
break;
case '#': {
_comment = _device->readLine(); // skip the comment
qDebug() << "COMMENT:" << _comment;
return COMMENT_TOKEN;
}
case '\"':
_datum = "";
@ -104,7 +109,8 @@ bool OBJTokenizer::isNextTokenFloat() {
}
bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
FBXGeometry &geometry, QVector<glm::vec3>& faceNormals, QVector<int>& faceNormalIndexes) {
FBXGeometry &geometry, QVector<glm::vec3>& faceNormals, QVector<int>& faceNormalIndexes,
float& scaleGuess) {
FBXMesh &mesh = geometry.meshes[0];
mesh.parts.append(FBXMeshPart());
FBXMeshPart &meshPart = mesh.parts.last();
@ -128,7 +134,17 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0));
while (true) {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
int tokenType = tokenizer.nextToken();
if (tokenType == OBJTokenizer::COMMENT_TOKEN) {
if (tokenizer.getComment().contains("This file uses centimeters as units")) {
scaleGuess = 1.0f / 100.0f;
}
if (tokenizer.getComment().contains("This file uses millimeters as units")) {
scaleGuess = 1.0f / 1000.0f;
}
continue;
}
if (tokenType != OBJTokenizer::DATUM_TOKEN) {
result = false;
break;
}
@ -192,6 +208,7 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
while (true) {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
if (indices.count() == 0) {
// nonsense, bail out.
goto done;
}
break;
@ -266,22 +283,22 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
}
} else {
// something we don't (yet) care about
qDebug() << "OBJ parser is skipping a line with" << token;
// qDebug() << "OBJ parser is skipping a line with" << token;
tokenizer.skipLine();
}
}
done:
if (meshPart.triangleIndices.size() == 0 && meshPart.quadIndices.size() == 0) {
// empty mesh?
mesh.parts.pop_back();
}
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);
@ -294,24 +311,30 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) {
OBJTokenizer tokenizer(device);
QVector<int> faceNormalIndexes;
QVector<glm::vec3> faceNormals;
float scaleGuess = 1.0f;
faceNormalIndexes.clear();
geometry.meshExtents.reset();
geometry.meshes.append(FBXMesh());
try {
// call parseOBJGroup as long as it's returning true. Each successful call will
// add a new meshPart to the geometry's single mesh.
bool success = true;
while (success) {
success = parseOBJGroup(tokenizer, mapping, geometry, faceNormals, faceNormalIndexes);
success = parseOBJGroup(tokenizer, mapping, geometry, faceNormals, faceNormalIndexes, scaleGuess);
}
FBXMesh &mesh = geometry.meshes[0];
// if we got a hint about units, scale all the points
if (scaleGuess != 1.0f) {
for (int i = 0; i < mesh.vertices.size(); i++) {
mesh.vertices[i] *= scaleGuess;
}
}
mesh.meshExtents.reset();
foreach (const glm::vec3& vertex, mesh.vertices) {
mesh.meshExtents.addPoint(vertex);