mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 12:37:51 +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 "Application.h"
|
||||||
#include "BlendFace.h"
|
#include "BlendFace.h"
|
||||||
#include "Head.h"
|
#include "Head.h"
|
||||||
|
#include "renderer/FBXReader.h"
|
||||||
|
|
||||||
using namespace fs;
|
using namespace fs;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -180,7 +181,12 @@ void BlendFace::handleModelDownloadProgress(qint64 bytesReceived, qint64 bytesTo
|
||||||
_modelReply->deleteLater();
|
_modelReply->deleteLater();
|
||||||
_modelReply = 0;
|
_modelReply = 0;
|
||||||
|
|
||||||
qDebug("Got %d bytes.\n", entirety.size());
|
try {
|
||||||
|
printNode(parseFBX(entirety));
|
||||||
|
|
||||||
|
} catch (const QString& error) {
|
||||||
|
qDebug() << error << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlendFace::handleModelReplyError() {
|
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