mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 09:33:36 +02:00
Basic FBX parser.
This commit is contained in:
parent
6be03ac3df
commit
dfea69ab8f
3 changed files with 239 additions and 1 deletions
|
@ -11,6 +11,7 @@
|
|||
#include "Application.h"
|
||||
#include "BlendFace.h"
|
||||
#include "Head.h"
|
||||
#include "renderer/FBXReader.h"
|
||||
|
||||
using namespace fs;
|
||||
using namespace std;
|
||||
|
@ -180,7 +181,12 @@ void BlendFace::handleModelDownloadProgress(qint64 bytesReceived, qint64 bytesTo
|
|||
_modelReply->deleteLater();
|
||||
_modelReply = 0;
|
||||
|
||||
qDebug("Got %d bytes.\n", entirety.size());
|
||||
try {
|
||||
printNode(parseFBX(entirety));
|
||||
|
||||
} catch (const QString& error) {
|
||||
qDebug() << error << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void BlendFace::handleModelReplyError() {
|
||||
|
|
192
interface/src/renderer/FBXReader.cpp
Normal file
192
interface/src/renderer/FBXReader.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
//
|
||||
// FBXReader.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/18/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QDataStream>
|
||||
#include <QIODevice>
|
||||
#include <QtDebug>
|
||||
#include <QtEndian>
|
||||
|
||||
#include "FBXReader.h"
|
||||
|
||||
FBXNode parseFBX(const QByteArray& data) {
|
||||
QBuffer buffer(const_cast<QByteArray*>(&data));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
return parseFBX(&buffer);
|
||||
}
|
||||
|
||||
template<class T> QVariant readArray(QDataStream& in) {
|
||||
quint32 arrayLength;
|
||||
quint32 encoding;
|
||||
quint32 compressedLength;
|
||||
|
||||
in >> arrayLength;
|
||||
in >> encoding;
|
||||
in >> compressedLength;
|
||||
|
||||
QVector<T> values;
|
||||
const int DEFLATE_ENCODING = 1;
|
||||
if (encoding == DEFLATE_ENCODING) {
|
||||
// preface encoded data with uncompressed length
|
||||
QByteArray compressed(sizeof(quint32) + compressedLength, 0);
|
||||
*((quint32*)compressed.data()) = qToBigEndian<quint32>(arrayLength * sizeof(T));
|
||||
in.readRawData(compressed.data() + sizeof(quint32), compressedLength);
|
||||
QByteArray uncompressed = qUncompress(compressed);
|
||||
QDataStream uncompressedIn(uncompressed);
|
||||
uncompressedIn.setByteOrder(QDataStream::LittleEndian);
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
T value;
|
||||
uncompressedIn >> value;
|
||||
values.append(value);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
T value;
|
||||
in >> value;
|
||||
values.append(value);
|
||||
}
|
||||
}
|
||||
return QVariant::fromValue(values);
|
||||
}
|
||||
|
||||
QVariant parseFBXProperty(QDataStream& in) {
|
||||
char ch;
|
||||
in.device()->getChar(&ch);
|
||||
switch (ch) {
|
||||
case 'Y': {
|
||||
qint16 value;
|
||||
in >> value;
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
case 'C': {
|
||||
bool value;
|
||||
in >> value;
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
case 'I': {
|
||||
qint32 value;
|
||||
in >> value;
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
case 'F': {
|
||||
float value;
|
||||
in >> value;
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
case 'D': {
|
||||
double value;
|
||||
in >> value;
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
case 'L': {
|
||||
qint64 value;
|
||||
in >> value;
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
case 'f': {
|
||||
return readArray<float>(in);
|
||||
}
|
||||
case 'd': {
|
||||
return readArray<double>(in);
|
||||
}
|
||||
case 'l': {
|
||||
return readArray<qint64>(in);
|
||||
}
|
||||
case 'i': {
|
||||
return readArray<qint32>(in);
|
||||
}
|
||||
case 'b': {
|
||||
return readArray<bool>(in);
|
||||
}
|
||||
case 'S':
|
||||
case 'R': {
|
||||
quint32 length;
|
||||
in >> length;
|
||||
return QVariant::fromValue(in.device()->read(length));
|
||||
}
|
||||
default:
|
||||
throw QString("Unknown property type: ") + ch;
|
||||
}
|
||||
}
|
||||
|
||||
FBXNode parseFBXNode(QDataStream& in) {
|
||||
quint32 endOffset;
|
||||
quint32 propertyCount;
|
||||
quint32 propertyListLength;
|
||||
quint8 nameLength;
|
||||
|
||||
in >> endOffset;
|
||||
in >> propertyCount;
|
||||
in >> propertyListLength;
|
||||
in >> nameLength;
|
||||
|
||||
FBXNode node;
|
||||
const int MIN_VALID_OFFSET = 40;
|
||||
if (endOffset < MIN_VALID_OFFSET || nameLength == 0) {
|
||||
// use a null name to indicate a null node
|
||||
return node;
|
||||
}
|
||||
node.name = in.device()->read(nameLength);
|
||||
|
||||
for (int i = 0; i < propertyCount; i++) {
|
||||
node.properties.append(parseFBXProperty(in));
|
||||
}
|
||||
|
||||
while (endOffset > in.device()->pos()) {
|
||||
FBXNode child = parseFBXNode(in);
|
||||
if (child.name.isNull()) {
|
||||
return node;
|
||||
|
||||
} else {
|
||||
node.children.append(child);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
FBXNode parseFBX(QIODevice* device) {
|
||||
QDataStream in(device);
|
||||
in.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
// verify the prolog
|
||||
const QByteArray EXPECTED_PROLOG = "Kaydara FBX Binary ";
|
||||
if (device->read(EXPECTED_PROLOG.size()) != EXPECTED_PROLOG) {
|
||||
throw QString("Invalid header.");
|
||||
}
|
||||
|
||||
// skip the rest of the header
|
||||
const int HEADER_SIZE = 27;
|
||||
in.skipRawData(HEADER_SIZE - EXPECTED_PROLOG.size());
|
||||
|
||||
// parse the top-level node
|
||||
FBXNode top;
|
||||
while (device->bytesAvailable() >= 13) {
|
||||
FBXNode next = parseFBXNode(in);
|
||||
if (next.name.isNull()) {
|
||||
return top;
|
||||
|
||||
} else {
|
||||
top.children.append(next);
|
||||
}
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
void printNode(const FBXNode& node, int indent) {
|
||||
QByteArray spaces(indent, ' ');
|
||||
qDebug("%s%s: ", spaces.data(), node.name.data());
|
||||
foreach (const QVariant& property, node.properties) {
|
||||
qDebug() << property;
|
||||
}
|
||||
qDebug() << "\n";
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
printNode(child, indent + 1);
|
||||
}
|
||||
}
|
40
interface/src/renderer/FBXReader.h
Normal file
40
interface/src/renderer/FBXReader.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// FBXReader.h
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 9/18/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__FBXReader__
|
||||
#define __interface__FBXReader__
|
||||
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
class FBXNode;
|
||||
|
||||
typedef QList<FBXNode> FBXNodeList;
|
||||
|
||||
/// A node within an FBX document.
|
||||
class FBXNode {
|
||||
public:
|
||||
|
||||
QByteArray name;
|
||||
QVariantList properties;
|
||||
FBXNodeList children;
|
||||
};
|
||||
|
||||
/// Parses the input from the supplied data as an FBX file.
|
||||
/// \exception QString if an error occurs in parsing
|
||||
FBXNode parseFBX(const QByteArray& data);
|
||||
|
||||
/// Parses the input from the supplied device as an FBX file.
|
||||
/// \exception QString if an error occurs in parsing
|
||||
FBXNode parseFBX(QIODevice* device);
|
||||
|
||||
void printNode(const FBXNode& node, int indent = 0);
|
||||
|
||||
#endif /* defined(__interface__FBXReader__) */
|
Loading…
Reference in a new issue