Exemple #1
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);
                }
            }
Exemple #2
0
        public void SetMorphClipName(int position, string newName)
        {
            string          oldName = Parser.MorphSection.ClipList[position].Name;
            xaMorphIndexSet set     = xa.FindMorphIndexSet(oldName, Parser.MorphSection);

            set.Name = newName;
            Parser.MorphSection.ClipList[position].Name = newName;
            Changed = true;
        }
Exemple #3
0
        public static void CalculateNormals(xaParser parser, xxFrame meshFrame, string morphClip, string keyframe, float threshold)
        {
            HashSet <Tuple <xaMorphClip, xaMorphKeyframe> > keyframes = new HashSet <Tuple <xaMorphClip, xaMorphKeyframe> >();

            foreach (xaMorphClip clip in parser.MorphSection.ClipList)
            {
                if (morphClip != null && clip.Name != morphClip)
                {
                    continue;
                }

                if (keyframe != null)
                {
                    xaMorphKeyframe xaKeyframe = FindMorphKeyFrame(keyframe, parser.MorphSection);
                    if (xaKeyframe == null)
                    {
                        throw new Exception("keyframe " + keyframe + " not found in morph clip " + morphClip);
                    }
                    keyframes.Add(new Tuple <xaMorphClip, xaMorphKeyframe>(clip, xaKeyframe));
                    break;
                }
                else
                {
                    foreach (xaMorphKeyframeRef morphRef in clip.KeyframeRefList)
                    {
                        xaMorphKeyframe xaKeyframe = FindMorphKeyFrame(morphRef.Name, parser.MorphSection);
                        keyframes.Add(new Tuple <xaMorphClip, xaMorphKeyframe>(clip, xaKeyframe));
                    }
                }
            }
            if (keyframes.Count == 0)
            {
                Report.ReportLog("No keyframe for mesh " + meshFrame.Name + " to calculate normals for found.");
                return;
            }

            foreach (var tup in keyframes)
            {
                xaMorphIndexSet set = FindMorphIndexSet(tup.Item1.Name, parser.MorphSection);
                CalculateNormals(parser, meshFrame, tup.Item2, set, threshold);
            }
        }
Exemple #4
0
        private VertexBuffer CreateMorphVertexBuffer(xaMorphIndexSet idxSet, xaMorphKeyframe keyframe, List <xxVertex> vertexList)
        {
            int          vertBufferSize = keyframe.PositionList.Count * Marshal.SizeOf(typeof(TweeningMeshesVertexBufferFormat.Stream0));
            VertexBuffer vertBuffer     = new VertexBuffer(device, vertBufferSize, Usage.WriteOnly, VertexFormat.Position | VertexFormat.Normal, Pool.Managed);

            Vector3[] positions = new Vector3[vertexList.Count];
            Vector3[] normals   = new Vector3[vertexList.Count];
            for (int i = 0; i < positions.Length; i++)
            {
                positions[i] = vertexList[i].Position;
                normals[i]   = vertexList[i].Normal;
            }
            ushort[]       meshIndices       = idxSet.MeshIndices;
            ushort[]       morphIndices      = idxSet.MorphIndices;
            List <Vector3> keyframePositions = keyframe.PositionList;
            List <Vector3> keyframeNormals   = keyframe.NormalList;

            for (int i = 0; i < meshIndices.Length; i++)
            {
                positions[meshIndices[i]] = keyframePositions[morphIndices[i]];
                normals[meshIndices[i]]   = keyframeNormals[morphIndices[i]];
            }

            using (DataStream vertexStream = vertBuffer.Lock(0, vertBufferSize, LockFlags.None))
            {
                for (int i = 0; i < positions.Length; i++)
                {
                    Vector3 pos = positions[i];
                    vertexStream.Write(pos.X);
                    vertexStream.Write(pos.Y);
                    vertexStream.Write(pos.Z);
                    Vector3 normal = normals[i];
                    vertexStream.Write(normal.X);
                    vertexStream.Write(normal.Y);
                    vertexStream.Write(normal.Z);
                }
                vertBuffer.Unlock();
            }

            return(vertBuffer);
        }
Exemple #5
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;
        }
Exemple #6
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);
        }
Exemple #7
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);
        }
