Merge pull request #971 from ey6es/blendface

Fix to allow models other than the pug.
This commit is contained in:
Philip Rosedale 2013-09-20 17:03:58 -07:00
commit 8fa4a60d31

View file

@ -41,6 +41,7 @@ template<class T> QVariant readArray(QDataStream& in) {
QByteArray uncompressed = qUncompress(compressed); QByteArray uncompressed = qUncompress(compressed);
QDataStream uncompressedIn(uncompressed); QDataStream uncompressedIn(uncompressed);
uncompressedIn.setByteOrder(QDataStream::LittleEndian); uncompressedIn.setByteOrder(QDataStream::LittleEndian);
uncompressedIn.setVersion(QDataStream::Qt_4_5); // for single/double precision switch
for (int i = 0; i < arrayLength; i++) { for (int i = 0; i < arrayLength; i++) {
T value; T value;
uncompressedIn >> value; uncompressedIn >> value;
@ -132,7 +133,7 @@ FBXNode parseFBXNode(QDataStream& in) {
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);
for (int i = 0; i < propertyCount; i++) { for (int i = 0; i < propertyCount; i++) {
@ -155,6 +156,7 @@ FBXNode parseFBXNode(QDataStream& in) {
FBXNode parseFBX(QIODevice* device) { FBXNode parseFBX(QIODevice* device) {
QDataStream in(device); QDataStream in(device);
in.setByteOrder(QDataStream::LittleEndian); in.setByteOrder(QDataStream::LittleEndian);
in.setVersion(QDataStream::Qt_4_5); // for single/double precision switch
// see http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ for an explanation // see http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ for an explanation
// of the FBX format // of the FBX format
@ -258,18 +260,23 @@ QHash<QByteArray, int> createBlendshapeMap() {
} }
FBXGeometry extractFBXGeometry(const FBXNode& node) { FBXGeometry extractFBXGeometry(const FBXNode& node) {
FBXGeometry geometry; QVector<FBXBlendshape> blendshapes;
QHash<qint64, FBXGeometry> meshMap;
qint64 blendshapeId = 0;
QHash<qint64, qint64> parentMap;
foreach (const FBXNode& child, node.children) { foreach (const FBXNode& child, node.children) {
if (child.name == "Objects") { if (child.name == "Objects") {
foreach (const FBXNode& object, child.children) { foreach (const FBXNode& object, child.children) {
if (object.name == "Geometry") { if (object.name == "Geometry") {
if (object.properties.at(2) == "Mesh") { if (object.properties.at(2) == "Mesh") {
FBXGeometry mesh;
QVector<glm::vec3> vertices; QVector<glm::vec3> vertices;
QVector<int> polygonIndices; QVector<int> polygonIndices;
foreach (const FBXNode& data, object.children) { foreach (const FBXNode& data, object.children) {
if (data.name == "Vertices") { if (data.name == "Vertices") {
geometry.vertices = createVec3Vector(data.properties.at(0).value<QVector<double> >()); mesh.vertices = createVec3Vector(data.properties.at(0).value<QVector<double> >());
} else if (data.name == "PolygonVertexIndex") { } else if (data.name == "PolygonVertexIndex") {
polygonIndices = data.properties.at(0).value<QVector<int> >(); polygonIndices = data.properties.at(0).value<QVector<int> >();
@ -277,7 +284,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
} else if (data.name == "LayerElementNormal") { } else if (data.name == "LayerElementNormal") {
foreach (const FBXNode& subdata, data.children) { foreach (const FBXNode& subdata, data.children) {
if (subdata.name == "Normals") { if (subdata.name == "Normals") {
geometry.normals = createVec3Vector( mesh.normals = createVec3Vector(
subdata.properties.at(0).value<QVector<double> >()); subdata.properties.at(0).value<QVector<double> >());
} }
} }
@ -290,25 +297,26 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
while (*endIndex++ >= 0); while (*endIndex++ >= 0);
if (endIndex - beginIndex == 4) { if (endIndex - beginIndex == 4) {
geometry.quadIndices.append(*beginIndex++); mesh.quadIndices.append(*beginIndex++);
geometry.quadIndices.append(*beginIndex++); mesh.quadIndices.append(*beginIndex++);
geometry.quadIndices.append(*beginIndex++); mesh.quadIndices.append(*beginIndex++);
geometry.quadIndices.append(-*beginIndex++ - 1); mesh.quadIndices.append(-*beginIndex++ - 1);
} else { } else {
for (const int* nextIndex = beginIndex + 1;; ) { for (const int* nextIndex = beginIndex + 1;; ) {
geometry.triangleIndices.append(*beginIndex); mesh.triangleIndices.append(*beginIndex);
geometry.triangleIndices.append(*nextIndex++); mesh.triangleIndices.append(*nextIndex++);
if (*nextIndex >= 0) { if (*nextIndex >= 0) {
geometry.triangleIndices.append(*nextIndex); mesh.triangleIndices.append(*nextIndex);
} else { } else {
geometry.triangleIndices.append(-*nextIndex - 1); mesh.triangleIndices.append(-*nextIndex - 1);
break; break;
} }
} }
beginIndex = endIndex; beginIndex = endIndex;
} }
} }
meshMap.insert(object.properties.at(0).value<qint64>(), mesh);
} else { // object.properties.at(2) == "Shape" } else { // object.properties.at(2) == "Shape"
FBXBlendshape blendshape; FBXBlendshape blendshape;
@ -328,14 +336,31 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
QByteArray name = object.properties.at(1).toByteArray(); QByteArray name = object.properties.at(1).toByteArray();
static QHash<QByteArray, int> blendshapeMap = createBlendshapeMap(); static QHash<QByteArray, int> blendshapeMap = createBlendshapeMap();
int index = blendshapeMap.value(name.left(name.indexOf('\0'))); int index = blendshapeMap.value(name.left(name.indexOf('\0')));
geometry.blendshapes.resize(qMax(geometry.blendshapes.size(), index + 1)); blendshapes.resize(qMax(blendshapes.size(), index + 1));
geometry.blendshapes[index] = blendshape; blendshapes[index] = blendshape;
} }
} } else if (object.name == "Deformer" && object.properties.at(2) == "BlendShape") {
blendshapeId = object.properties.at(0).value<qint64>();
}
}
} else if (child.name == "Connections") {
foreach (const FBXNode& connection, child.children) {
if (connection.name == "C") {
parentMap.insert(connection.properties.at(1).value<qint64>(), connection.properties.at(2).value<qint64>());
}
} }
} }
} }
// get the mesh that owns the blendshape
FBXGeometry geometry;
if (meshMap.size() == 1) {
geometry = *meshMap.begin();
} else {
geometry = meshMap.take(parentMap.value(blendshapeId));
}
geometry.blendshapes = blendshapes;
return geometry; return geometry;
} }