public static Node LoadHiearchy(Node parent, node daeNode,
                                        STGenericModel model, ColladaScene colladaScene)
        {
            Node node = new Node(parent);

            node.Name      = daeNode.name;
            node.Type      = daeNode.type;
            node.Transform = DaeUtility.GetMatrix(daeNode.Items) * parent.Transform;

            try
            {
                if (daeNode.instance_geometry != null)
                {
                    geometry geom = DaeUtility.FindGeoemertyFromNode(daeNode, colladaScene.geometries);
                    model.Meshes.Add(LoadMeshData(colladaScene, node, geom, colladaScene.materials));
                }
                if (daeNode.instance_controller != null)
                {
                    controller controller = DaeUtility.FindControllerFromNode(daeNode, colladaScene.controllers);
                    geometry   geom       = DaeUtility.FindGeoemertyFromController(controller, colladaScene.geometries);
                    model.Meshes.Add(LoadMeshData(colladaScene, node, geom, colladaScene.materials, controller));
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Failed to convert mesh {daeNode.name} \n {ex.ToString()}");
            }

            //Find the root bone
            if (node.Type == NodeType.JOINT)
            {
                //Apply axis rotation
                Matrix4 boneTransform = Matrix4.Identity;
                if (colladaScene.UpAxisType == UpAxisType.Y_UP)
                {
                    //  boneTransform = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(90));
                }
                if (colladaScene.UintSize != null && colladaScene.UintSize.meter != 1)
                {
                    var scale = ApplyUintScaling(colladaScene, new Vector3(1));
                    boneTransform *= Matrix4.CreateScale(scale);
                }

                LoadBoneHiearchy(daeNode, model, null, ref boneTransform);
            }
            else if (daeNode.node1 != null)
            {
                foreach (node child in daeNode.node1)
                {
                    node.Children.Add(LoadHiearchy(node, child, model, colladaScene));
                }
            }

            return(node);
        }
        private static List <BoneWeight[]> ParseWeightController(controller controller, ColladaScene scene)
        {
            if (controller == null)
            {
                return(new List <BoneWeight[]>());
            }

            List <BoneWeight[]> boneWeights = new List <BoneWeight[]>();
            skin skin = controller.Item as skin;

            string[] skinningCounts = skin.vertex_weights.vcount.Trim(' ').Split(' ');
            string[] indices        = skin.vertex_weights.v.Trim(' ').Split(' ');

            int maxSkinning = (int)scene.Settings.MaxSkinningCount;
            int stride      = skin.vertex_weights.input.Length;
            int indexOffset = 0;

            for (int v = 0; v < skinningCounts.Length; v++)
            {
                int numSkinning = Convert.ToInt32(skinningCounts[v]);

                BoneWeight[] boneWeightsArr = new BoneWeight[Math.Min(maxSkinning, numSkinning)];
                for (int j = 0; j < numSkinning; j++)
                {
                    if (j < scene.Settings.MaxSkinningCount)
                    {
                        boneWeightsArr[j] = new BoneWeight();
                        foreach (var input in skin.vertex_weights.input)
                        {
                            int offset = (int)input.offset;
                            var source = DaeUtility.FindSourceFromInput(input, skin.source);
                            int index  = Convert.ToInt32(indices[indexOffset + offset]);
                            if (input.semantic == "WEIGHT")
                            {
                                var weights = source.Item as float_array;
                                boneWeightsArr[j].Weight = (float)weights.Values[index];
                            }
                            if (input.semantic == "JOINT")
                            {
                                var bones = source.Item as Name_array;
                                boneWeightsArr[j].Bone = bones.Values[index];
                            }
                        }
                    }
                    indexOffset += stride;
                }

                boneWeightsArr = RemoveZeroWeights(boneWeightsArr);
                boneWeights.Add(boneWeightsArr);
            }

            return(boneWeights);
        }
        private static STBone LoadBoneHiearchy(node daeNode, STGenericModel model,
                                               STBone boneParent, ref Matrix4 parentTransform)
        {
            STBone bone = new STBone(model.Skeleton, daeNode.name);

            model.Skeleton.Bones.Add(bone);

            bone.Transform = DaeUtility.GetMatrix(daeNode.Items) * parentTransform;
            bone.Parent    = boneParent;
            Console.WriteLine("NODE " + bone.Name + " " + bone.Transform);

            parentTransform = Matrix4.Identity;

            if (daeNode.node1 != null)
            {
                foreach (node child in daeNode.node1)
                {
                    bone.Children.Add(LoadBoneHiearchy(child, model, bone, ref parentTransform));
                }
            }
            return(bone);
        }
        private static void ConvertPolygon(ColladaScene scene, STGenericMesh mesh, mesh daeMesh,
                                           InputLocalOffset[] inputs, List <BoneWeight[]> boneWeights,
                                           library_materials materials, string material, string polys, int polyCount, string vcount = "")
        {
            List <uint> faces = new List <uint>();

            STPolygonGroup group = new STPolygonGroup();

            mesh.PolygonGroups.Add(group);
            group.MaterialIndex = DaeUtility.FindMaterialIndex(materials, material);

            string[] indices     = polys.Trim(' ').Split(' ');
            string[] vertexCount = new string[0];
            if (vcount != string.Empty)
            {
                vertexCount = vcount.Trim(' ').Split(' ');
            }

            int stride = 0;

            for (int i = 0; i < inputs.Length; i++)
            {
                stride = Math.Max(0, (int)inputs[i].offset + 1);
            }

            //Create a current list of all the vertices
            //Use a list to expand duplicate indices
            List <Vertex> vertices     = new List <Vertex>();
            var           vertexSource = DaeUtility.FindSourceFromInput(daeMesh.vertices.input[0], daeMesh.source);
            var           floatArr     = vertexSource.Item as float_array;

            for (int v = 0; v < (int)floatArr.count / 3; v++)
            {
                vertices.Add(new Vertex(vertices.Count, new List <int>()));
            }

            var indexStride = (indices.Length / 3) / polyCount;

            for (int i = 0; i < polyCount; i++)
            {
                int count = 3;
                if (vertexCount.Length > i)
                {
                    count = Convert.ToInt32(vertexCount[i]);
                }

                for (int v = 0; v < count; v++)
                {
                    List <int> semanticIndices = new List <int>();
                    for (int j = 0; j < inputs.Length; j++)
                    {
                        int faceOffset = (indexStride * 3) * i;
                        int index      = Convert.ToInt32(indices[faceOffset + (v * indexStride) + (int)inputs[j].offset]);
                        semanticIndices.Add(index);
                    }

                    BoneWeight[] boneWeightData = new BoneWeight[0];
                    if (boneWeights?.Count > semanticIndices[0])
                    {
                        boneWeightData = boneWeights[semanticIndices[0]];
                    }

                    VertexLoader.LoadVertex(ref faces, ref vertices, semanticIndices, boneWeightData);
                }
            }

            int numTexCoordChannels = 0;
            int numColorChannels    = 0;

            //Find them in both types of inputs
            for (int i = 0; i < inputs.Length; i++)
            {
                if (inputs[i].semantic == "TEXCOORD")
                {
                    numTexCoordChannels++;
                }
                if (inputs[i].semantic == "COLOR")
                {
                    numColorChannels++;
                }
            }

            for (int i = 0; i < daeMesh.vertices.input.Length; i++)
            {
                if (daeMesh.vertices.input[i].semantic == "TEXCOORD")
                {
                    numTexCoordChannels++;
                }
                if (daeMesh.vertices.input[i].semantic == "COLOR")
                {
                    numColorChannels++;
                }
            }


            for (int i = 0; i < vertices.Count; i++)
            {
                if (!vertices[i].IsSet)
                {
                    vertices.Remove(vertices[i]);
                }
            }

            bool hasNormals = false;

            foreach (var daeVertex in vertices)
            {
                if (daeVertex.semanticIndices.Count == 0)
                {
                    continue;
                }

                STVertex vertex = new STVertex();
                vertex.TexCoords   = new Vector2[numTexCoordChannels];
                vertex.Colors      = new Vector4[numColorChannels];
                vertex.BoneWeights = daeVertex.BoneWeights.ToList();
                mesh.Vertices.Add(vertex);

                //DAE has 2 inputs. Vertex and triangle inputs
                //Triangle inputs use indices over vertex inputs which only use one
                //Triangle inputs allow multiple color/uv sets unlike vertex inputs
                //Certain programs ie Noesis DAEs use vertex inputs. Most programs use triangle inputs
                for (int j = 0; j < daeMesh.vertices.input.Length; j++)
                {
                    //Vertex inputs only use the first index
                    var    vertexInput = daeMesh.vertices.input[j];
                    source source      = DaeUtility.FindSourceFromInput(vertexInput, daeMesh.source);
                    if (source == null)
                    {
                        continue;
                    }
                    if (vertexInput.semantic == "NORMAL")
                    {
                        hasNormals = true;
                    }

                    int dataStride = (int)source.technique_common.accessor.stride;
                    int index      = daeVertex.semanticIndices[0] * dataStride;

                    ParseVertexSource(ref vertex, scene, source, numTexCoordChannels, numColorChannels,
                                      dataStride, index, 0, vertexInput.semantic);
                }

                for (int i = 0; i < inputs.Length; i++)
                {
                    var    input  = inputs[i];
                    source source = DaeUtility.FindSourceFromInput(input, daeMesh.source);
                    if (source == null)
                    {
                        continue;
                    }
                    if (input.semantic == "NORMAL")
                    {
                        hasNormals = true;
                    }

                    int dataStride = (int)source.technique_common.accessor.stride;
                    int index      = daeVertex.semanticIndices[i] * dataStride;

                    ParseVertexSource(ref vertex, scene, source, numTexCoordChannels, numColorChannels,
                                      dataStride, index, (int)input.set, input.semantic);
                }
            }

            group.Faces = faces;

            if (!hasNormals)
            {
                CalculateNormals(mesh.Vertices, faces);
            }
            if (scene.Settings.RemoveDuplicateVerts)
            {
                RemoveDuplicateVerts(mesh.Vertices, faces);
            }
        }