Exemple #8
0
        protected xaMorphSection ParseMorphSection()
        {
            if (reader.ReadByte() == 0)
            {
                return(null);
            }

            xaMorphSection section = new xaMorphSection();

            int numIndexSets = reader.ReadInt32();

            section.IndexSetList = new List <xaMorphIndexSet>(numIndexSets);
            for (int i = 0; i < numIndexSets; i++)
            {
                xaMorphIndexSet indexSet = new xaMorphIndexSet();
                section.IndexSetList.Add(indexSet);

                indexSet.Unknown1 = reader.ReadBytes(1);

                int numVertices = reader.ReadInt32();
                indexSet.MeshIndices  = reader.ReadUInt16Array(numVertices);
                indexSet.MorphIndices = reader.ReadUInt16Array(numVertices);

                indexSet.Name = reader.ReadName();
            }

            int numKeyframes = reader.ReadInt32();

            section.KeyframeList = new List <xaMorphKeyframe>(numKeyframes);
            for (int i = 0; i < numKeyframes; i++)
            {
                xaMorphKeyframe keyframe = new xaMorphKeyframe();
                section.KeyframeList.Add(keyframe);

                int numVertices = reader.ReadInt32();
                keyframe.PositionList = new List <Vector3>(numVertices);
                keyframe.NormalList   = new List <Vector3>(numVertices);
                for (int j = 0; j < numVertices; j++)
                {
                    keyframe.PositionList.Add(reader.ReadVector3());
                }
                for (int j = 0; j < numVertices; j++)
                {
                    keyframe.NormalList.Add(reader.ReadVector3());
                }

                keyframe.Name = reader.ReadName();
            }

            int numClips = reader.ReadInt32();

            section.ClipList = new List <xaMorphClip>(numClips);
            for (int i = 0; i < numClips; i++)
            {
                xaMorphClip clip = new xaMorphClip();
                section.ClipList.Add(clip);

                clip.MeshName = reader.ReadName();
                clip.Name     = reader.ReadName();

                int numKeyframeRefs = reader.ReadInt32();
                clip.KeyframeRefList = new List <xaMorphKeyframeRef>(numKeyframeRefs);
                for (int j = 0; j < numKeyframeRefs; j++)
                {
                    xaMorphKeyframeRef keyframeRef = new xaMorphKeyframeRef();
                    clip.KeyframeRefList.Add(keyframeRef);

                    keyframeRef.Unknown1 = reader.ReadBytes(1);
                    keyframeRef.Index    = reader.ReadInt32();
                    keyframeRef.Unknown2 = reader.ReadBytes(1);
                    keyframeRef.Name     = reader.ReadName();
                }

                clip.Unknown1 = reader.ReadBytes(4);
            }

            return(section);
        }
Exemple #9
0
        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;
            }
        }
