From d1d999dd7228d186ceea2165c73f68fc2b068edd Mon Sep 17 00:00:00 2001
From: raveenajain <jain.rav@husky.neu.edu>
Date: Fri, 5 Apr 2019 19:58:26 +0100
Subject: [PATCH 1/6] init node order fix

---
 libraries/fbx/src/GLTFSerializer.cpp | 37 ++++++++++++++++++++--------
 libraries/fbx/src/GLTFSerializer.h   |  2 +-
 2 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp
index 1699722215..ec58f15a95 100755
--- a/libraries/fbx/src/GLTFSerializer.cpp
+++ b/libraries/fbx/src/GLTFSerializer.cpp
@@ -751,7 +751,7 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>&
     }
 }
 
-void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, std::vector<int>& result) {
+void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool order, std::vector<int>& result) {
     int startingIndex = 0;
     int finalIndex = (int)children.size();
     if (stride == -1) {
@@ -763,10 +763,12 @@ void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children
         result.push_back(c);
         std::vector<int> nested = _file.nodes[c].children.toStdVector();
         if (nested.size() != 0) {
-            std::sort(nested.begin(), nested.end());
+            if (order) {
+                std::sort(nested.begin(), nested.end());
+            }
             for (int r : nested) {
                 if (result.end() == std::find(result.begin(), result.end(), r)) {
-                    getNodeQueueByDepthFirstChildren(nested, stride, result);
+                    getNodeQueueByDepthFirstChildren(nested, stride, order, result);
                 }
             }
         } 
@@ -776,13 +778,18 @@ void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children
 
 bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     int numNodes = _file.nodes.size();
+    bool skinnedModel = !_file.skins.isEmpty();
 
     //Build dependencies
     QVector<QVector<int>> nodeDependencies(numNodes);
     int nodecount = 0;
+    bool parentOutOfOrder = false;
     foreach(auto &node, _file.nodes) {
         //nodes_transforms.push_back(getModelTransform(node));
-        foreach(int child, node.children) nodeDependencies[child].push_back(nodecount);
+        foreach(int child, node.children) {
+            nodeDependencies[child].push_back(nodecount);
+            parentOutOfOrder |= nodecount < child;
+        }
         nodecount++;
     }
     
@@ -806,20 +813,27 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
 
 
     // initialize order in which nodes will be parsed
+    bool sortNodes = (!parentOutOfOrder && skinnedModel) || !skinnedModel;
     std::vector<int> nodeQueue;
     nodeQueue.reserve(numNodes);
     int rootNode = 0;
     int finalNode = numNodes;
-    if (!_file.scenes[_file.scene].nodes.contains(0)) {
-        rootNode = numNodes - 1;
-        finalNode = -1;
+    for (int sceneNode : _file.scenes[_file.scene].nodes) {
+        if (!_file.nodes[sceneNode].defined["camera"] && sceneNode != 0) {
+            rootNode = numNodes - 1;
+            finalNode = -1;
+            break;
+        }
     }
     bool rootAtStartOfList = rootNode < finalNode;
     int nodeListStride = 1;
     if (!rootAtStartOfList) { nodeListStride = -1; }
 
     QVector<int> initialSceneNodes = _file.scenes[_file.scene].nodes; 
-    std::sort(initialSceneNodes.begin(), initialSceneNodes.end());
+    if (sortNodes) {
+        std::sort(initialSceneNodes.begin(), initialSceneNodes.end());
+    }
+
     int sceneRootNode = 0; 
     int sceneFinalNode = initialSceneNodes.size();
     if (!rootAtStartOfList) { 
@@ -830,10 +844,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
         int i = initialSceneNodes[index];
         nodeQueue.push_back(i);
         std::vector<int> children = _file.nodes[i].children.toStdVector(); 
-        std::sort(children.begin(), children.end());
-        getNodeQueueByDepthFirstChildren(children, nodeListStride, nodeQueue);
+        if (sortNodes) {
+            std::sort(children.begin(), children.end());
+        }
+        getNodeQueueByDepthFirstChildren(children, nodeListStride, sortNodes, nodeQueue);
     }
 
+
     // Build joints
     HFMJoint joint;
     joint.distanceToParent = 0;
diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h
index d9c477bd99..dd3649478e 100755
--- a/libraries/fbx/src/GLTFSerializer.h
+++ b/libraries/fbx/src/GLTFSerializer.h
@@ -713,7 +713,7 @@ private:
 
     glm::mat4 getModelTransform(const GLTFNode& node);
     void getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues);
-    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, std::vector<int>& result);
+    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool order, std::vector<int>& result);
 
     bool buildGeometry(HFMModel& hfmModel, const hifi::URL& url);
     bool parseGLTF(const hifi::ByteArray& data);

