示例#1
0
        static void SearchHierarchy(xxFrame root, xxFrame frame, HashSet <string> meshNames, HashSet <string> exportFrames)
        {
            if (frame.Mesh != null)
            {
                if (meshNames.Contains(frame.Name))
                {
                    xxFrame parent = frame;
                    while (parent != null)
                    {
                        exportFrames.Add(parent.Name);
                        parent = (xxFrame)parent.Parent;
                    }

                    xxMesh        meshListSome = frame.Mesh;
                    List <xxBone> boneList     = meshListSome.BoneList;
                    for (int i = 0; i < boneList.Count; i++)
                    {
                        if (!exportFrames.Contains(boneList[i].Name))
                        {
                            xxFrame boneParent = FindFrame(boneList[i].Name, root);
                            while (boneParent != null)
                            {
                                exportFrames.Add(boneParent.Name);
                                boneParent = (xxFrame)boneParent.Parent;
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < frame.Count; i++)
            {
                SearchHierarchy(root, frame[i], meshNames, exportFrames);
            }
        }
示例#2
0
        public xxMesh Clone(bool submeshes, bool vertexListDup, bool boneList)
        {
            xxMesh mesh = new xxMesh();

            mesh.SubmeshList                = new List <xxSubmesh>(SubmeshList.Count);
            mesh.NumVector2PerVertex        = NumVector2PerVertex;
            mesh.VertexListDuplicateUnknown = (byte[])VertexListDuplicateUnknown.Clone();
            mesh.VertexListDuplicate        = new List <xxVertex>(VertexListDuplicate.Count);
            mesh.BoneList = new List <xxBone>(BoneList.Count);

            if (submeshes)
            {
                for (int i = 0; i < SubmeshList.Count; i++)
                {
                    mesh.SubmeshList.Add(SubmeshList[i].Clone());
                }
            }
            if (vertexListDup)
            {
                for (int i = 0; i < VertexListDuplicate.Count; i++)
                {
                    mesh.VertexListDuplicate.Add(VertexListDuplicate[i].Clone());
                }
            }
            if (boneList)
            {
                for (int i = 0; i < BoneList.Count; i++)
                {
                    mesh.BoneList.Add(BoneList[i].Clone());
                }
            }
            return(mesh);
        }
示例#3
0
 public static void CreateUnknowns(xxMesh mesh)
 {
     mesh.NumVector2PerVertex        = 0;
     mesh.VertexListDuplicateUnknown = IsSkinned(mesh)
                         ? new byte[] { 0x1C, 0x11, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00 }
                         : new byte[] { 0x12, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00 };
 }
示例#4
0
 public static void SetBoundingBox(xxFrame frame)
 {
     if (frame.Mesh == null)
     {
         frame.Bounds = new BoundingBox();
     }
     else
     {
         xxMesh  meshList = frame.Mesh;
         Vector3 min      = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue);
         Vector3 max      = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue);
         for (int i = 0; i < meshList.SubmeshList.Count; i++)
         {
             List <xxVertex> vertList = meshList.SubmeshList[i].VertexList;
             for (int j = 0; j < vertList.Count; j++)
             {
                 xxVertex vert = vertList[j];
                 Vector3  pos  = vert.Position;
                 min = Vector3.Minimize(min, pos);
                 max = Vector3.Maximize(max, pos);
             }
         }
         frame.Bounds = new BoundingBox(min, max);
     }
 }
示例#5
0
文件: xaOps.cs 项目: kkdevs/sb3u
        public static int MorphMeshObjIdx(ushort[] meshIndices, xxMesh mesh)
        {
            int meshObjIdx = -1;

            if (mesh.SubmeshList.Count > 0)
            {
                if (mesh.SubmeshList.Count == 1)
                {
                    if (ValidIndices(meshIndices, mesh.SubmeshList[0].VertexList))
                    {
                        meshObjIdx = 0;
                    }
                }
                else
                {
                    float maxModified = 0;
                    for (int i = 0; i < mesh.SubmeshList.Count; i++)
                    {
                        if (ValidIndices(meshIndices, mesh.SubmeshList[i].VertexList))
                        {
                            float modified = (float)meshIndices.Length / mesh.SubmeshList[i].VertexList.Count;
                            if (modified > maxModified)
                            {
                                maxModified = modified;
                                meshObjIdx  = i;
                            }
                        }
                    }
                }
            }
            return(meshObjIdx);
        }
示例#6
0
        public static void SetNumVector2PerVertex(xxMesh mesh, byte value)
        {
            int diff = value - mesh.NumVector2PerVertex;

            if (diff < 0)
            {
                if (value == 0)
                {
                    for (int i = 0; i < mesh.SubmeshList.Count; i++)
                    {
                        mesh.SubmeshList[i].Vector2Lists = null;
                    }
                }
                else
                {
                    diff = Math.Abs(diff);
                    for (int i = 0; i < mesh.SubmeshList.Count; i++)
                    {
                        var submesh = mesh.SubmeshList[i];
                        for (int j = 0; j < submesh.VertexList.Count; j++)
                        {
                            var vectorList = submesh.Vector2Lists[j];
                            vectorList.RemoveRange(vectorList.Count - diff, diff);
                        }
                    }
                }
            }
            else if (diff > 0)
            {
                for (int i = 0; i < mesh.SubmeshList.Count; i++)
                {
                    var submesh = mesh.SubmeshList[i];
                    if (submesh.Vector2Lists == null)
                    {
                        submesh.Vector2Lists = new List <List <Vector2> >(submesh.VertexList.Count);
                        for (int j = 0; j < submesh.VertexList.Count; j++)
                        {
                            submesh.Vector2Lists.Add(new List <Vector2>(value));
                            for (int k = 0; k < diff; k++)
                            {
                                submesh.Vector2Lists[j].Add(new Vector2());
                            }
                        }
                    }
                    else
                    {
                        for (int j = 0; j < submesh.VertexList.Count; j++)
                        {
                            for (int k = 0; k < diff; k++)
                            {
                                submesh.Vector2Lists[j].Add(new Vector2());
                            }
                        }
                    }
                }
            }

            mesh.NumVector2PerVertex = value;
        }
示例#7
0
            private void Export(DirectoryInfo dir, xxFrame meshFrame)
            {
                try
                {
                    xaMorphSection  morphSection = xaParser.MorphSection;
                    xaMorphIndexSet indexSet     = xa.FindMorphIndexSet(clip.Name, morphSection);
                    ushort[]        meshIndices  = indexSet.MeshIndices;
                    ushort[]        morphIndices = indexSet.MorphIndices;

                    xxMesh meshList   = meshFrame.Mesh;
                    int    meshObjIdx = xa.MorphMeshObjIdx(meshIndices, meshList);
                    if (meshObjIdx < 0)
                    {
                        throw new Exception("no valid mesh object was found for the morph");
                    }

                    xxSubmesh meshObjBase = meshList.SubmeshList[meshObjIdx];
                    colorVertex = new bool[meshObjBase.VertexList.Count];
                    for (int i = 0; i < meshIndices.Length; i++)
                    {
                        colorVertex[meshIndices[i]] = true;
                    }

                    string dest = Utility.GetDestFile(dir, meshFrame.Name + "-" + clip.Name + "-", ".morph.mqo");

                    List <xaMorphKeyframeRef> refList = clip.KeyframeRefList;
                    morphNames = new List <string>(refList.Count);
                    vertLists  = new List <List <ImportedVertex> >(refList.Count);
                    for (int i = 0; i < refList.Count; i++)
                    {
                        if (!morphNames.Contains(refList[i].Name))
                        {
                            List <ImportedVertex> vertList = xx.ImportedVertexList(meshObjBase.VertexList, xx.IsSkinned(meshList));
                            vertLists.Add(vertList);

                            xaMorphKeyframe keyframe = xa.FindMorphKeyFrame(refList[i].Name, morphSection);
                            for (int j = 0; j < meshIndices.Length; j++)
                            {
                                ImportedVertex vert = vertList[meshIndices[j]];
                                vert.Position = keyframe.PositionList[morphIndices[j]];
                            }
                            morphNames.Add(keyframe.Name);
                        }
                    }

                    faceList = xx.ImportedFaceList(meshObjBase.FaceList);
                    Export(dest, meshObjBase.MaterialIndex);
                    foreach (xxTexture tex in usedTextures)
                    {
                        xx.ExportTexture(tex, dir.FullName + @"\" + Path.GetFileName(tex.Name));
                    }
                    Report.ReportLog("Finished exporting morph to " + dest);
                }
                catch (Exception ex)
                {
                    Report.ReportLog("Error exporting morph: " + ex.Message);
                }
            }
示例#8
0
文件: xxEditor.cs 项目: kkdevs/sb3u
        public void MoveSubmesh(int meshId, int submeshId, int newPosition)
        {
            xxMesh    mesh = Meshes[meshId].Mesh;
            xxSubmesh src  = mesh.SubmeshList[submeshId];

            mesh.SubmeshList.Remove(src);
            mesh.SubmeshList.Insert(newPosition, src);
            Changed = true;
        }
示例#9
0
        public static bool RemoveUnusedBones(xxMesh mesh)
        {
            List <List <xxVertex> > vertexLists = new List <List <xxVertex> >(mesh.SubmeshList.Count);

            foreach (xxSubmesh submesh in mesh.SubmeshList)
            {
                vertexLists.Add(submesh.VertexList);
            }
            RemoveUnusedBones(vertexLists, mesh.BoneList);

            return(mesh.BoneList.Count > 0);
        }
示例#10
0
文件: xxEditor.cs 项目: kkdevs/sb3u
        public void ZeroWeights(int meshId, int boneId)
        {
            xxMesh  mesh          = Meshes[meshId].Mesh;
            xxBone  bone          = mesh.BoneList[boneId];
            xxFrame parentFrame   = xx.FindFrame(bone.Name, Parser.Frame).Parent;
            xxBone  parentBone    = xx.FindBone(mesh.BoneList, parentFrame.Name);
            byte    parentBoneIdx = (byte)mesh.BoneList.IndexOf(parentBone);

            foreach (xxSubmesh submesh in mesh.SubmeshList)
            {
                foreach (xxVertex vertex in submesh.VertexList)
                {
                    int parentIdx = -1;
                    for (int i = 0; i < vertex.BoneIndices.Length; i++)
                    {
                        if (vertex.BoneIndices[i] == parentBoneIdx)
                        {
                            parentIdx = i;
                            break;
                        }
                    }
                    for (int i = 0; i < vertex.BoneIndices.Length; i++)
                    {
                        if (vertex.BoneIndices[i] == boneId)
                        {
                            if (parentIdx >= 0)
                            {
                                float[] w4 = vertex.Weights4(true);
                                w4[parentIdx]     += w4[i];
                                w4[i]              = 0;
                                vertex.Weights3[0] = w4[0];
                                vertex.Weights3[1] = w4[1];
                                vertex.Weights3[2] = w4[2];
                            }
                            else
                            {
                                vertex.BoneIndices[i] = parentBoneIdx;
                            }
                            break;
                        }
                    }
                }
            }
            Changed = true;
        }
示例#11
0
文件: xxEditor.cs 项目: kkdevs/sb3u
        public void SnapBorders(object[] editors, object[] numMeshes, object[] meshes, int targetMesh, object[] targetSubmeshes, double tolerance, bool position, bool normal, bool bonesAndWeights, bool uv)
        {
            List <xxMesh>    srcMeshes   = new List <xxMesh>();
            xxMesh           mesh        = Meshes[targetMesh].Mesh;
            List <xxSubmesh> submeshList = new List <xxSubmesh>(targetSubmeshes != null ? targetSubmeshes.Length : mesh.SubmeshList.Count);

            if (editors != null && numMeshes != null && meshes != null)
            {
                srcMeshes.Capacity = meshes.Length;
                xxEditor editor    = null;
                int      editorIdx = -1;
                int      i         = 1;
                foreach (object id in meshes)
                {
                    if (--i == 0)
                    {
                        editorIdx++;
                        i      = (int)(double)numMeshes[editorIdx];
                        editor = (xxEditor)editors[editorIdx];
                    }
                    srcMeshes.Add(editor.Meshes[(int)(double)id].Mesh);
                }

                if (targetSubmeshes != null)
                {
                    foreach (object id in targetSubmeshes)
                    {
                        submeshList.Add(mesh.SubmeshList[(int)(double)id]);
                    }
                }
                else
                {
                    submeshList.AddRange(mesh.SubmeshList);
                }
                xx.SnapBorders(srcMeshes, mesh, submeshList, (float)tolerance, position, normal, bonesAndWeights, uv);
            }
            else
            {
                Report.ReportLog("Snapping inside of one mesh not implemented yet.");
                return;
            }
        }
示例#12
0
        public void HighlightBone(xxMesh xxMesh, int boneIdx, bool show)
        {
            int submeshIdx = 0;

            for (AnimationMeshContainer mesh = (AnimationMeshContainer)meshFrames[0].MeshContainer;
                 mesh != null;
                 mesh = (AnimationMeshContainer)mesh.NextMeshContainer, submeshIdx++)
            {
                if (mesh.MeshData != null && mesh.MeshData.Mesh != null)
                {
                    List <xxVertex> vertexList = xxMesh.SubmeshList[submeshIdx].VertexList;
                    FillVertexBuffer(mesh.MeshData.Mesh, vertexList, show ? boneIdx : -1);
                }
                if (mesh.BoneLines != null)
                {
                    for (int j = 0; j < BoneObjSize; j++)
                    {
                        mesh.BoneLines[boneIdx * BoneObjSize + j].Color = show ? Color.Crimson.ToArgb(): Color.CornflowerBlue.ToArgb();
                    }
                }
            }
        }
示例#13
0
文件: xaOps.cs 项目: kkdevs/sb3u
        private static void CalculateNormals(xaParser parser, xxFrame meshFrame, xaMorphKeyframe keyframe, xaMorphIndexSet set, float threshold)
        {
            xxMesh mesh = meshFrame.Mesh;

            ushort[] meshIndices     = set.MeshIndices;
            ushort[] morphIndices    = set.MorphIndices;
            int      morphSubmeshIdx = MorphMeshObjIdx(meshIndices, mesh);

            if (morphSubmeshIdx < 0)
            {
                throw new Exception("no valid mesh object was found for the morph " + set.Name);
            }
            xxSubmesh       submesh         = mesh.SubmeshList[morphSubmeshIdx];
            List <xxVertex> morphedVertices = new List <xxVertex>(submesh.VertexList.Count);

            for (ushort i = 0; i < submesh.VertexList.Count; i++)
            {
                xxVertex vert = new xxVertexUShort();
                vert.Index    = i;
                vert.Position = submesh.VertexList[i].Position;
                vert.Normal   = submesh.VertexList[i].Normal;
                morphedVertices.Add(vert);
            }
            for (int i = 0; i < meshIndices.Length; i++)
            {
                morphedVertices[meshIndices[i]].Position = keyframe.PositionList[morphIndices[i]];
            }

            var pairList = new List <Tuple <List <xxFace>, List <xxVertex> > >(1);

            pairList.Add(new Tuple <List <xxFace>, List <xxVertex> >(submesh.FaceList, morphedVertices));
            xx.CalculateNormals(pairList, threshold);

            for (int i = 0; i < meshIndices.Length; i++)
            {
                keyframe.NormalList[morphIndices[i]] = morphedVertices[meshIndices[i]].Normal;
            }
        }
示例#14
0
        public void SetTweenFactor(xxFrame meshFrame, xaMorphIndexSet idxSet, float tweenFactor)
        {
            foreach (AnimationFrame frame in meshFrames)
            {
                if (frame.Name == meshFrame.Name)
                {
                    xxMesh xxMesh     = meshFrame.Mesh;
                    int    meshObjIdx = xa.MorphMeshObjIdx(idxSet.MeshIndices, xxMesh);
                    if (meshObjIdx < 0)
                    {
                        Report.ReportLog("no valid mesh object was found for the morph");
                        return;
                    }
                    MeshContainer animMesh = frame.MeshContainer;
                    for (int i = 1; i < meshObjIdx; i++)
                    {
                        animMesh = animMesh.NextMeshContainer;
                        if (animMesh == null)
                        {
                            break;
                        }
                    }
                    if (animMesh == null)
                    {
                        Report.ReportLog("Bad submesh specified.");
                        return;
                    }
                    MorphMeshContainer morphMesh = (MorphMeshContainer)animMesh;

                    morphMesh.TweenFactor = tweenFactor;
                    return;
                }
            }
            Report.ReportLog("Mesh frame " + meshFrame + " not displayed.");
            return;
        }
示例#15
0
文件: xxReplace.cs 项目: kkdevs/sb3u
        public static xxMesh CreateMesh(WorkspaceMesh mesh, int xxFormat, out string[] materialNames, out int[] indices, out bool[] worldCoords, out bool[] replaceSubmeshesOption)
        {
            int numUncheckedSubmeshes = 0;

            foreach (ImportedSubmesh submesh in mesh.SubmeshList)
            {
                if (!mesh.isSubmeshEnabled(submesh))
                {
                    numUncheckedSubmeshes++;
                }
            }
            int numSubmeshes = mesh.SubmeshList.Count - numUncheckedSubmeshes;

            materialNames          = new string[numSubmeshes];
            indices                = new int[numSubmeshes];
            worldCoords            = new bool[numSubmeshes];
            replaceSubmeshesOption = new bool[numSubmeshes];

            xxMesh xxMesh = new xxMesh();

            xxMesh.BoneList = CreateBoneList(mesh.BoneList);

            xxMesh.SubmeshList = new List <xxSubmesh>(mesh.SubmeshList.Count);
            for (int i = 0, submeshIdx = 0; i < numSubmeshes; i++, submeshIdx++)
            {
                while (!mesh.isSubmeshEnabled(mesh.SubmeshList[submeshIdx]))
                {
                    submeshIdx++;
                }

                xxSubmesh xxSubmesh = new xxSubmesh();
                xxMesh.SubmeshList.Add(xxSubmesh);

                xxSubmesh.MaterialIndex = -1;
                materialNames[i]        = mesh.SubmeshList[submeshIdx].Material;
                indices[i]                = mesh.SubmeshList[submeshIdx].Index;
                worldCoords[i]            = mesh.SubmeshList[submeshIdx].WorldCoords;
                replaceSubmeshesOption[i] = mesh.isSubmeshReplacingOriginal(mesh.SubmeshList[submeshIdx]);

                List <ImportedVertex> vertexList   = mesh.SubmeshList[submeshIdx].VertexList;
                List <xxVertex>       xxVertexList = new List <xxVertex>(vertexList.Count);
                for (int j = 0; j < vertexList.Count; j++)
                {
                    ImportedVertex vert = vertexList[j];
                    xxVertex       xxVertex;
                    if (xxFormat >= 4)
                    {
                        xxVertex = new xxVertexUShort();
                        CreateUnknown(xxVertex);
                    }
                    else
                    {
                        xxVertex = new xxVertexInt();
                    }

                    xxVertex.Index    = j;
                    xxVertex.Normal   = vert.Normal;
                    xxVertex.UV       = (float[])vert.UV.Clone();
                    xxVertex.Weights3 = new float[3] {
                        vert.Weights[0], vert.Weights[1], vert.Weights[2]
                    };
                    xxVertex.BoneIndices = (byte[])vert.BoneIndices.Clone();
                    xxVertex.Position    = vert.Position;
                    xxVertexList.Add(xxVertex);
                }
                xxSubmesh.VertexList = xxVertexList;

                List <ImportedFace> faceList   = mesh.SubmeshList[submeshIdx].FaceList;
                List <xxFace>       xxFaceList = new List <xxFace>(faceList.Count);
                for (int j = 0; j < faceList.Count; j++)
                {
                    int[]  vertexIndices = faceList[j].VertexIndices;
                    xxFace xxFace        = new xxFace();
                    xxFace.VertexIndices = new ushort[3] {
                        (ushort)vertexIndices[0], (ushort)vertexIndices[1], (ushort)vertexIndices[2]
                    };
                    xxFaceList.Add(xxFace);
                }
                xxSubmesh.FaceList = xxFaceList;
            }

            xxMesh.VertexListDuplicate = CreateVertexListDup(xxMesh.SubmeshList);
            return(xxMesh);
        }
示例#16
0
文件: xxReplace.cs 项目: kkdevs/sb3u
        public static void ReplaceMesh(xxFrame frame, xxParser parser, WorkspaceMesh mesh, bool merge, CopyMeshMethod normalsMethod, CopyMeshMethod bonesMethod, bool targetFullMesh)
        {
            Matrix  transform      = Matrix.Identity;
            xxFrame transformFrame = frame;

            while (transformFrame != null)
            {
                transform      = transformFrame.Matrix * transform;
                transformFrame = (xxFrame)transformFrame.Parent;
            }
            transform.Invert();

            string[] materialNames;
            int[]    indices;
            bool[]   worldCoords;
            bool[]   replaceSubmeshesOption;
            xxMesh   xxMesh = CreateMesh(mesh, parser.Format, out materialNames, out indices, out worldCoords, out replaceSubmeshesOption);

            List <xxVertex> allVertices = null;

            if (frame.Mesh == null)
            {
                CreateUnknowns(xxMesh);
            }
            else
            {
                CopyUnknowns(frame.Mesh, xxMesh);

                if ((bonesMethod == CopyMeshMethod.CopyOrder) || (bonesMethod == CopyMeshMethod.CopyNear))
                {
                    xxMesh.BoneList = new List <xxBone>(frame.Mesh.BoneList.Count);
                    for (int i = 0; i < frame.Mesh.BoneList.Count; i++)
                    {
                        xxMesh.BoneList.Add(frame.Mesh.BoneList[i].Clone());
                    }
                }

                if (targetFullMesh && (normalsMethod == CopyMeshMethod.CopyNear || bonesMethod == CopyMeshMethod.CopyNear))
                {
                    allVertices = new List <xxVertex>();
                    HashSet <Vector3> posSet = new HashSet <Vector3>(new VertexPositionComparer());
                    foreach (xxSubmesh submesh in frame.Mesh.SubmeshList)
                    {
                        allVertices.Capacity = allVertices.Count + submesh.VertexList.Count;
                        foreach (xxVertex vertex in submesh.VertexList)
                        {
                            if (!posSet.Contains(vertex.Position))
                            {
                                posSet.Add(vertex.Position);
                                allVertices.Add(vertex);
                            }
                        }
                    }
                }
            }

            xxSubmesh[]      replaceSubmeshes = (frame.Mesh == null) ? null : new xxSubmesh[frame.Mesh.SubmeshList.Count];
            List <xxSubmesh> addSubmeshes     = new List <xxSubmesh>(xxMesh.SubmeshList.Count);

            for (int i = 0; i < xxMesh.SubmeshList.Count; i++)
            {
                for (int j = 0; j < parser.MaterialList.Count; j++)
                {
                    if (parser.MaterialList[j].Name == materialNames[i])
                    {
                        xxMesh.SubmeshList[i].MaterialIndex = j;
                        break;
                    }
                }

                xxSubmesh       xxSubmesh    = xxMesh.SubmeshList[i];
                List <xxVertex> xxVertexList = xxSubmesh.VertexList;
                if (worldCoords[i])
                {
                    for (int j = 0; j < xxVertexList.Count; j++)
                    {
                        xxVertexList[j].Position = Vector3.TransformCoordinate(xxVertexList[j].Position, transform);
                    }
                }

                xxSubmesh baseSubmesh = null;
                int       idx         = indices[i];
                if ((frame.Mesh != null) && (idx >= 0) && (idx < frame.Mesh.SubmeshList.Count))
                {
                    baseSubmesh = frame.Mesh.SubmeshList[idx];
                    CopyUnknowns(baseSubmesh, xxSubmesh, parser.Format, xxMesh.NumVector2PerVertex);
                }
                else
                {
                    CreateUnknowns(xxSubmesh, parser.Format, xxMesh.NumVector2PerVertex);
                }

                if (baseSubmesh != null)
                {
                    if (normalsMethod == CopyMeshMethod.CopyOrder)
                    {
                        xx.CopyNormalsOrder(baseSubmesh.VertexList, xxSubmesh.VertexList);
                    }
                    else if (normalsMethod == CopyMeshMethod.CopyNear)
                    {
                        xx.CopyNormalsNear(targetFullMesh ? allVertices : baseSubmesh.VertexList, xxSubmesh.VertexList);
                    }

                    if (bonesMethod == CopyMeshMethod.CopyOrder)
                    {
                        xx.CopyBonesOrder(baseSubmesh.VertexList, xxSubmesh.VertexList);
                    }
                    else if (bonesMethod == CopyMeshMethod.CopyNear)
                    {
                        xx.CopyBonesNear(targetFullMesh ? allVertices : baseSubmesh.VertexList, xxSubmesh.VertexList);
                    }
                }

                if ((baseSubmesh != null) && merge && replaceSubmeshesOption[i])
                {
                    replaceSubmeshes[idx] = xxSubmesh;
                }
                else
                {
                    addSubmeshes.Add(xxSubmesh);
                }
            }

            if ((frame.Mesh != null) && merge)
            {
                xxMesh.SubmeshList = new List <xxSubmesh>(replaceSubmeshes.Length + addSubmeshes.Count);
                List <xxSubmesh> copiedSubmeshes = new List <xxSubmesh>(replaceSubmeshes.Length);
                for (int i = 0; i < replaceSubmeshes.Length; i++)
                {
                    if (replaceSubmeshes[i] == null)
                    {
                        xxSubmesh xxSubmesh = frame.Mesh.SubmeshList[i].Clone();
                        copiedSubmeshes.Add(xxSubmesh);
                        xxMesh.SubmeshList.Add(xxSubmesh);
                    }
                    else
                    {
                        xxMesh.SubmeshList.Add(replaceSubmeshes[i]);
                    }
                }
                xxMesh.SubmeshList.AddRange(addSubmeshes);

                if ((frame.Mesh.BoneList.Count == 0) && (xxMesh.BoneList.Count > 0))
                {
                    for (int i = 0; i < copiedSubmeshes.Count; i++)
                    {
                        List <xxVertex> vertexList = copiedSubmeshes[i].VertexList;
                        for (int j = 0; j < vertexList.Count; j++)
                        {
                            vertexList[j].BoneIndices = new byte[4] {
                                0xFF, 0xFF, 0xFF, 0xFF
                            };
                        }
                    }
                }
                else if ((frame.Mesh.BoneList.Count > 0) && (xxMesh.BoneList.Count == 0))
                {
                    for (int i = 0; i < replaceSubmeshes.Length; i++)
                    {
                        if (replaceSubmeshes[i] != null)
                        {
                            List <xxVertex> vertexList = replaceSubmeshes[i].VertexList;
                            for (int j = 0; j < vertexList.Count; j++)
                            {
                                vertexList[j].BoneIndices = new byte[4] {
                                    0xFF, 0xFF, 0xFF, 0xFF
                                };
                            }
                        }
                    }
                    for (int i = 0; i < addSubmeshes.Count; i++)
                    {
                        List <xxVertex> vertexList = addSubmeshes[i].VertexList;
                        for (int j = 0; j < vertexList.Count; j++)
                        {
                            vertexList[j].BoneIndices = new byte[4] {
                                0xFF, 0xFF, 0xFF, 0xFF
                            };
                        }
                    }
                }
                else if ((frame.Mesh.BoneList.Count > 0) && (xxMesh.BoneList.Count > 0))
                {
                    byte[] boneIdxMap;
                    xxMesh.BoneList = MergeBoneList(frame.Mesh.BoneList, xxMesh.BoneList, out boneIdxMap);
                    for (int i = 0; i < replaceSubmeshes.Length; i++)
                    {
                        if (replaceSubmeshes[i] != null)
                        {
                            List <xxVertex> vertexList = replaceSubmeshes[i].VertexList;
                            for (int j = 0; j < vertexList.Count; j++)
                            {
                                byte[] boneIndices = vertexList[j].BoneIndices;
                                vertexList[j].BoneIndices = new byte[4];
                                for (int k = 0; k < 4; k++)
                                {
                                    vertexList[j].BoneIndices[k] = boneIndices[k] < 0xFF ? boneIdxMap[boneIndices[k]] : (byte)0xFF;
                                }
                            }
                        }
                    }
                    for (int i = 0; i < addSubmeshes.Count; i++)
                    {
                        List <xxVertex> vertexList = addSubmeshes[i].VertexList;
                        for (int j = 0; j < vertexList.Count; j++)
                        {
                            byte[] boneIndices = vertexList[j].BoneIndices;
                            vertexList[j].BoneIndices = new byte[4];
                            for (int k = 0; k < 4; k++)
                            {
                                vertexList[j].BoneIndices[k] = boneIndices[k] < 0xFF ? boneIdxMap[boneIndices[k]] : (byte)0xFF;
                            }
                        }
                    }
                }
            }

            if ((xxMesh.NumVector2PerVertex > 0) || ((frame.Mesh != null) && merge))
            {
                xxMesh.VertexListDuplicate = CreateVertexListDup(xxMesh.SubmeshList);
            }

            frame.Mesh = xxMesh;
            SetBoundingBox(frame);
        }
示例#17
0
        public float SetMorphKeyframe(xxFrame meshFrame, xaMorphIndexSet idxSet, xaMorphKeyframe keyframe, bool asStart)
        {
            foreach (AnimationFrame frame in meshFrames)
            {
                if (frame.Name == meshFrame.Name)
                {
                    xxMesh xxMesh     = meshFrame.Mesh;
                    int    meshObjIdx = xa.MorphMeshObjIdx(idxSet.MeshIndices, xxMesh);
                    if (meshObjIdx < 0)
                    {
                        Report.ReportLog("no valid mesh object was found for the morph");
                        return(-1f);
                    }
                    MorphMeshContainer     morphMesh = null;
                    AnimationMeshContainer animMesh  = frame.MeshContainer as AnimationMeshContainer;
                    if (animMesh != null)
                    {
                        for (int i = 1; i < meshObjIdx; i++)
                        {
                            animMesh = (AnimationMeshContainer)animMesh.NextMeshContainer;
                            if (animMesh == null)
                            {
                                break;
                            }
                        }
                        if (animMesh == null)
                        {
                            Report.ReportLog("Bad submesh specified.");
                            return(-1f);
                        }

                        morphMesh             = new MorphMeshContainer();
                        morphMesh.FaceCount   = xxMesh.SubmeshList[meshObjIdx].FaceList.Count;
                        morphMesh.IndexBuffer = animMesh.MeshData.Mesh.IndexBuffer;

                        morphMesh.VertexCount = xxMesh.SubmeshList[meshObjIdx].VertexList.Count;
                        List <xxVertex> vertexList = xxMesh.SubmeshList[meshObjIdx].VertexList;
                        VertexBuffer    vertBuffer = CreateMorphVertexBuffer(idxSet, keyframe, vertexList);
                        morphMesh.StartBuffer = morphMesh.EndBuffer = vertBuffer;

                        int vertBufferSize = morphMesh.VertexCount * Marshal.SizeOf(typeof(TweeningMeshesVertexBufferFormat.Stream2));
                        vertBuffer = new VertexBuffer(device, vertBufferSize, Usage.WriteOnly, VertexFormat.Texture1, Pool.Managed);
                        using (DataStream vertexStream = vertBuffer.Lock(0, vertBufferSize, LockFlags.None))
                        {
                            for (int i = 0; i < vertexList.Count; i++)
                            {
                                xxVertex vertex = vertexList[i];
                                vertexStream.Write(vertex.UV[0]);
                                vertexStream.Write(vertex.UV[1]);
                            }
                            vertBuffer.Unlock();
                        }
                        morphMesh.CommonBuffer = vertBuffer;

                        morphMesh.MaterialIndex = animMesh.MaterialIndex;
                        morphMesh.TextureIndex  = animMesh.TextureIndex;

                        morphMesh.NextMeshContainer = animMesh;
                        frame.MeshContainer         = morphMesh;

                        morphMesh.TweenFactor = 0.0f;
                    }
                    else
                    {
                        morphMesh = frame.MeshContainer as MorphMeshContainer;
                        List <xxVertex> vertexList = xxMesh.SubmeshList[meshObjIdx].VertexList;
                        VertexBuffer    vertBuffer = CreateMorphVertexBuffer(idxSet, keyframe, vertexList);
                        if (asStart)
                        {
                            if (morphMesh.StartBuffer != morphMesh.EndBuffer)
                            {
                                morphMesh.StartBuffer.Dispose();
                            }
                            morphMesh.StartBuffer = vertBuffer;
                            morphMesh.TweenFactor = 0.0f;
                        }
                        else
                        {
                            if (morphMesh.StartBuffer != morphMesh.EndBuffer)
                            {
                                morphMesh.EndBuffer.Dispose();
                            }
                            morphMesh.EndBuffer   = vertBuffer;
                            morphMesh.TweenFactor = 1.0f;
                        }
                    }
                    return(morphMesh.TweenFactor);
                }
            }
            Report.ReportLog("Mesh frame " + meshFrame + " not displayed.");
            return(-1f);
        }
示例#18
0
        public float UnsetMorphKeyframe(xxFrame meshFrame, xaMorphIndexSet idxSet, bool asStart)
        {
            foreach (AnimationFrame frame in meshFrames)
            {
                if (frame.Name == meshFrame.Name)
                {
                    xxMesh xxMesh     = meshFrame.Mesh;
                    int    meshObjIdx = xa.MorphMeshObjIdx(idxSet.MeshIndices, xxMesh);
                    if (meshObjIdx < 0)
                    {
                        Report.ReportLog("no valid mesh object was found for the morph");
                        return(-1f);
                    }
                    MeshContainer animMesh = frame.MeshContainer;
                    for (int i = 1; i < meshObjIdx; i++)
                    {
                        animMesh = animMesh.NextMeshContainer;
                        if (animMesh == null)
                        {
                            break;
                        }
                    }
                    if (animMesh == null)
                    {
                        Report.ReportLog("Bad submesh specified.");
                        return(-1f);
                    }
                    MorphMeshContainer morphMesh = (MorphMeshContainer)animMesh;

                    if (asStart)
                    {
                        if (morphMesh.StartBuffer != morphMesh.EndBuffer)
                        {
                            morphMesh.StartBuffer.Dispose();
                            morphMesh.StartBuffer = morphMesh.EndBuffer;
                        }
                        else
                        {
                            frame.MeshContainer = morphMesh.NextMeshContainer;
                        }
                        morphMesh.TweenFactor = 1.0f;
                    }
                    else
                    {
                        if (morphMesh.StartBuffer != morphMesh.EndBuffer)
                        {
                            morphMesh.EndBuffer.Dispose();
                            morphMesh.EndBuffer = morphMesh.StartBuffer;
                        }
                        else
                        {
                            frame.MeshContainer = morphMesh.NextMeshContainer;
                        }
                        morphMesh.TweenFactor = 0.0f;
                    }
                    return(morphMesh.TweenFactor);
                }
            }
            Report.ReportLog("Mesh frame " + meshFrame + " not displayed.");
            return(-1f);
        }
示例#19
0
 public static void CopyUnknowns(xxMesh src, xxMesh dest)
 {
     dest.NumVector2PerVertex        = src.NumVector2PerVertex;
     dest.VertexListDuplicateUnknown = (byte[])src.VertexListDuplicateUnknown.Clone();
 }
示例#20
0
        private AnimationFrame CreateFrame(xxFrame frame, xxParser parser, HashSet <string> extractFrames, HashSet <string> meshNames, Device device, Matrix combinedParent, List <AnimationFrame> meshFrames)
        {
            AnimationFrame animationFrame = new AnimationFrame();

            animationFrame.Name = frame.Name;
            animationFrame.TransformationMatrix = frame.Matrix;
            animationFrame.OriginalTransform    = animationFrame.TransformationMatrix;
            animationFrame.CombinedTransform    = combinedParent * animationFrame.TransformationMatrix;

            xxMesh mesh = frame.Mesh;

            if (meshNames.Contains(frame.Name) && (mesh != null))
            {
                List <xxBone> boneList = mesh.BoneList;

                string[] boneNames   = new string[boneList.Count];
                Matrix[] boneOffsets = new Matrix[boneList.Count];
                for (int i = 0; i < boneList.Count; i++)
                {
                    xxBone bone = boneList[i];
                    boneNames[i]   = bone.Name;
                    boneOffsets[i] = bone.Matrix;
                }

                AnimationMeshContainer[] meshContainers = new AnimationMeshContainer[mesh.SubmeshList.Count];
                Vector3 min = new Vector3(Single.MaxValue);
                Vector3 max = new Vector3(Single.MinValue);
                for (int i = 0; i < mesh.SubmeshList.Count; i++)
                {
                    xxSubmesh       submesh    = mesh.SubmeshList[i];
                    List <xxFace>   faceList   = submesh.FaceList;
                    List <xxVertex> vertexList = submesh.VertexList;

                    Mesh animationMesh = new Mesh(device, faceList.Count, vertexList.Count, MeshFlags.Managed, PositionBlendWeightsIndexedNormalTexturedColoured.Format);

                    using (DataStream indexStream = animationMesh.LockIndexBuffer(LockFlags.None))
                    {
                        for (int j = 0; j < faceList.Count; j++)
                        {
                            ushort[] indices = faceList[j].VertexIndices;
                            indexStream.Write(indices[0]);
                            indexStream.Write(indices[2]);
                            indexStream.Write(indices[1]);
                        }
                        animationMesh.UnlockIndexBuffer();
                    }

                    FillVertexBuffer(animationMesh, vertexList, -1);

                    var normalLines = new PositionBlendWeightsIndexedColored[vertexList.Count * 2];
                    for (int j = 0; j < vertexList.Count; j++)
                    {
                        xxVertex vertex = vertexList[j];

                        normalLines[j * 2]       = new PositionBlendWeightsIndexedColored(vertex.Position, vertex.Weights3, vertex.BoneIndices, Color.Yellow.ToArgb());
                        normalLines[(j * 2) + 1] = new PositionBlendWeightsIndexedColored(vertex.Position + (vertex.Normal / 16), vertex.Weights3, vertex.BoneIndices, Color.Yellow.ToArgb());

                        min = Vector3.Minimize(min, vertex.Position);
                        max = Vector3.Maximize(max, vertex.Position);
                    }

                    AnimationMeshContainer meshContainer = new AnimationMeshContainer();
                    meshContainer.Name        = animationFrame.Name;
                    meshContainer.MeshData    = new MeshData(animationMesh);
                    meshContainer.NormalLines = normalLines;
                    meshContainers[i]         = meshContainer;

                    int matIdx = submesh.MaterialIndex;
                    if ((matIdx >= 0) && (matIdx < parser.MaterialList.Count))
                    {
                        int texIdx;
                        if (!MatTexIndices.TryGetValue(matIdx, out texIdx))
                        {
                            texIdx = -1;

                            xxMaterial mat         = parser.MaterialList[matIdx];
                            Material   materialD3D = new Material();
                            materialD3D.Ambient  = mat.Ambient;
                            materialD3D.Diffuse  = mat.Diffuse;
                            materialD3D.Emissive = mat.Emissive;
                            materialD3D.Specular = mat.Specular;
                            materialD3D.Power    = mat.Power;
                            Materials[matIdx]    = materialD3D;

                            xxMaterialTexture matTex     = mat.Textures[0];
                            string            matTexName = matTex.Name;
                            if (matTexName != String.Empty)
                            {
                                for (int j = 0; j < parser.TextureList.Count; j++)
                                {
                                    xxTexture tex = parser.TextureList[j];
                                    if (tex.Name == matTexName)
                                    {
                                        texIdx = j;
                                        if (Textures[j] == null)
                                        {
                                            ImportedTexture importedTex = xx.ImportedTexture(tex);
                                            Textures[j] = Texture.FromMemory(device, importedTex.Data);
                                        }
                                        break;
                                    }
                                }
                            }

                            MatTexIndices.Add(matIdx, texIdx);
                        }

                        meshContainer.MaterialIndex = matIdx;
                        meshContainer.TextureIndex  = texIdx;
                    }
                }

                for (int i = 0; i < (meshContainers.Length - 1); i++)
                {
                    meshContainers[i].NextMeshContainer = meshContainers[i + 1];
                }
                for (int i = 0; i < meshContainers.Length; i++)
                {
                    meshContainers[i].BoneNames   = boneNames;
                    meshContainers[i].BoneOffsets = boneOffsets;
                }

                min = Vector3.TransformCoordinate(min, animationFrame.CombinedTransform);
                max = Vector3.TransformCoordinate(max, animationFrame.CombinedTransform);
                animationFrame.Bounds        = new BoundingBox(min, max);
                animationFrame.MeshContainer = meshContainers[0];
                meshFrames.Add(animationFrame);
            }

            for (int i = 0; i < frame.Count; i++)
            {
                xxFrame child = frame[i];
                if (extractFrames.Contains(child.Name))
                {
                    AnimationFrame childAnimationFrame = CreateFrame(child, parser, extractFrames, meshNames, device, animationFrame.CombinedTransform, meshFrames);
                    childAnimationFrame.Parent = animationFrame;
                    animationFrame.AppendChild(childAnimationFrame);
                }
            }

            numFrames++;
            return(animationFrame);
        }
示例#21
0
 public static bool IsSkinned(xxMesh mesh)
 {
     return(mesh.BoneList.Count > 0);
 }
示例#22
0
            private static List <xxTexture> Export(string dest, xxParser parser, List <xxFrame> meshParents, bool worldCoords)
            {
                List <xxTexture> usedTextures = new List <xxTexture>(parser.TextureList.Count);
                DirectoryInfo    dir          = new DirectoryInfo(Path.GetDirectoryName(dest));

                if (!dir.Exists)
                {
                    dir.Create();
                }

                List <int> materialList = new List <int>(parser.MaterialList.Count);

                using (StreamWriter writer = new StreamWriter(dest, false))
                {
                    for (int i = 0; i < meshParents.Count; i++)
                    {
                        xxMesh meshListSome = meshParents[i].Mesh;
                        for (int j = 0; j < meshListSome.SubmeshList.Count; j++)
                        {
                            xxSubmesh meshObj       = meshListSome.SubmeshList[j];
                            int       meshObjMatIdx = meshObj.MaterialIndex;
                            if ((meshObjMatIdx >= 0) && (meshObjMatIdx < parser.MaterialList.Count))
                            {
                                if (!materialList.Contains(meshObjMatIdx))
                                {
                                    materialList.Add(meshObjMatIdx);
                                }
                            }
                            else
                            {
                                Report.ReportLog("Warning: Mesh " + meshParents[i].Name + " Object " + j + " has an invalid material");
                            }
                        }
                    }

                    writer.WriteLine("Metasequoia Document");
                    writer.WriteLine("Format Text Ver 1.0");
                    writer.WriteLine();
                    writer.WriteLine("Material " + materialList.Count + " {");
                    foreach (int matIdx in materialList)
                    {
                        xxMaterial mat        = parser.MaterialList[matIdx];
                        string     s          = "\t\"" + mat.Name + "\" col(0.800 0.800 0.800 1.000) dif(0.500) amb(0.100) emi(0.500) spc(0.100) power(30.00)";
                        string     matTexName = mat.Textures[0].Name;
                        if (matTexName != String.Empty)
                        {
                            s += " tex(\"" + Path.GetFileName(matTexName) + "\")";
                        }
                        writer.WriteLine(s);
                    }
                    writer.WriteLine("}");

                    Random rand = new Random();
                    for (int i = 0; i < meshParents.Count; i++)
                    {
                        Matrix transform = Matrix.Identity;
                        if (worldCoords)
                        {
                            xxFrame parent = meshParents[i];
                            while (parent != null)
                            {
                                transform = parent.Matrix * transform;
                                parent    = (xxFrame)parent.Parent;
                            }
                        }

                        string meshName     = meshParents[i].Name;
                        xxMesh meshListSome = meshParents[i].Mesh;
                        for (int j = 0; j < meshListSome.SubmeshList.Count; j++)
                        {
                            xxSubmesh meshObj       = meshListSome.SubmeshList[j];
                            int       meshObjMatIdx = meshObj.MaterialIndex;
                            int       mqoMatIdx     = -1;
                            if ((meshObjMatIdx >= 0) && (meshObjMatIdx < parser.MaterialList.Count))
                            {
                                mqoMatIdx = materialList.IndexOf(meshObjMatIdx);
                            }
                            float[] color = new float[3];
                            for (int k = 0; k < color.Length; k++)
                            {
                                color[k] = (float)((rand.NextDouble() / 2) + 0.5);
                            }

                            string mqoName = meshName + "[" + j + "]";
                            if (worldCoords)
                            {
                                mqoName += "[W]";
                            }
                            writer.WriteLine("Object \"" + mqoName + "\" {");
                            writer.WriteLine("\tshading 1");
                            writer.WriteLine("\tcolor " + color[0].ToFloatString() + " " + color[1].ToFloatString() + " " + color[2].ToFloatString());
                            writer.WriteLine("\tcolor_type 1");

                            List <ImportedVertex> vertList = xx.ImportedVertexList(meshObj.VertexList, xx.IsSkinned(meshListSome));
                            List <ImportedFace>   faceList = xx.ImportedFaceList(meshObj.FaceList);
                            if (worldCoords)
                            {
                                for (int k = 0; k < vertList.Count; k++)
                                {
                                    vertList[k].Position = Vector3.TransformCoordinate(vertList[k].Position, transform);
                                }
                            }

                            ExporterCommon.WriteMeshObject(writer, vertList, faceList, mqoMatIdx, null);
                            writer.WriteLine("}");
                        }
                    }
                    writer.WriteLine("Eof");
                }

                foreach (int matIdx in materialList)
                {
                    xxMaterial        mat        = parser.MaterialList[matIdx];
                    xxMaterialTexture matTex     = mat.Textures[0];
                    string            matTexName = matTex.Name;
                    if (matTexName != String.Empty)
                    {
                        for (int i = 0; i < parser.TextureList.Count; i++)
                        {
                            xxTexture tex     = parser.TextureList[i];
                            string    texName = tex.Name;
                            if ((texName == matTexName) && !usedTextures.Contains(tex))
                            {
                                usedTextures.Add(tex);
                                break;
                            }
                        }
                    }
                }
                return(usedTextures);
            }
示例#23
0
        protected xxFrame ParseFrame()
        {
            xxFrame frame = new xxFrame();

            frame.Name = reader.ReadName();

            int numChildFrames = reader.ReadInt32();

            frame.InitChildren(numChildFrames);

            frame.Matrix   = reader.ReadMatrix();
            frame.Unknown1 = (Format >= 7) ? reader.ReadBytes(32) : reader.ReadBytes(16);

            int numSubmeshes = reader.ReadInt32();

            frame.Bounds   = new BoundingBox(reader.ReadVector3(), reader.ReadVector3());
            frame.Unknown2 = (Format >= 7) ? reader.ReadBytes(64) : reader.ReadBytes(16);

            if (Format >= 6)
            {
                frame.Name2 = reader.ReadName();
            }

            if (numSubmeshes > 0)
            {
                xxMesh mesh = new xxMesh();
                frame.Mesh = mesh;
                mesh.NumVector2PerVertex = reader.ReadByte();

                mesh.SubmeshList = new List <xxSubmesh>(numSubmeshes);
                for (int i = 0; i < numSubmeshes; i++)
                {
                    xxSubmesh submesh = new xxSubmesh();
                    mesh.SubmeshList.Add(submesh);

                    submesh.Unknown1      = (Format >= 7) ? reader.ReadBytes(64) : reader.ReadBytes(16);
                    submesh.MaterialIndex = reader.ReadInt32();

                    submesh.FaceList   = ParseFaceList();
                    submesh.VertexList = ParseVertexList();

                    if (Format >= 7)
                    {
                        submesh.Unknown2 = reader.ReadBytes(20);
                    }

                    if (mesh.NumVector2PerVertex > 0)
                    {
                        submesh.Vector2Lists = new List <List <Vector2> >(submesh.VertexList.Count);
                        for (int j = 0; j < submesh.VertexList.Count; j++)
                        {
                            List <Vector2> vectorList = new List <Vector2>(mesh.NumVector2PerVertex);
                            submesh.Vector2Lists.Add(vectorList);
                            for (byte k = 0; k < mesh.NumVector2PerVertex; k++)
                            {
                                vectorList.Add(reader.ReadVector2());
                            }
                        }
                    }

                    if (Format >= 2)
                    {
                        submesh.Unknown3 = reader.ReadBytes(100);                         // 96 + 4
                    }

                    if (Format >= 7)
                    {
                        submesh.Unknown4 = reader.ReadBytes(284);                         // 256 + 28

                        if (Format >= 8)
                        {
                            byte   format    = reader.ReadByte();
                            string nullFrame = reader.ReadName();
                            byte[] u5end     = reader.ReadBytes(12 + 4);

                            byte[] encryptedName = Utility.EncryptName(nullFrame);
                            submesh.Unknown5    = new byte[1 + 4 + encryptedName.Length + 12 + 4];
                            submesh.Unknown5[0] = format;
                            BitConverter.GetBytes(encryptedName.Length).CopyTo(submesh.Unknown5, 1);
                            encryptedName.CopyTo(submesh.Unknown5, 1 + 4);
                            u5end.CopyTo(submesh.Unknown5, 1 + 4 + encryptedName.Length);
                        }
                    }
                    else
                    {
                        if (Format >= 3)
                        {
                            submesh.Unknown4 = reader.ReadBytes(64);
                        }
                        if (Format >= 5)
                        {
                            submesh.Unknown5 = reader.ReadBytes(20);
                        }
                        if (Format >= 6)
                        {
                            submesh.Unknown6 = reader.ReadBytes(28);
                        }
                    }
                }

                ushort numVerticesDup = reader.ReadUInt16();
                mesh.VertexListDuplicate        = new List <xxVertex>(numVerticesDup);
                mesh.VertexListDuplicateUnknown = reader.ReadBytes(8);                  // 4 + 4
                for (int i = 0; i < numVerticesDup; i++)
                {
                    mesh.VertexListDuplicate.Add(ParseVertex());
                }

                mesh.BoneList = ParseBoneList();
            }

            for (int i = 0; i < numChildFrames; i++)
            {
                frame.AddChild(ParseFrame());
            }

            return(frame);
        }