Exemple #10
0
        public static void ReplaceMorph(string destMorphName, xaParser parser, WorkspaceMorph wsMorphList, string newMorphName, bool replaceMorphMask, bool replaceNormals, float minSquaredDistance, bool minKeyframes)
        {
            if (parser.MorphSection == null)
            {
                Report.ReportLog("The .xa file doesn't have a morph section. Skipping these morphs");
                return;
            }

            xaMorphSection  morphSection = parser.MorphSection;
            xaMorphIndexSet indices      = FindMorphIndexSet(destMorphName, morphSection);

            if (indices == null)
            {
                Report.ReportLog("Couldn't find morph clip " + destMorphName + ". Skipping these morphs");
                return;
            }
            if (replaceMorphMask && wsMorphList.MorphedVertexIndices != null)
            {
                int             index      = morphSection.IndexSetList.IndexOf(indices);
                xaMorphIndexSet newIndices = new xaMorphIndexSet();
                newIndices.Name = indices.Name;
                int numMorphedVertices = wsMorphList.MorphedVertexIndices.Count;
                newIndices.MeshIndices = new ushort[numMorphedVertices];
                wsMorphList.MorphedVertexIndices.CopyTo(newIndices.MeshIndices);
                newIndices.MorphIndices = new ushort[numMorphedVertices];
                if (minKeyframes)
                {
                    for (ushort i = 0; i < numMorphedVertices; i++)
                    {
                        newIndices.MorphIndices[i] = i;
                    }
                }
                else
                {
                    wsMorphList.MorphedVertexIndices.CopyTo(newIndices.MorphIndices);
                }
                newIndices.Unknown1 = indices.Unknown1;
                morphSection.IndexSetList.RemoveAt(index);
                morphSection.IndexSetList.Insert(index, newIndices);
                indices = newIndices;
            }

            Report.ReportLog("Replacing morphs ...");
            try
            {
                ushort[] meshIndices  = indices.MeshIndices;
                ushort[] morphIndices = indices.MorphIndices;
                foreach (ImportedMorphKeyframe wsMorph in wsMorphList.KeyframeList)
                {
                    if (!wsMorphList.isMorphKeyframeEnabled(wsMorph))
                    {
                        continue;
                    }

                    List <ImportedVertex> vertList = wsMorph.VertexList;
                    xaMorphKeyframe       keyframe = FindMorphKeyFrame(wsMorph.Name, morphSection);
                    if (keyframe == null)
                    {
                        Report.ReportLog("Adding new Keyframe " + wsMorph.Name);
                        keyframe      = new xaMorphKeyframe();
                        keyframe.Name = wsMorph.Name;
                        int numVertices = minKeyframes ? meshIndices.Length : wsMorph.VertexList.Count;
                        keyframe.PositionList = new List <Vector3>(new Vector3[numVertices]);
                        keyframe.NormalList   = new List <Vector3>(new Vector3[numVertices]);
                        for (int i = 0; i < meshIndices.Length; i++)
                        {
                            keyframe.PositionList[morphIndices[i]] = vertList[meshIndices[i]].Position;
                            keyframe.NormalList[morphIndices[i]]   = vertList[meshIndices[i]].Normal;
                        }
                        morphSection.KeyframeList.Add(keyframe);
                    }
                    else
                    {
                        if (!minKeyframes && keyframe.PositionList.Count != vertList.Count ||
                            minKeyframes && keyframe.PositionList.Count != meshIndices.Length)
                        {
                            Report.ReportLog("Adapting Keyframe " + wsMorph.Name + " to new length.");
                            int       length       = minKeyframes ? meshIndices.Length : vertList.Count;
                            Vector3[] newPositions = new Vector3[length];
                            Vector3[] newNormals   = new Vector3[length];
                            if (!minKeyframes)
                            {
                                for (int i = 0; i < vertList.Count; i++)
                                {
                                    newPositions[i] = vertList[i].Position;
                                    newNormals[i]   = vertList[i].Normal;
                                }
                            }
                            for (int i = 0; i < meshIndices.Length; i++)
                            {
                                newPositions[morphIndices[i]] = vertList[meshIndices[i]].Position;
                                newNormals[morphIndices[i]]   = vertList[meshIndices[i]].Normal;
                            }
                            keyframe.PositionList.Clear();
                            keyframe.NormalList.Clear();
                            keyframe.PositionList.AddRange(newPositions);
                            keyframe.NormalList.AddRange(newNormals);
                        }
                        else
                        {
                            Report.ReportLog("Replacing Keyframe " + wsMorph.Name);
                            for (int i = 0; i < meshIndices.Length; i++)
                            {
                                Vector3 orgPos = new Vector3(keyframe.PositionList[morphIndices[i]].X, keyframe.PositionList[morphIndices[i]].Y, keyframe.PositionList[morphIndices[i]].Z),
                                        newPos = new Vector3(vertList[meshIndices[i]].Position.X, vertList[meshIndices[i]].Position.Y, vertList[meshIndices[i]].Position.Z);
                                if ((orgPos - newPos).LengthSquared() >= minSquaredDistance)
                                {
                                    keyframe.PositionList[morphIndices[i]] = vertList[meshIndices[i]].Position;
                                    if (replaceNormals)
                                    {
                                        keyframe.NormalList[morphIndices[i]] = vertList[meshIndices[i]].Normal;
                                    }
                                }
                            }
                        }
                    }

                    string morphNewName = wsMorphList.getMorphKeyframeNewName(wsMorph);
                    if (morphNewName != String.Empty)
                    {
                        for (int i = 0; i < morphSection.ClipList.Count; i++)
                        {
                            xaMorphClip clip = morphSection.ClipList[i];
                            for (int j = 0; j < clip.KeyframeRefList.Count; j++)
                            {
                                xaMorphKeyframeRef keyframeRef = clip.KeyframeRefList[j];
                                if (keyframeRef.Name == wsMorph.Name)
                                {
                                    keyframeRef.Name = morphNewName;
                                }
                            }
                        }
                        keyframe.Name = morphNewName;
                    }
                }
                if (newMorphName != String.Empty)
                {
                    for (int i = 0; i < morphSection.ClipList.Count; i++)
                    {
                        xaMorphClip clip = morphSection.ClipList[i];
                        if (clip.Name == destMorphName)
                        {
                            clip.Name = newMorphName;
                            break;
                        }
                    }
                    indices.Name = newMorphName;
                }
            }
            catch (Exception ex)
            {
                Report.ReportLog("Error replacing morphs: " + ex.Message);
            }
        }