From 40fe156c8b25ec2a3124d6c5f9d3fd02fe46fc0e Mon Sep 17 00:00:00 2001
From: raveenajain <jain.rav@husky.neu.edu>
Date: Mon, 8 Apr 2019 19:54:31 +0100
Subject: [PATCH 2/6] naming, condition

---
 libraries/fbx/src/GLTFSerializer.cpp | 14 +++++++-------
 libraries/fbx/src/GLTFSerializer.h   |  2 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp
index ec58f15a95..21df5bc2dc 100755
--- a/libraries/fbx/src/GLTFSerializer.cpp
+++ b/libraries/fbx/src/GLTFSerializer.cpp
@@ -751,7 +751,7 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>&
     }
 }
 
-void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool order, std::vector<int>& result) {
+void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool needToSort, std::vector<int>& result) {
     int startingIndex = 0;
     int finalIndex = (int)children.size();
     if (stride == -1) {
@@ -763,12 +763,12 @@ void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children
         result.push_back(c);
         std::vector<int> nested = _file.nodes[c].children.toStdVector();
         if (nested.size() != 0) {
-            if (order) {
+            if (needToSort) {
                 std::sort(nested.begin(), nested.end());
             }
             for (int r : nested) {
                 if (result.end() == std::find(result.begin(), result.end(), r)) {
-                    getNodeQueueByDepthFirstChildren(nested, stride, order, result);
+                    getNodeQueueByDepthFirstChildren(nested, stride, needToSort, result);
                 }
             }
         } 
@@ -813,7 +813,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
 
 
     // initialize order in which nodes will be parsed
-    bool sortNodes = (!parentOutOfOrder && skinnedModel) || !skinnedModel;
+    bool needToSort = !parentOutOfOrder || !skinnedModel;
     std::vector<int> nodeQueue;
     nodeQueue.reserve(numNodes);
     int rootNode = 0;
@@ -830,7 +830,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     if (!rootAtStartOfList) { nodeListStride = -1; }
 
     QVector<int> initialSceneNodes = _file.scenes[_file.scene].nodes; 
-    if (sortNodes) {
+    if (needToSort) {
         std::sort(initialSceneNodes.begin(), initialSceneNodes.end());
     }
 
@@ -844,10 +844,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
         int i = initialSceneNodes[index];
         nodeQueue.push_back(i);
         std::vector<int> children = _file.nodes[i].children.toStdVector(); 
-        if (sortNodes) {
+        if (needToSort) {
             std::sort(children.begin(), children.end());
         }
-        getNodeQueueByDepthFirstChildren(children, nodeListStride, sortNodes, nodeQueue);
+        getNodeQueueByDepthFirstChildren(children, nodeListStride, needToSort, nodeQueue);
     }
 
 
diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h
index dd3649478e..3eee24284e 100755
--- a/libraries/fbx/src/GLTFSerializer.h
+++ b/libraries/fbx/src/GLTFSerializer.h
@@ -713,7 +713,7 @@ private:
 
     glm::mat4 getModelTransform(const GLTFNode& node);
     void getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues);
-    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool order, std::vector<int>& result);
+    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool needToSort, std::vector<int>& result);
 
     bool buildGeometry(HFMModel& hfmModel, const hifi::URL& url);
     bool parseGLTF(const hifi::ByteArray& data);

From c970a58715fcc4e568b2dd99acf21939ede919ce Mon Sep 17 00:00:00 2001
From: raveenajain <jain.rav@husky.neu.edu>
Date: Tue, 9 Apr 2019 17:29:07 +0100
Subject: [PATCH 3/6] comments, edge case for skinned

---
 libraries/fbx/src/GLTFSerializer.cpp | 31 ++++++++++++++--------------
 libraries/fbx/src/GLTFSerializer.h   |  2 +-
 2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp
index 21df5bc2dc..e4a759fa9b 100755
--- a/libraries/fbx/src/GLTFSerializer.cpp
+++ b/libraries/fbx/src/GLTFSerializer.cpp
@@ -751,24 +751,23 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>&
     }
 }
 
