Rather than loading the entire FBX file into a byte array, read it straight

from the QNetworkReply.
This commit is contained in:
Andrzej Kapolka 2014-12-10 15:22:48 -08:00
parent 9aaaae6759
commit c57fd15bc9
3 changed files with 53 additions and 21 deletions

View file

@ -841,14 +841,14 @@ void GeometryReader::run() {
if (urlValid) { if (urlValid) {
// Let's read the binaries from the network // Let's read the binaries from the network
QByteArray fileBinary = _reply->readAll();
if (fileBinary.isEmpty() || fileBinary.isNull()) {
throw QString("Read File binary is empty?!");
}
FBXGeometry fbxgeo; FBXGeometry fbxgeo;
if (_url.path().toLower().endsWith(".svo")) { if (_url.path().toLower().endsWith(".svo")) {
QByteArray fileBinary = _reply->readAll();
if (fileBinary.isEmpty() || fileBinary.isNull()) {
throw QString("Read File binary is empty?!");
}
fbxgeo = readSVO(fileBinary); fbxgeo = readSVO(fileBinary);
} else if (_url.path().toLower().endsWith(".fbx")) { } else if (_url.path().toLower().endsWith(".fbx")) {
bool grabLightmaps = true; bool grabLightmaps = true;
float lightmapLevel = 1.0f; float lightmapLevel = 1.0f;
@ -860,7 +860,7 @@ void GeometryReader::run() {
} else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) { } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) {
lightmapLevel = 3.5f; lightmapLevel = 3.5f;
} }
fbxgeo = readFBX(fileBinary, _mapping, grabLightmaps, lightmapLevel); fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel);
} }
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
} else { } else {

View file

@ -138,7 +138,15 @@ static int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>(); static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >(); static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >();
template<class T> QVariant readBinaryArray(QDataStream& in) { template<class T> int streamSize() {
return sizeof(T);
}
template<bool> int streamSize() {
return 1;
}
template<class T> QVariant readBinaryArray(QDataStream& in, int& position) {
quint32 arrayLength; quint32 arrayLength;
quint32 encoding; quint32 encoding;
quint32 compressedLength; quint32 compressedLength;
@ -146,6 +154,7 @@ template<class T> QVariant readBinaryArray(QDataStream& in) {
in >> arrayLength; in >> arrayLength;
in >> encoding; in >> encoding;
in >> compressedLength; in >> compressedLength;
position += sizeof(quint32) * 3;
QVector<T> values; QVector<T> values;
const unsigned int DEFLATE_ENCODING = 1; const unsigned int DEFLATE_ENCODING = 1;
@ -154,6 +163,7 @@ template<class T> QVariant readBinaryArray(QDataStream& in) {
QByteArray compressed(sizeof(quint32) + compressedLength, 0); QByteArray compressed(sizeof(quint32) + compressedLength, 0);
*((quint32*)compressed.data()) = qToBigEndian<quint32>(arrayLength * sizeof(T)); *((quint32*)compressed.data()) = qToBigEndian<quint32>(arrayLength * sizeof(T));
in.readRawData(compressed.data() + sizeof(quint32), compressedLength); in.readRawData(compressed.data() + sizeof(quint32), compressedLength);
position += compressedLength;
QByteArray uncompressed = qUncompress(compressed); QByteArray uncompressed = qUncompress(compressed);
QDataStream uncompressedIn(uncompressed); QDataStream uncompressedIn(uncompressed);
uncompressedIn.setByteOrder(QDataStream::LittleEndian); uncompressedIn.setByteOrder(QDataStream::LittleEndian);
@ -167,65 +177,74 @@ template<class T> QVariant readBinaryArray(QDataStream& in) {
for (quint32 i = 0; i < arrayLength; i++) { for (quint32 i = 0; i < arrayLength; i++) {
T value; T value;
in >> value; in >> value;
position += streamSize<T>();
values.append(value); values.append(value);
} }
} }
return QVariant::fromValue(values); return QVariant::fromValue(values);
} }
QVariant parseBinaryFBXProperty(QDataStream& in) { QVariant parseBinaryFBXProperty(QDataStream& in, int& position) {
char ch; char ch;
in.device()->getChar(&ch); in.device()->getChar(&ch);
position++;
switch (ch) { switch (ch) {
case 'Y': { case 'Y': {
qint16 value; qint16 value;
in >> value; in >> value;
position += sizeof(qint16);
return QVariant::fromValue(value); return QVariant::fromValue(value);
} }
case 'C': { case 'C': {
bool value; bool value;
in >> value; in >> value;
position++;
return QVariant::fromValue(value); return QVariant::fromValue(value);
} }
case 'I': { case 'I': {
qint32 value; qint32 value;
in >> value; in >> value;
position += sizeof(qint32);
return QVariant::fromValue(value); return QVariant::fromValue(value);
} }
case 'F': { case 'F': {
float value; float value;
in >> value; in >> value;
position += sizeof(float);
return QVariant::fromValue(value); return QVariant::fromValue(value);
} }
case 'D': { case 'D': {
double value; double value;
in >> value; in >> value;
position += sizeof(double);
return QVariant::fromValue(value); return QVariant::fromValue(value);
} }
case 'L': { case 'L': {
qint64 value; qint64 value;
in >> value; in >> value;
position += sizeof(qint64);
return QVariant::fromValue(value); return QVariant::fromValue(value);
} }
case 'f': { case 'f': {
return readBinaryArray<float>(in); return readBinaryArray<float>(in, position);
} }
case 'd': { case 'd': {
return readBinaryArray<double>(in); return readBinaryArray<double>(in, position);
} }
case 'l': { case 'l': {
return readBinaryArray<qint64>(in); return readBinaryArray<qint64>(in, position);
} }
case 'i': { case 'i': {
return readBinaryArray<qint32>(in); return readBinaryArray<qint32>(in, position);
} }
case 'b': { case 'b': {
return readBinaryArray<bool>(in); return readBinaryArray<bool>(in, position);
} }
case 'S': case 'S':
case 'R': { case 'R': {
quint32 length; quint32 length;
in >> length; in >> length;
position += sizeof(quint32) + length;
return QVariant::fromValue(in.device()->read(length)); return QVariant::fromValue(in.device()->read(length));
} }
default: default:
@ -233,8 +252,8 @@ QVariant parseBinaryFBXProperty(QDataStream& in) {
} }
} }
FBXNode parseBinaryFBXNode(QDataStream& in) { FBXNode parseBinaryFBXNode(QDataStream& in, int& position) {
quint32 endOffset; qint32 endOffset;
quint32 propertyCount; quint32 propertyCount;
quint32 propertyListLength; quint32 propertyListLength;
quint8 nameLength; quint8 nameLength;
@ -243,21 +262,23 @@ FBXNode parseBinaryFBXNode(QDataStream& in) {
in >> propertyCount; in >> propertyCount;
in >> propertyListLength; in >> propertyListLength;
in >> nameLength; in >> nameLength;
position += sizeof(quint32) * 3 + sizeof(quint8);
FBXNode node; FBXNode node;
const unsigned int MIN_VALID_OFFSET = 40; const int MIN_VALID_OFFSET = 40;
if (endOffset < MIN_VALID_OFFSET || nameLength == 0) { if (endOffset < MIN_VALID_OFFSET || nameLength == 0) {
// use a null name to indicate a null node // use a null name to indicate a null node
return node; return node;
} }
node.name = in.device()->read(nameLength); node.name = in.device()->read(nameLength);
position += nameLength;
for (quint32 i = 0; i < propertyCount; i++) { for (quint32 i = 0; i < propertyCount; i++) {
node.properties.append(parseBinaryFBXProperty(in)); node.properties.append(parseBinaryFBXProperty(in, position));
} }
while (endOffset > in.device()->pos()) { while (endOffset > position) {
FBXNode child = parseBinaryFBXNode(in); FBXNode child = parseBinaryFBXNode(in, position);
if (child.name.isNull()) { if (child.name.isNull()) {
return node; return node;
@ -416,11 +437,12 @@ FBXNode parseFBX(QIODevice* device) {
// skip the rest of the header // skip the rest of the header
const int HEADER_SIZE = 27; const int HEADER_SIZE = 27;
in.skipRawData(HEADER_SIZE); in.skipRawData(HEADER_SIZE);
int position = HEADER_SIZE;
// parse the top-level node // parse the top-level node
FBXNode top; FBXNode top;
while (device->bytesAvailable()) { while (device->bytesAvailable()) {
FBXNode next = parseBinaryFBXNode(in); FBXNode next = parseBinaryFBXNode(in, position);
if (next.name.isNull()) { if (next.name.isNull()) {
return top; return top;
@ -2516,7 +2538,11 @@ QByteArray writeMapping(const QVariantHash& mapping) {
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
QBuffer buffer(const_cast<QByteArray*>(&model)); QBuffer buffer(const_cast<QByteArray*>(&model));
buffer.open(QIODevice::ReadOnly); buffer.open(QIODevice::ReadOnly);
return extractFBXGeometry(parseFBX(&buffer), mapping, loadLightmaps, lightmapLevel); return readFBX(&buffer, mapping, loadLightmaps, lightmapLevel);
}
FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
return extractFBXGeometry(parseFBX(device), mapping, loadLightmaps, lightmapLevel);
} }
bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) { bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) {

View file

@ -24,6 +24,8 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
class QIODevice;
class FBXNode; class FBXNode;
typedef QList<FBXNode> FBXNodeList; typedef QList<FBXNode> FBXNodeList;
@ -272,6 +274,10 @@ QByteArray writeMapping(const QVariantHash& mapping);
/// \exception QString if an error occurs in parsing /// \exception QString if an error occurs in parsing
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f);
/// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f);
/// Reads SVO geometry from the supplied model data. /// Reads SVO geometry from the supplied model data.
FBXGeometry readSVO(const QByteArray& model); FBXGeometry readSVO(const QByteArray& model);