Exemple #11
0
        public static void ReplaceMorph(string destMorphName, xaParser parser, WorkspaceMorph wsMorphList, string newMorphName, bool replaceNormals, float minSquaredDistance)
        {
            if (parser.MorphSection == null)
            {
                Report.ReportLog("The .xa file doesn't have a morph section. Skipping these morphs");
                return;
            }

            xaMorphSection  morphSection = parser.MorphSection;
            xaMorphIndexSet indices      = FindMorphIndexSet(destMorphName, morphSection);

            if (indices == null)
            {
                Report.ReportLog("Couldn't find morph clip " + destMorphName + ". Skipping these morphs");
                return;
            }

            Report.ReportLog("Replacing morphs ...");
            try
            {
                ushort[] meshIndices  = indices.MeshIndices;
                ushort[] morphIndices = indices.MorphIndices;
                foreach (ImportedMorphKeyframe wsMorph in wsMorphList.KeyframeList)
                {
                    if (!wsMorphList.isMorphKeyframeEnabled(wsMorph))
                    {
                        continue;
                    }

                    List <ImportedVertex> vertList = wsMorph.VertexList;
                    xaMorphKeyframe       keyframe = FindMorphKeyFrame(wsMorph.Name, morphSection);
                    if (keyframe == null)
                    {
                        keyframe              = new xaMorphKeyframe();
                        keyframe.Name         = wsMorph.Name;
                        keyframe.PositionList = new List <Vector3>(new Vector3[wsMorph.VertexList.Count]);
                        keyframe.NormalList   = new List <Vector3>(new Vector3[wsMorph.VertexList.Count]);
                        for (int i = 0; i < meshIndices.Length; i++)
                        {
                            keyframe.PositionList[morphIndices[i]] = vertList[meshIndices[i]].Position;
                            keyframe.NormalList[morphIndices[i]]   = vertList[meshIndices[i]].Normal;
                        }
                        morphSection.KeyframeList.Add(keyframe);
                    }
                    else
                    {
                        for (int i = 0; i < meshIndices.Length; i++)
                        {
                            Vector3 orgPos = new Vector3(keyframe.PositionList[morphIndices[i]].X, keyframe.PositionList[morphIndices[i]].Y, keyframe.PositionList[morphIndices[i]].Z),
                                    newPos = new Vector3(vertList[meshIndices[i]].Position.X, vertList[meshIndices[i]].Position.Y, vertList[meshIndices[i]].Position.Z);
                            if ((orgPos - newPos).LengthSquared() >= minSquaredDistance)
                            {
                                keyframe.PositionList[morphIndices[i]] = vertList[meshIndices[i]].Position;
                                if (replaceNormals)
                                {
                                    keyframe.NormalList[morphIndices[i]] = vertList[meshIndices[i]].Normal;
                                }
                            }
                        }
                    }

                    string morphNewName = wsMorphList.getMorphKeyframeNewName(wsMorph);
                    if (morphNewName != String.Empty)
                    {
                        for (int i = 0; i < morphSection.ClipList.Count; i++)
                        {
                            xaMorphClip clip = morphSection.ClipList[i];
                            for (int j = 0; j < clip.KeyframeRefList.Count; j++)
                            {
                                xaMorphKeyframeRef keyframeRef = clip.KeyframeRefList[j];
                                if (keyframeRef.Name == wsMorph.Name)
                                {
                                    keyframeRef.Name = morphNewName;
                                }
                            }
                        }
                        keyframe.Name = morphNewName;
                    }
                }
                if (newMorphName != String.Empty)
                {
                    for (int i = 0; i < morphSection.ClipList.Count; i++)
                    {
                        xaMorphClip clip = morphSection.ClipList[i];
                        if (clip.Name == destMorphName)
                        {
                            clip.Name = newMorphName;
                            break;
                        }
                    }
                    indices.Name = newMorphName;
                }
            }
            catch (Exception ex)
            {
                Report.ReportLog("Error replacing morphs: " + ex.Message);
            }
        }