-void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool needToSort, std::vector<int>& result) {
+void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool addChildrenInReverseOrder, std::vector<int>& result) {
     int startingIndex = 0;
     int finalIndex = (int)children.size();
-    if (stride == -1) {
+    if (stride == -1 || addChildrenInReverseOrder) {
         startingIndex = (int)children.size() - 1;
         finalIndex = -1;
+        stride = -1; 
     }
     for (int index = startingIndex; index != finalIndex; index += stride) {
         int c = children[index];
         result.push_back(c);
         std::vector<int> nested = _file.nodes[c].children.toStdVector();
         if (nested.size() != 0) {
-            if (needToSort) {
-                std::sort(nested.begin(), nested.end());
-            }
+            std::sort(nested.begin(), nested.end());
             for (int r : nested) {
                 if (result.end() == std::find(result.begin(), result.end(), r)) {
-                    getNodeQueueByDepthFirstChildren(nested, stride, needToSort, result);
+                    getNodeQueueByDepthFirstChildren(nested, stride, addChildrenInReverseOrder, result);
                 }
             }
         } 
@@ -783,12 +782,12 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     //Build dependencies
     QVector<QVector<int>> nodeDependencies(numNodes);
     int nodecount = 0;
-    bool parentOutOfOrder = false;
+    bool parentGreaterThanChild = false;
     foreach(auto &node, _file.nodes) {
         //nodes_transforms.push_back(getModelTransform(node));
         foreach(int child, node.children) {
             nodeDependencies[child].push_back(nodecount);
-            parentOutOfOrder |= nodecount < child;
+            parentGreaterThanChild |= nodecount > child;
         }
         nodecount++;
     }
@@ -813,12 +812,12 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
 
 
     // initialize order in which nodes will be parsed
-    bool needToSort = !parentOutOfOrder || !skinnedModel;
     std::vector<int> nodeQueue;
     nodeQueue.reserve(numNodes);
     int rootNode = 0;
     int finalNode = numNodes;
     for (int sceneNode : _file.scenes[_file.scene].nodes) {
+        // reverse the order in which the nodes are initialized 
         if (!_file.nodes[sceneNode].defined["camera"] && sceneNode != 0) {
             rootNode = numNodes - 1;
             finalNode = -1;
@@ -830,9 +829,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     if (!rootAtStartOfList) { nodeListStride = -1; }
 
     QVector<int> initialSceneNodes = _file.scenes[_file.scene].nodes; 
-    if (needToSort) {
-        std::sort(initialSceneNodes.begin(), initialSceneNodes.end());
-    }
+    std::sort(initialSceneNodes.begin(), initialSceneNodes.end());
 
     int sceneRootNode = 0; 
     int sceneFinalNode = initialSceneNodes.size();
@@ -840,14 +837,16 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
         sceneRootNode = initialSceneNodes.size() - 1;
         sceneFinalNode = -1;
     }
+    // this is an edge case where, for a skinned model, there is a parent who's index is greater than it's child's index
+    // when the opposite is expected
+    // in this case, we want the order of the children to be reversed, even if the root node is 0
+    bool addChildrenInReverseOrder = rootAtStartOfList && parentGreaterThanChild && skinnedModel;
     for (int index = sceneRootNode; index != sceneFinalNode; index += nodeListStride) {
         int i = initialSceneNodes[index];
         nodeQueue.push_back(i);
         std::vector<int> children = _file.nodes[i].children.toStdVector(); 
-        if (needToSort) {
-            std::sort(children.begin(), children.end());
-        }
-        getNodeQueueByDepthFirstChildren(children, nodeListStride, needToSort, nodeQueue);
+        std::sort(children.begin(), children.end());
+        getNodeQueueByDepthFirstChildren(children, nodeListStride, addChildrenInReverseOrder, nodeQueue);
     }
 
 
diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h
index 3eee24284e..ca4e79fcb6 100755
--- a/libraries/fbx/src/GLTFSerializer.h
+++ b/libraries/fbx/src/GLTFSerializer.h
@@ -713,7 +713,7 @@ private:
 
     glm::mat4 getModelTransform(const GLTFNode& node);
     void getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues);
-    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool needToSort, std::vector<int>& result);
+    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool addChildrenInReverseOrder, std::vector<int>& result);
 
     bool buildGeometry(HFMModel& hfmModel, const hifi::URL& url);
     bool parseGLTF(const hifi::ByteArray& data);

From 3c84a46cba8590980e5ea3479465705b72de5327 Mon Sep 17 00:00:00 2001
From: raveenajain <jain.rav@husky.neu.edu>
Date: Mon, 15 Apr 2019 20:27:54 +0100
Subject: [PATCH 4/6] update how nodes are initially parsed

---
 libraries/fbx/src/GLTFSerializer.cpp | 143 +++++++++++++--------------
 libraries/fbx/src/GLTFSerializer.h   |   1 -
 2 files changed, 69 insertions(+), 75 deletions(-)

diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp
index e4a759fa9b..95d055481a 100755
--- a/libraries/fbx/src/GLTFSerializer.cpp
+++ b/libraries/fbx/src/GLTFSerializer.cpp
@@ -751,43 +751,25 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>&
     }
 }
 
