Merge pull request #3944 from ey6es/master

To prevent allocation error on Windows (in this instance), don't load entire FBX at once; parse it directly from the QNetworkReply.
This commit is contained in:
Brad Hefta-Gaub 2014-12-10 16:39:44 -08:00
commit e82968771e
3 changed files with 53 additions and 21 deletions

View file

@ -841,14 +841,14 @@ void GeometryReader::run() {
if (urlValid) {
// 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;
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);
} else if (_url.path().toLower().endsWith(".fbx")) {
bool grabLightmaps = true;
float lightmapLevel = 1.0f;
@ -860,7 +860,7 @@ void GeometryReader::run() {
} else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) {
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));
} else {

View file

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

View file

@ -24,6 +24,8 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
class QIODevice;
class FBXNode;
typedef QList<FBXNode> FBXNodeList;
@ -272,6 +274,10 @@ QByteArray writeMapping(const QVariantHash& mapping);
/// \exception QString if an error occurs in parsing
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.
FBXGeometry readSVO(const QByteArray& model);