-void GLTFSerializer::getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool addChildrenInReverseOrder, std::vector<int>& result) {
-    int startingIndex = 0;
-    int finalIndex = (int)children.size();
-    if (stride == -1 || addChildrenInReverseOrder) {
-        startingIndex = (int)children.size() - 1;
-        finalIndex = -1;
-        stride = -1; 
-    }
-    for (int index = startingIndex; index != finalIndex; index += stride) {
-        int c = children[index];
-        result.push_back(c);
-        std::vector<int> nested = _file.nodes[c].children.toStdVector();
-        if (nested.size() != 0) {
-            std::sort(nested.begin(), nested.end());
-            for (int r : nested) {
-                if (result.end() == std::find(result.begin(), result.end(), r)) {
-                    getNodeQueueByDepthFirstChildren(nested, stride, addChildrenInReverseOrder, result);
-                }
-            }
-        } 
-    }
-}
-
-
 bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     int numNodes = _file.nodes.size();
     bool skinnedModel = !_file.skins.isEmpty();
 
+
     //Build dependencies
     QVector<QVector<int>> nodeDependencies(numNodes);
+    QVector<int> parents;
+    QVector<int> nodesToSort = _file.scenes[_file.scene].nodes;
+    parents.fill(-1, numNodes);
+    nodesToSort.reserve(numNodes);
     int nodecount = 0;
-    bool parentGreaterThanChild = false;
     foreach(auto &node, _file.nodes) {
-        //nodes_transforms.push_back(getModelTransform(node));
         foreach(int child, node.children) {
             nodeDependencies[child].push_back(nodecount);
-            parentGreaterThanChild |= nodecount > child;
+            parents[child] = nodecount;
+        }
+        if (!nodesToSort.contains(nodecount)) {
+            nodesToSort.push_back(nodecount);
         }
         nodecount++;
     }
@@ -806,47 +788,62 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                 } else break;
             }
         }
-        
         nodecount++;
     }
 
-
+ 
     // initialize order in which nodes will be parsed
     std::vector<int> nodeQueue;
-    nodeQueue.reserve(numNodes);
-    int rootNode = 0;
-    int finalNode = numNodes;
-    for (int sceneNode : _file.scenes[_file.scene].nodes) {
-        // reverse the order in which the nodes are initialized 
-        if (!_file.nodes[sceneNode].defined["camera"] && sceneNode != 0) {
-            rootNode = numNodes - 1;
-            finalNode = -1;
-            break;
+    QVector<int> originalToNewNodeIndexMap;
+    QVector<bool> hasBeenSorted;
+    originalToNewNodeIndexMap.fill(-1, numNodes);
+    hasBeenSorted.fill(false, numNodes);
+    nodeQueue = _file.scenes[_file.scene].nodes.toStdVector();
+
+    for (int sceneNodeCount = 0; sceneNodeCount < _file.scenes[_file.scene].nodes.size(); sceneNodeCount++) {
+        int sceneNode = nodeQueue[sceneNodeCount];
+        originalToNewNodeIndexMap[sceneNode] = sceneNodeCount;
+        nodesToSort[nodesToSort.indexOf(sceneNode)] = nodesToSort.back();
+        nodesToSort.pop_back();
+        hasBeenSorted[sceneNode] = true;
+        for (int child : _file.nodes[sceneNode].children.toStdVector()) {
+            nodesToSort[nodesToSort.indexOf(child)] = nodesToSort.back();
+            nodesToSort.pop_back();
         }
-    }
-    bool rootAtStartOfList = rootNode < finalNode;
-    int nodeListStride = 1;
-    if (!rootAtStartOfList) { nodeListStride = -1; }
 
-    QVector<int> initialSceneNodes = _file.scenes[_file.scene].nodes; 
-    std::sort(initialSceneNodes.begin(), initialSceneNodes.end());
+        for (int child : _file.nodes[sceneNode].children) {
+            originalToNewNodeIndexMap[child] = nodeQueue.size();
+            nodeQueue.push_back(child);
+            hasBeenSorted[child] = true;
 
-    int sceneRootNode = 0; 
-    int sceneFinalNode = initialSceneNodes.size();
-    if (!rootAtStartOfList) { 
-        sceneRootNode = initialSceneNodes.size() - 1;
-        sceneFinalNode = -1;
-    }
-    // this is an edge case where, for a skinned model, there is a parent who's index is greater than it's child's index
-    // when the opposite is expected
-    // in this case, we want the order of the children to be reversed, even if the root node is 0
-    bool addChildrenInReverseOrder = rootAtStartOfList && parentGreaterThanChild && skinnedModel;
-    for (int index = sceneRootNode; index != sceneFinalNode; index += nodeListStride) {
-        int i = initialSceneNodes[index];
-        nodeQueue.push_back(i);
-        std::vector<int> children = _file.nodes[i].children.toStdVector(); 
-        std::sort(children.begin(), children.end());
-        getNodeQueueByDepthFirstChildren(children, nodeListStride, addChildrenInReverseOrder, nodeQueue);
+            if (!_file.nodes[child].children.isEmpty() && nodeQueue.size() < numNodes) {
+                int newSize = nodesToSort.size();
+                while (!nodesToSort.isEmpty()) {
+                    int i = 0;
+
+                    while (i < nodesToSort.size()) {
+                        int nodeIndex = nodesToSort[i];
+                        int parentIndex = parents[nodeIndex];
+                        newSize = nodesToSort.size();
+
+                        if ((parentIndex == -1 || hasBeenSorted[parentIndex])) {
+                            originalToNewNodeIndexMap[nodeIndex] = nodeQueue.size();
+                            nodeQueue.push_back(nodeIndex);
+                            hasBeenSorted[nodeIndex] = true;
+                            // copy back and pop
+                            nodesToSort[i] = nodesToSort.back();
+                            nodesToSort.pop_back();
+                        } else {  // skip
+                            i++;
+                        }
+                    }
+                    // if the end of nodesToSort is reached without removing any nodes, break to move onto the next child
+                    if (newSize == nodesToSort.size() && i == nodesToSort.size()) {
+                        break;
+                    }
+                }
+            }
+        }
     }
 
 
@@ -861,13 +858,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
 
         joint.parentIndex = -1;
         if (!_file.scenes[_file.scene].nodes.contains(nodeIndex)) {
-            joint.parentIndex = std::distance(nodeQueue.begin(), std::find(nodeQueue.begin(), nodeQueue.end(), nodeDependencies[nodeIndex][0]));
+            joint.parentIndex = originalToNewNodeIndexMap[parents[nodeIndex]];
         }
         joint.transform = node.transforms.first();
         joint.translation = extractTranslation(joint.transform);
         joint.rotation = glmExtractRotation(joint.transform);
         glm::vec3 scale = extractScale(joint.transform);
-        joint.postTransform = glm::scale(glm::mat4(), scale);        
+        joint.postTransform = glm::scale(glm::mat4(), scale);  
 
         joint.name = node.name;
         joint.isSkeletonJoint = false;
@@ -882,20 +879,19 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
         std::vector<std::vector<float>> inverseBindValues;
         getSkinInverseBindMatrices(inverseBindValues);
 
-        int jointIndex = finalNode;
-        while (jointIndex != rootNode) {
-            rootAtStartOfList ? jointIndex-- : jointIndex++;
-            int jOffset = nodeQueue[jointIndex];
+        for (int jointIndex = 0; jointIndex < numNodes; jointIndex++) {
+            int nodeIndex = nodeQueue[jointIndex];
             auto joint = hfmModel.joints[jointIndex];
 
             hfmModel.hasSkeletonJoints = true;
             for (int s = 0; s < _file.skins.size(); s++) {
-                auto skin = _file.skins[s];
-                joint.isSkeletonJoint = skin.joints.contains(jOffset);
+                const auto& skin = _file.skins[s];
+                int matrixIndex = skin.joints.indexOf(nodeIndex);
+                joint.isSkeletonJoint = skin.joints.contains(nodeIndex);
 
                 if (joint.isSkeletonJoint) {
-                    std::vector<float> value = inverseBindValues[s];
-                    int matrixCount = 16 * skin.joints.indexOf(jOffset);
+                    std::vector<float>& value = inverseBindValues[s];
+                    int matrixCount = 16 * matrixIndex;
                     jointInverseBindTransforms[jointIndex] =
                         glm::mat4(value[matrixCount], value[matrixCount + 1], value[matrixCount + 2], value[matrixCount + 3], 
                             value[matrixCount + 4], value[matrixCount + 5], value[matrixCount + 6], value[matrixCount + 7], 
@@ -932,7 +928,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     
     // Build meshes
     nodecount = 0;
-    for (int nodeIndex = rootNode; nodeIndex != finalNode; nodeIndex += nodeListStride) {
+    for (int nodeIndex : nodeQueue) {
         auto& node = _file.nodes[nodeIndex];
 
         if (node.defined["mesh"]) {
@@ -947,7 +943,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);
                     mesh.clusters.append(cluster);
                 } else {
-                    for (int j = rootNode; j != finalNode; j += nodeListStride) {
+                    for (int j : nodeQueue) {
                         HFMCluster cluster;
                         cluster.jointIndex = j;
                         cluster.inverseBindMatrix = jointInverseBindTransforms[j];
@@ -956,7 +952,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     }
                 }
                 HFMCluster root; 
-                root.jointIndex = rootNode;
+                root.jointIndex = nodeQueue[0];
                 if (root.jointIndex == -1) { 
                     root.jointIndex = 0; 
                 }
@@ -1181,7 +1177,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
         nodecount++;
     }
 
-    
     return true;
 }
 
diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h
index ca4e79fcb6..a9e7152e5b 100755
--- a/libraries/fbx/src/GLTFSerializer.h
+++ b/libraries/fbx/src/GLTFSerializer.h
@@ -713,7 +713,6 @@ private:
 
     glm::mat4 getModelTransform(const GLTFNode& node);
     void getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues);
-    void getNodeQueueByDepthFirstChildren(std::vector<int>& children, int stride, bool addChildrenInReverseOrder, std::vector<int>& result);
 
     bool buildGeometry(HFMModel& hfmModel, const hifi::URL& url);
     bool parseGLTF(const hifi::ByteArray& data);

From 104ed758b9f4fa32ca232e1247284af474ed8eb6 Mon Sep 17 00:00:00 2001
From: raveenajain <jain.rav@husky.neu.edu>
Date: Wed, 17 Apr 2019 17:52:48 +0100
Subject: [PATCH 5/6] re-order nodes, cluster update

---
 libraries/fbx/src/GLTFSerializer.cpp | 140 +++++++++++----------------
 1 file changed, 57 insertions(+), 83 deletions(-)

diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp
index 95d055481a..497d1f6ef0 100755
--- a/libraries/fbx/src/GLTFSerializer.cpp
+++ b/libraries/fbx/src/GLTFSerializer.cpp
@@ -753,107 +753,82 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>&
 
 bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     int numNodes = _file.nodes.size();
-    bool skinnedModel = !_file.skins.isEmpty();
 
-
-    //Build dependencies
-    QVector<QVector<int>> nodeDependencies(numNodes);
+    // Build dependencies
     QVector<int> parents;
-    QVector<int> nodesToSort = _file.scenes[_file.scene].nodes;
+    QVector<int> sortedNodes;
     parents.fill(-1, numNodes);
-    nodesToSort.reserve(numNodes);
+    sortedNodes.reserve(numNodes);
     int nodecount = 0;
     foreach(auto &node, _file.nodes) {
         foreach(int child, node.children) {
-            nodeDependencies[child].push_back(nodecount);
             parents[child] = nodecount;
         }
-        if (!nodesToSort.contains(nodecount)) {
-            nodesToSort.push_back(nodecount);
-        }
+        sortedNodes.push_back(nodecount);
         nodecount++;
     }
     
+
+    // Build transforms
     nodecount = 0;
     foreach(auto &node, _file.nodes) {
         // collect node transform
-        _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); 
-        if (nodeDependencies[nodecount].size() == 1) {
-            int parentidx = nodeDependencies[nodecount][0];
-            while (true) { // iterate parents
-                // collect parents transforms
-                _file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx])); 
-                if (nodeDependencies[parentidx].size() == 1) {
-                    parentidx = nodeDependencies[parentidx][0];
-                } else break;
-            }
+        _file.nodes[nodecount].transforms.push_back(getModelTransform(node));
+        int parentIndex = parents[nodecount];
+        while (parentIndex != -1) {
+            const auto& parentNode = _file.nodes[parentIndex];
+            // collect transforms for a node's parents, grandparents, etc.
+            _file.nodes[nodecount].transforms.push_back(getModelTransform(parentNode));
+            parentIndex = parents[parentIndex];
         }
         nodecount++;
     }
 
  
-    // initialize order in which nodes will be parsed
-    std::vector<int> nodeQueue;
-    QVector<int> originalToNewNodeIndexMap;
+    // since parent indices must exist in the sorted list before any of their children, sortedNodes might not be initialized in the correct order
+    // therefore we need to re-initialize the order in which nodes will be parsed
     QVector<bool> hasBeenSorted;
-    originalToNewNodeIndexMap.fill(-1, numNodes);
     hasBeenSorted.fill(false, numNodes);
-    nodeQueue = _file.scenes[_file.scene].nodes.toStdVector();
-
-    for (int sceneNodeCount = 0; sceneNodeCount < _file.scenes[_file.scene].nodes.size(); sceneNodeCount++) {
-        int sceneNode = nodeQueue[sceneNodeCount];
-        originalToNewNodeIndexMap[sceneNode] = sceneNodeCount;
-        nodesToSort[nodesToSort.indexOf(sceneNode)] = nodesToSort.back();
-        nodesToSort.pop_back();
-        hasBeenSorted[sceneNode] = true;
-        for (int child : _file.nodes[sceneNode].children.toStdVector()) {
-            nodesToSort[nodesToSort.indexOf(child)] = nodesToSort.back();
-            nodesToSort.pop_back();
-        }
-
-        for (int child : _file.nodes[sceneNode].children) {
-            originalToNewNodeIndexMap[child] = nodeQueue.size();
-            nodeQueue.push_back(child);
-            hasBeenSorted[child] = true;
-
-            if (!_file.nodes[child].children.isEmpty() && nodeQueue.size() < numNodes) {
-                int newSize = nodesToSort.size();
-                while (!nodesToSort.isEmpty()) {
-                    int i = 0;
-
-                    while (i < nodesToSort.size()) {
-                        int nodeIndex = nodesToSort[i];
-                        int parentIndex = parents[nodeIndex];
-                        newSize = nodesToSort.size();
-
-                        if ((parentIndex == -1 || hasBeenSorted[parentIndex])) {
-                            originalToNewNodeIndexMap[nodeIndex] = nodeQueue.size();
-                            nodeQueue.push_back(nodeIndex);
-                            hasBeenSorted[nodeIndex] = true;
-                            // copy back and pop
-                            nodesToSort[i] = nodesToSort.back();
-                            nodesToSort.pop_back();
-                        } else {  // skip
-                            i++;
-                        }
-                    }
-                    // if the end of nodesToSort is reached without removing any nodes, break to move onto the next child
-                    if (newSize == nodesToSort.size() && i == nodesToSort.size()) {
-                        break;
-                    }
+    int i = 0;  // initial index
+    while (i < numNodes) {
+        int currentNode = sortedNodes[i];
+        int parentIndex = parents[currentNode];
+        if (parentIndex == -1 || hasBeenSorted[parentIndex]) {
+            hasBeenSorted[currentNode] = true;
+            i++;
+        } else {
+            int j = i + 1; // index of node to be sorted
+            while (j < numNodes) {
+                int nextNode = sortedNodes[j];
+                parentIndex = parents[nextNode];
+                if (parentIndex == -1 || hasBeenSorted[parentIndex]) {
+                    // swap with currentNode
+                    hasBeenSorted[nextNode] = true;
+                    sortedNodes[i] = nextNode;
+                    sortedNodes[j] = currentNode;
+                    i++;
+                    break;
                 }
+                j++;
             }
         }
     }
 
 
+     // Build map from original to new indices
+    QVector<int> originalToNewNodeIndexMap;
+    originalToNewNodeIndexMap.fill(-1, numNodes);
+    for (int i = 0; i < numNodes; i++) {
+        originalToNewNodeIndexMap[sortedNodes[i]] = i;
+    }
+
+
     // Build joints
     HFMJoint joint;
     joint.distanceToParent = 0;
     hfmModel.jointIndices["x"] = numNodes;
-    hfmModel.hasSkeletonJoints = false;
 
-    for (int nodeIndex : nodeQueue) {
+    for (int nodeIndex : sortedNodes) {
         auto& node = _file.nodes[nodeIndex];
 
         joint.parentIndex = -1;
@@ -873,22 +848,24 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
 
 
     // Build skeleton
+    hfmModel.hasSkeletonJoints = false;
     std::vector<glm::mat4> jointInverseBindTransforms;
     jointInverseBindTransforms.resize(numNodes);
     if (!_file.skins.isEmpty()) {
+        hfmModel.hasSkeletonJoints = true;
         std::vector<std::vector<float>> inverseBindValues;
         getSkinInverseBindMatrices(inverseBindValues);
 
         for (int jointIndex = 0; jointIndex < numNodes; jointIndex++) {
-            int nodeIndex = nodeQueue[jointIndex];
+            int nodeIndex = sortedNodes[jointIndex];
             auto joint = hfmModel.joints[jointIndex];
 
-            hfmModel.hasSkeletonJoints = true;
             for (int s = 0; s < _file.skins.size(); s++) {
                 const auto& skin = _file.skins[s];
                 int matrixIndex = skin.joints.indexOf(nodeIndex);
                 joint.isSkeletonJoint = skin.joints.contains(nodeIndex);
 
+                // build inverse bind matrices
                 if (joint.isSkeletonJoint) {
                     std::vector<float>& value = inverseBindValues[s];
                     int matrixCount = 16 * matrixIndex;
@@ -908,7 +885,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     }
 
 
-    //Build materials
+    // Build materials
     QVector<QString> materialIDs;
     QString unknown = "Default";
     int ukcount = 0;
@@ -928,7 +905,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     
     // Build meshes
     nodecount = 0;
-    for (int nodeIndex : nodeQueue) {
+    for (int nodeIndex : sortedNodes) {
         auto& node = _file.nodes[nodeIndex];
 
         if (node.defined["mesh"]) {
@@ -936,14 +913,14 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
             foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
                 hfmModel.meshes.append(HFMMesh());
                 HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1];
-                if (!hfmModel.hasSkeletonJoints) {
+                if (!hfmModel.hasSkeletonJoints) { 
                     HFMCluster cluster;
                     cluster.jointIndex = nodecount;
                     cluster.inverseBindMatrix = glm::mat4();
                     cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);
                     mesh.clusters.append(cluster);
-                } else {
-                    for (int j : nodeQueue) {
+                } else { // skinned model
+                    for (int j = 0; j < numNodes; j++) {
                         HFMCluster cluster;
                         cluster.jointIndex = j;
                         cluster.inverseBindMatrix = jointInverseBindTransforms[j];
@@ -952,10 +929,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     }
                 }
                 HFMCluster root; 
-                root.jointIndex = nodeQueue[0];
-                if (root.jointIndex == -1) { 
-                    root.jointIndex = 0; 
-                }
+                root.jointIndex = sortedNodes[0];
                 root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex];
                 root.inverseBindTransform = Transform(root.inverseBindMatrix);
                 mesh.clusters.append(root);
@@ -1055,6 +1029,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                             qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url;
                             continue;
                         }
+                        // tangents can be a vec3 or a vec4 which includes a w component (of -1 or 1)
                         int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3;
                         for (int n = 0; n < tangents.size() - 3; n += stride) {
                             float tanW = stride == 4 ? tangents[n + 3] : 1; 
@@ -1123,7 +1098,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     }
                 }
             
-                // adapted from FBXSerializer.cpp
+                // Build weights (adapted from FBXSerializer.cpp)
                 if (hfmModel.hasSkeletonJoints) {
                     int numClusterIndices = clusterJoints.size();
                     const int WEIGHTS_PER_VERTEX = 4;
@@ -1133,7 +1108,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     mesh.clusterWeights.fill(0, numClusterIndices);
 
                     for (int c = 0; c < clusterJoints.size(); c++) {
-                        mesh.clusterIndices[c] = _file.skins[node.skin].joints[clusterJoints[c]];
+                        mesh.clusterIndices[c] = originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]];
                     }
 
                     // normalize and compress to 16-bits
@@ -1172,7 +1147,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                
                 mesh.meshIndex = hfmModel.meshes.size();
             }
-            
         }
         nodecount++;
     }

From 2fab5a0945cdce019171495200b580751fa55d8a Mon Sep 17 00:00:00 2001
From: raveenajain <jain.rav@husky.neu.edu>
Date: Wed, 17 Apr 2019 21:14:44 +0100
Subject: [PATCH 6/6] parents, skeleton, break fix

---
 libraries/fbx/src/GLTFSerializer.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp
index 497d1f6ef0..a4d18fb111 100755
--- a/libraries/fbx/src/GLTFSerializer.cpp
+++ b/libraries/fbx/src/GLTFSerializer.cpp
@@ -807,7 +807,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     sortedNodes[i] = nextNode;
                     sortedNodes[j] = currentNode;
                     i++;
-                    break;
+                    currentNode = sortedNodes[i];
                 }
                 j++;
             }
@@ -831,9 +831,9 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
     for (int nodeIndex : sortedNodes) {
         auto& node = _file.nodes[nodeIndex];
 
-        joint.parentIndex = -1;
-        if (!_file.scenes[_file.scene].nodes.contains(nodeIndex)) {
-            joint.parentIndex = originalToNewNodeIndexMap[parents[nodeIndex]];
+        joint.parentIndex = parents[nodeIndex];
+        if (joint.parentIndex != -1) {
+            joint.parentIndex = originalToNewNodeIndexMap[joint.parentIndex];
         }
         joint.transform = node.transforms.first();
         joint.translation = extractTranslation(joint.transform);
@@ -848,10 +848,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
 
 
     // Build skeleton
-    hfmModel.hasSkeletonJoints = false;
     std::vector<glm::mat4> jointInverseBindTransforms;
     jointInverseBindTransforms.resize(numNodes);
-    if (!_file.skins.isEmpty()) {
+    hfmModel.hasSkeletonJoints = !_file.skins.isEmpty();
+    if (hfmModel.hasSkeletonJoints) {
         hfmModel.hasSkeletonJoints = true;
         std::vector<std::vector<float>> inverseBindValues;
         getSkinInverseBindMatrices(inverseBindValues);
@@ -929,7 +929,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
                     }
                 }
                 HFMCluster root; 
-                root.jointIndex = sortedNodes[0];
+                root.jointIndex = 0;
                 root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex];
                 root.inverseBindTransform = Transform(root.inverseBindMatrix);
                 mesh.clusters.append(root);