コード例 #1
0
        public virtual Matrix3D Rotate(Axis axis, double deltaAngle, bool isFromSaved)
        {
            Quaternion3D rotationQ = Quaternion3D.Identity;

            switch (axis)
            {
            case Axis.X:
                rotationQ *= Quaternion3D.CreateFromAxisAngle(_unitX, deltaAngle);
                break;

            case Axis.Y:
                rotationQ *= Quaternion3D.CreateFromAxisAngle(_unitY, deltaAngle);
                break;

            case Axis.Z:
                rotationQ *= Quaternion3D.CreateFromAxisAngle(_unitZ, deltaAngle);
                break;
            }
            Matrix3D matrix = Ext3D.CreateFromQuaternion(rotationQ);

            if (isFromSaved)
            {
                _transform = matrix * _savedTransform;
            }
            else
            {
                _transform = matrix * _transform;
            }

            return(matrix);
        }
コード例 #2
0
        public override void DoTransform(double deltaAngle)
        {
            //  Debug.WriteLine("start DoTransform");
            foreach (CubicleFace face in AffectedFaces)
            {
                Cubie     cubie     = face.CubieFace.Cubie;
                CubieFace cubieFace = face.CubieFace;
                //cubicle.Cubie.Rotate(BasicOp.Axis, deltaAngle, false);
                Vector3D axis = face.CubieFace.Cubie.UnitX;

                if (Axis == Axis.X)
                {
                    axis = face.CubieFace.Cubie.UnitX;
                }
                else if (Axis == Axis.Y)
                {
                    axis = face.CubieFace.Cubie.UnitY;
                }
                else if (Axis == Axis.Z)
                {
                    axis = face.CubieFace.Cubie.UnitZ;
                }

                Quaternion3D rot       = Quaternion3D.CreateFromAxisAngle(axis, deltaAngle);
                Matrix3D     rotMatrix = Ext3D.CreateFromQuaternion(rot);
                Matrix3D     matrix    = cubie.Transform;// Matrix.Invert(cubie.Transform);
                matrix.Invert();


                Matrix3D rotation = Ext3D.CreateTranslation(Ext3D.Transform(-AxisTranslationFromOrigin, matrix)) * rotMatrix * Ext3D.CreateTranslation(Ext3D.Transform(AxisTranslationFromOrigin, matrix));
                if (IsAxisMoving)
                {
                    Vector3D v1;
                    if (!_axisTranslation.ContainsKey(cubieFace))
                    {
                        Matrix3D m = (cubieFace as ITransform).Transform; m.Invert();
                        v1 = Ext3D.Transform(Axis2TranslationFromOrigin, m);
                        _axisTranslation.Add(cubieFace, v1);
                    }
                    v1 = _axisTranslation[cubieFace];
                    Matrix3D r = rotation; r.Invert();
                    v1 = Ext3D.Transform(v1, r);// Matrix.Invert(rotation));

                    Matrix3D rotationAxis = Ext3D.CreateTranslation(-v1) * rotMatrix * Ext3D.CreateTranslation(v1);
                    rotation = rotationAxis * rotation;

                    _axisTranslation[cubieFace] = v1;
                }
                (cubieFace as ITransform).DoTransform(rotation, false);
            }
        }
コード例 #3
0
        public static RotateCameraResult RotateCamera(this PerspectiveCamera camera, Vector3D axis, double angle)
        {
            axis.Normalize();
            Quaternion3D q = Quaternion3D.CreateFromAxisAngle(axis, angle);
            Matrix3D     m = Ext3D.CreateFromQuaternion(q);

            Vector3D p   = new Vector3D(camera.Position.X, camera.Position.Y, camera.Position.Z);
            Vector3D pos = Ext3D.Transform(p, m);

            camera.Position = new Point3D(pos.X, pos.Y, pos.Z);

            Vector3D d = new Vector3D(camera.LookDirection.X, camera.LookDirection.Y, camera.LookDirection.Z);

            camera.LookDirection = Ext3D.Transform(d, m);
            Vector3D up = new Vector3D(camera.UpDirection.X, camera.UpDirection.Y, camera.UpDirection.Z);

            camera.UpDirection = Ext3D.Transform(up, m);
            return(new RotateCameraResult
            {
                RotateMatrix = m,
                ViewMatrix = CalculateViewMatrix(camera.Position, camera.LookDirection, camera.UpDirection)
            });
        }
コード例 #4
0
            // ReSharper disable once InconsistentNaming
            // data is object[] { bool exportAttachments, string materialReference, string modelName, bool onlyOneLOD, bool skipCollision }
            public void Write(ICLIFlags flags, Chunked chunked, Stream output, List <byte> LODs, object[] data, FindLogic.Combo.ModelInfoNew modelInfo)
            {
                byte?flagLOD = null;

                if (flags is ExtractFlags extractFlags)
                {
                    flagLOD = extractFlags.LOD;
                }

                IChunk chunk = chunked.FindNextChunk("MNRM").Value;

                if (chunk == null)
                {
                    return;
                }
                MNRM model = (MNRM)chunk;

                chunk = chunked.FindNextChunk("CLDM").Value;
                CLDM materials = null;

                if (chunk != null)
                {
                    materials = (CLDM)chunk;
                }
                chunk = chunked.FindNextChunk("lksm").Value;
                lksm skeleton = null;

                if (chunk != null)
                {
                    skeleton = (lksm)chunk;
                }
                chunk = chunked.FindNextChunk("PRHM").Value;
                PRHM hardpoints = null;

                if (chunk != null)
                {
                    hardpoints = (PRHM)chunk;
                }
                HTLC cloth = chunked.FindNextChunk("HTLC").Value as HTLC;

                short[] hierarchy = (short[])skeleton?.Hierarchy.Clone();
                Dictionary <int, HTLC.ClothNode> nodeMap = new Dictionary <int, HTLC.ClothNode>();

                if (cloth != null)
                {
                    uint clothIndex = 0;
                    foreach (HTLC.ClothNode[] nodeCollection in cloth.Nodes)
                    {
                        if (nodeCollection == null)
                        {
                            continue;
                        }
                        int nodeIndex = 0;
                        foreach (HTLC.ClothNode node in nodeCollection)
                        {
                            int parentRaw = node.VerticalParent;
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex) &&
                                cloth.NodeBones[clothIndex].ContainsKey(parentRaw))
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] =
                                        cloth.NodeBones[clothIndex][parentRaw];
                                    if (cloth.NodeBones[clothIndex][parentRaw] == -1)
                                    {
                                        HTLC.ClothNodeWeight weightedBone =
                                            node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                        hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    }
                                }
                            }
                            else
                            {
                                if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                                {
                                    if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                    {
                                        hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = -1;
                                        HTLC.ClothNodeWeight weightedBone =
                                            node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                        hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    }
                                }
                            }
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    nodeMap[cloth.NodeBones[clothIndex][nodeIndex]] = node;
                                }
                            }

                            nodeIndex++;
                        }
                        clothIndex++;
                    }
                }

                using (BinaryWriter writer = new BinaryWriter(output)) {
                    writer.Write((ushort)1);  // version major
                    writer.Write((ushort)5);  // version minor

                    if (data.Length > 1 && data[1] is string && ((string)data[1]).Length > 0)
                    {
                        writer.Write((string)data[1]);
                    }
                    else
                    {
                        writer.Write((byte)0);
                    }

                    if (data.Length > 2 && data[2] is string && ((string)data[2]).Length > 0)
                    {
                        writer.Write((string)data[2]);
                    }
                    else
                    {
                        writer.Write((byte)0);
                    }

                    if (skeleton == null)
                    {
                        writer.Write((ushort)0);  // number of bones
                    }
                    else
                    {
                        writer.Write(skeleton.Data.bonesAbs);
                    }

                    // ReSharper disable once InconsistentNaming
                    Dictionary <byte, List <int> > LODMap = new Dictionary <byte, List <int> >();
                    uint sz         = 0;
                    uint lookForLod = 0;

                    if (model.Submeshes.Any(x => x.lod == flagLOD))
                    {
                        lookForLod = (byte)flagLOD;
                    }
                    else if (flagLOD != null)
                    {
                        SubmeshDescriptor nextLowest = model.Submeshes.Where(p => p.lod < flagLOD).OrderBy(x => x.lod).LastOrDefault();
                        if (nextLowest.verticesToDraw == 0 && nextLowest.indexCount == 0)   // not real mesh
                        {
                            SubmeshDescriptor nextHighest = model.Submeshes.Where(p => p.lod > flagLOD).OrderBy(x => x.lod).FirstOrDefault();
                            lookForLod = nextHighest.lod;
                        }
                        else
                        {
                            lookForLod = nextLowest.lod;
                        }
                    }

                    for (int i = 0; i < model.Submeshes.Length; ++i)
                    {
                        SubmeshDescriptor submesh = model.Submeshes[i];
                        if (data.Length > 4 && data[4] is bool && (bool)data[4])
                        {
                            if (submesh.flags == SubmeshFlags.COLLISION_MESH)
                            {
                                continue;
                            }
                        }
                        if (lookForLod > 0 && submesh.lod != lookForLod && submesh.lod != 255)
                        {
                            continue;
                        }

                        if (!LODMap.ContainsKey(submesh.lod))
                        {
                            LODMap.Add(submesh.lod, new List <int>());
                        }
                        sz++;
                        LODMap[submesh.lod].Add(i);
                    }

                    writer.Write(sz);
                    writer.Write(hardpoints?.HardPoints.Length ?? 0);

                    if (skeleton != null)
                    {
                        for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                        {
                            writer.Write(IdToString("bone", skeleton.IDs[i]));
                            short parent = hierarchy[i];
                            if (parent == -1)
                            {
                                parent = (short)i;
                            }
                            writer.Write(parent);

                            Matrix3x4  bone = skeleton.Matrices34[i];
                            Quaternion rot  = new Quaternion(bone[0, 0], bone[0, 1], bone[0, 2], bone[0, 3]);
                            Vector3    scl  = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                            Vector3    pos  = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                            if (nodeMap.ContainsKey(i))
                            {
                                HTLC.ClothNode thisNode = nodeMap[i];
                                pos.X = thisNode.X;
                                pos.Y = thisNode.Y;
                                pos.Z = thisNode.Z;
                            }
                            writer.Write(pos.X);
                            writer.Write(pos.Y);
                            writer.Write(pos.Z);
                            writer.Write(scl.X);
                            writer.Write(scl.Y);
                            writer.Write(scl.Z);
                            writer.Write(rot.X);
                            writer.Write(rot.Y);
                            writer.Write(rot.Z);
                            writer.Write(rot.W);
                        }
                    }

                    foreach (KeyValuePair <byte, List <int> > kv in LODMap)
                    {
                        foreach (int i in kv.Value)
                        {
                            SubmeshDescriptor submesh = model.Submeshes[i];
                            ModelVertex[]     vertex  = model.Vertices[i];
                            ModelVertex[]     normal  = model.Normals[i];
                            ModelUV[][]       uv      = model.TextureCoordinates[i];
                            ModelIndice[]     index   = model.Indices[i];

                            ModelBoneData[] bones = model.Bones[i];
                            writer.Write($"Submesh_{i}.{kv.Key}.{materials.Materials[submesh.material]:X16}");
                            writer.Write(materials.Materials[submesh.material]);
                            writer.Write((byte)uv.Length);

                            writer.Write(vertex.Length);
                            writer.Write(index.Length);
                            for (int j = 0; j < vertex.Length; ++j)
                            {
                                writer.Write(vertex[j].x);
                                writer.Write(vertex[j].y);
                                writer.Write(vertex[j].z);
                                writer.Write(-normal[j].x);
                                writer.Write(-normal[j].y);
                                writer.Write(-normal[j].z);
                                foreach (ModelUV[] t in uv)
                                {
                                    writer.Write(t[j].u);
                                    writer.Write(t[j].v);
                                }
                                if (skeleton != null && bones != null && bones[j].boneIndex != null &&
                                    bones[j].boneWeight != null)
                                {
                                    writer.Write((byte)4);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[0]]);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[1]]);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[2]]);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[3]]);
                                    writer.Write(bones[j].boneWeight[0]);
                                    writer.Write(bones[j].boneWeight[1]);
                                    writer.Write(bones[j].boneWeight[2]);
                                    writer.Write(bones[j].boneWeight[3]);
                                }
                                else
                                {
                                    // bone -> size + index + weight
                                    writer.Write((byte)0);
                                }
                            }
                            List <ModelIndiceModifiable> indexNew = new List <ModelIndiceModifiable>();
                            foreach (ModelIndice indice in index)
                            {
                                indexNew.Add(new ModelIndiceModifiable {
                                    v1 = indice.v1,
                                    v2 = indice.v2,
                                    v3 = indice.v3
                                });
                            }
                            foreach (ModelIndiceModifiable indice in indexNew)
                            {
                                writer.Write((byte)3);
                                writer.Write(indice.v1);
                                writer.Write(indice.v2);
                                writer.Write(indice.v3);
                            }
                        }
                    }

                    if (hardpoints != null)
                    {
                        // attachments
                        foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                        {
                            writer.Write(IdToString("hardpoint", GUID.Index(hp.HardPointGUID)));
                            Matrix4 mat = hp.Matrix.ToOpenTK();

                            Vector3    pos = mat.ExtractTranslation();
                            Quaternion rot = mat.ExtractRotation();

                            writer.Write(pos.X);
                            writer.Write(pos.Y);
                            writer.Write(pos.Z);
                            writer.Write(rot.X);
                            writer.Write(rot.Y);
                            writer.Write(rot.Z);
                            writer.Write(rot.W);
                        }
                        // extension 1.1
                        foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                        {
                            writer.Write(IdToString("bone", GUID.Index(hp.GUIDx012)));
                        }
                    }

                    // ext 1.3: cloth
                    writer.Write(0);

                    // ext 1.4: embedded refpose
                    if (skeleton != null)
                    {
                        for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                        {
                            writer.Write(IdToString("bone", skeleton.IDs[i]));
                            short parent = hierarchy[i];
                            writer.Write(parent);

                            Matrix3x4 bone = skeleton.Matrices34Inverted[i];

                            Quaternion3D quat = new Quaternion3D(bone[0, 3], bone[0, 0], bone[0, 1], bone[0, 2]);

                            Vector3D rot = C3D.ToEulerAngles(quat);
                            // ReSharper disable CompareOfFloatsByEqualityOperator
                            if (rot.X == -3.14159274f && rot.Y == 0 && rot.Z == 0)
                            {
                                rot = new Vector3D(0, 3.14159274f, 3.14159274f);
                                // effectively the same but you know, eulers.
                            }
                            // ReSharper restore CompareOfFloatsByEqualityOperator
                            Vector3 scl = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                            Vector3 pos = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                            writer.Write(pos.X);
                            writer.Write(pos.Y);
                            writer.Write(pos.Z);
                            writer.Write(scl.X);
                            writer.Write(scl.Y);
                            writer.Write(scl.Z);
                            writer.Write(rot.X);
                            writer.Write(rot.Y);
                            writer.Write(rot.Z);
                        }
                    }

                    // ext 1.5: guid
                    writer.Write(GUID.Index(modelInfo.GUID));

                    // ext 1.6: cloth 2.0
                    if (cloth == null)
                    {
                        writer.Write(0);
                    }
                    else
                    {
                        writer.Write(cloth.Descriptors.Length);

                        for (int i = 0; i < cloth.Descriptors.Length; i++)
                        {
                            var desc = cloth.Descriptors[i];

                            writer.Write(desc.Name);
                            writer.Write(cloth.Nodes[i].Length);
                            foreach (HTLC.ClothNode clothNode in cloth.Nodes[i])
                            {
                                writer.Write(clothNode.Bones.Length);

                                foreach (HTLC.ClothNodeWeight clothNodeWeight in clothNode.Bones)
                                {
                                    writer.Write(clothNodeWeight.Bone);
                                    writer.Write(clothNodeWeight.Weight);
                                }
                            }
                        }
                    }
                }
            }
コード例 #5
0
        // ReSharper disable once InconsistentNaming
        public bool Write(Chunked chunked, Stream output, List <byte> LODs, Dictionary <ulong, List <ImageLayer> > layers, object[] data)
        {
            IChunk chunk = chunked.FindNextChunk("MNRM").Value;

            if (chunk == null)
            {
                return(false);
            }
            MNRM model = (MNRM)chunk;

            chunk = chunked.FindNextChunk("CLDM").Value;
            CLDM materials = null;

            if (chunk != null)
            {
                materials = (CLDM)chunk;
            }
            chunk = chunked.FindNextChunk("lksm").Value;
            lksm skeleton = null;

            if (chunk != null)
            {
                skeleton = (lksm)chunk;
            }
            chunk = chunked.FindNextChunk("PRHM").Value;
            PRHM hardpoints = null;

            if (chunk != null)
            {
                hardpoints = (PRHM)chunk;
            }

            short[] hierarchy = (short[])skeleton?.Hierarchy.Clone();
            Dictionary <int, HTLC.ClothNode> nodeMap = new Dictionary <int, HTLC.ClothNode>();

            if (chunked.FindNextChunk("HTLC").Value is HTLC cloth)
            {
                uint clothIndex = 0;
                foreach (HTLC.ClothNode[] nodeCollection in cloth.Nodes)
                {
                    if (nodeCollection == null)
                    {
                        continue;
                    }
                    int nodeIndex = 0;
                    foreach (HTLC.ClothNode node in nodeCollection)
                    {
                        int parentRaw = node.VerticalParent;
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex) &&
                            cloth.NodeBones[clothIndex].ContainsKey(parentRaw))
                        {
                            if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                            {
                                hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = cloth.NodeBones[clothIndex][parentRaw];
                                if (cloth.NodeBones[clothIndex][parentRaw] == -1)
                                {
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                }
                            }
                        }
                        else
                        {
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))    // if on main skele
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = -1;
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                }
                            }
                        }
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                        {
                            // good code:
                            if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                            {
                                nodeMap[cloth.NodeBones[clothIndex][nodeIndex]] = node;
                            }
                        }

                        nodeIndex++;
                    }
                    clothIndex++;
                }
            }

            using (BinaryWriter writer = new BinaryWriter(output)) {
                writer.Write((ushort)1); // version major
                writer.Write((ushort)4); // version minor

                if (data.Length > 1 && data[1] is string && ((string)data[1]).Length > 0)
                {
                    writer.Write((string)data[1]);
                }
                else
                {
                    writer.Write((byte)0);
                }

                if (data.Length > 2 && data[2] is string && ((string)data[2]).Length > 0)
                {
                    writer.Write((string)data[2]);
                }
                else
                {
                    writer.Write((byte)0);
                }

                if (skeleton == null)
                {
                    writer.Write((ushort)0); // number of bones
                }
                else
                {
                    writer.Write(skeleton.Data.bonesAbs);
                }

                // ReSharper disable once InconsistentNaming
                Dictionary <byte, List <int> > LODMap = new Dictionary <byte, List <int> >();
                uint sz         = 0;
                uint lookForLod = 0;
                bool lodOnly    = data.Length > 3 && data[3] is bool && (bool)data[3];
                for (int i = 0; i < model.Submeshes.Length; ++i)
                {
                    SubmeshDescriptor submesh = model.Submeshes[i];
                    if (data.Length > 4 && data[4] is bool && (bool)data[4])
                    {
                        if (submesh.flags == SubmeshFlags.COLLISION_MESH)
                        {
                            continue;
                        }
                    }
                    if (LODs != null && !LODs.Contains(submesh.lod))
                    {
                        continue;
                    }
                    if (lodOnly && lookForLod > 0 && submesh.lod != lookForLod)
                    {
                        continue;
                    }
                    if (!LODMap.ContainsKey(submesh.lod))
                    {
                        LODMap.Add(submesh.lod, new List <int>());
                    }
                    lookForLod = submesh.lod;
                    sz++;
                    LODMap[submesh.lod].Add(i);
                }

                //long meshCountPos = writer.BaseStream.Position;
                writer.Write(sz);

                writer.Write(hardpoints?.HardPoints.Length ?? 0);

                if (skeleton != null)
                {
                    for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                    {
                        writer.Write(IdToString("bone", skeleton.IDs[i]));
                        short parent = hierarchy[i];
                        if (parent == -1)
                        {
                            parent = (short)i;
                        }
                        writer.Write(parent);

                        Matrix3x4  bone = skeleton.Matrices34[i];
                        Quaternion rot  = new Quaternion(bone[0, 0], bone[0, 1], bone[0, 2], bone[0, 3]);
                        Vector3    scl  = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                        Vector3    pos  = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                        if (nodeMap.ContainsKey(i))
                        {
                            HTLC.ClothNode thisNode = nodeMap[i];
                            pos.X = thisNode.X;
                            pos.Y = thisNode.Y;
                            pos.Z = thisNode.Z;
                        }
                        writer.Write(pos.X);
                        writer.Write(pos.Y);
                        writer.Write(pos.Z);
                        writer.Write(scl.X);
                        writer.Write(scl.Y);
                        writer.Write(scl.Z);
                        writer.Write(rot.X);
                        writer.Write(rot.Y);
                        writer.Write(rot.Z);
                        writer.Write(rot.W);
                    }
                }

                foreach (KeyValuePair <byte, List <int> > kv in LODMap)
                {
                    foreach (int i in kv.Value)
                    {
                        SubmeshDescriptor submesh = model.Submeshes[i];
                        ModelVertex[]     vertex  = model.Vertices[i];
                        ModelVertex[]     normal  = model.Normals[i];
                        ModelUV[][]       uv      = model.TextureCoordinates[i];
                        ModelIndice[]     index   = model.Indices[i];

                        ModelBoneData[] bones = model.Bones[i];
                        writer.Write($"Submesh_{i}.{kv.Key}.{materials.Materials[submesh.material]:X16}");
                        writer.Write(materials.Materials[submesh.material]);
                        writer.Write((byte)uv.Length);

                        writer.Write(vertex.Length);
                        writer.Write(index.Length);
                        for (int j = 0; j < vertex.Length; ++j)
                        {
                            writer.Write(vertex[j].x);
                            writer.Write(vertex[j].y);
                            writer.Write(vertex[j].z);
                            writer.Write(-normal[j].x);
                            writer.Write(-normal[j].y);
                            writer.Write(-normal[j].z);
                            foreach (ModelUV[] t in uv)
                            {
                                writer.Write(t[j].u);
                                writer.Write(t[j].v);
                            }
                            if (skeleton != null && bones != null && bones[j].boneIndex != null && bones[j].boneWeight != null)
                            {
                                writer.Write((byte)4);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[0]]);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[1]]);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[2]]);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[3]]);
                                writer.Write(bones[j].boneWeight[0]);
                                writer.Write(bones[j].boneWeight[1]);
                                writer.Write(bones[j].boneWeight[2]);
                                writer.Write(bones[j].boneWeight[3]);
                            }
                            else
                            {
                                // bone -> size + index + weight
                                writer.Write((byte)0);
                            }
                        }
                        List <ModelIndiceModifiable> indexNew = new List <ModelIndiceModifiable>();
                        foreach (ModelIndice indice in index)
                        {
                            indexNew.Add(new ModelIndiceModifiable {
                                v1 = indice.v1, v2 = indice.v2, v3 = indice.v3
                            });
                        }
                        foreach (ModelIndiceModifiable indice in indexNew)
                        {
                            writer.Write((byte)3);
                            writer.Write(indice.v1);
                            writer.Write(indice.v2);
                            writer.Write(indice.v3);
                        }
                    }
                }

                if (hardpoints != null)
                {
                    // attachments
                    foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                    {
                        writer.Write(IdToString("attachment_", GUID.Index(hp.HardPointGUID)));
                        Matrix4    mat = hp.Matrix.ToOpenTK();
                        Vector3    pos = mat.ExtractTranslation();
                        Quaternion rot = mat.ExtractRotation();
                        writer.Write(pos.X);
                        writer.Write(pos.Y);
                        writer.Write(pos.Z);
                        writer.Write(rot.X);
                        writer.Write(rot.Y);
                        writer.Write(rot.Z);
                        writer.Write(rot.W);
                    }
                    // extension 1.1
                    foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                    {
                        writer.Write(IdToString("bone", GUID.Index(hp.GUIDx012)));
                    }
                }

                // ext 1.3: cloth
                writer.Write(0);

                // ext 1.4: embedded refpose
                if (skeleton != null)
                {
                    for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                    {
                        writer.Write(IdToString("bone", skeleton.IDs[i]));
                        short parent = hierarchy[i];
                        // if (parent == -1) {
                        //     parent = (short)i;
                        // }
                        writer.Write(parent);

                        Matrix3x4 bone = skeleton.Matrices34Inverted[i];

                        // Quaternion3D quat = new Quaternion3D(bone[0, 0], bone[0, 1], bone[0, 2], bone[0, 3]);
                        // why are they different
                        Quaternion3D quat = new Quaternion3D(bone[0, 3], bone[0, 0], bone[0, 1], bone[0, 2]);

                        Vector3D rot = C3D.ToEulerAngles(quat);
                        if (rot.X == -3.14159274f && rot.Y == 0 && rot.Z == 0)
                        {
                            rot = new Vector3D(0, 3.14159274f, 3.14159274f); // effectively the same but you know, eulers.
                        }
                        Vector3 scl = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                        Vector3 pos = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);

                        writer.Write(pos.X);
                        writer.Write(pos.Y);
                        writer.Write(pos.Z);
                        writer.Write(scl.X);
                        writer.Write(scl.Y);
                        writer.Write(scl.Z);
                        writer.Write(rot.X);
                        writer.Write(rot.Y);
                        writer.Write(rot.Z);
                    }
                }
            }

            return(true);
        }
コード例 #6
0
        public bool Write(Chunked model, Stream output, bool keepOpen = false)
        {
            culture.NumberFormat.NumberDecimalSeparator          = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = culture;
            IChunk chunk = model.FindNextChunk("lksm").Value;

            if (chunk == null)
            {
                return(false);
            }
            lksm skeleton = (lksm)chunk;

            short[]         hierarchy                = (short[])skeleton.Hierarchy.Clone();
            HashSet <short> weightedParNodes         = new HashSet <short>();
            Dictionary <int, HTLC.ClothNode> nodeMap = new Dictionary <int, HTLC.ClothNode>();
            HTLC cloth = model.FindNextChunk("HTLC").Value as HTLC;

            if (cloth != null)
            {
                uint clothIndex = 0;
                foreach (HTLC.ClothNode[] nodeCollection in cloth.Nodes)
                {
                    if (nodeCollection == null)
                    {
                        continue;
                    }
                    int nodeIndex = 0;
                    foreach (HTLC.ClothNode node in nodeCollection)
                    {
                        int parentRaw = node.VerticalParent;
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex) &&
                            cloth.NodeBones[clothIndex].ContainsKey(parentRaw))
                        {
                            // good code:
                            if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                            {
                                hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = cloth.NodeBones[clothIndex][parentRaw];
                                if (cloth.NodeBones[clothIndex][parentRaw] == -1)
                                {
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    weightedParNodes.Add(cloth.NodeBones[clothIndex][nodeIndex]);
                                }
                            }
                            // else: on subskele
                            // todo: add subskelebones?
                        }
                        else
                        {
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))    // if on main skele
                            // good code:
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = -1;
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    weightedParNodes.Add(cloth.NodeBones[clothIndex][nodeIndex]);
                                }
                                // else: on subskele
                                // todo: add subskelebones?
                            }
                        }
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                        {
                            // good code:
                            nodeMap[cloth.NodeBones[clothIndex][nodeIndex]] = node;
                        }
                        nodeIndex++;
                    }
                    clothIndex++;
                }
            }
            using (StreamWriter writer = new StreamWriter(output, Encoding.Default, 512, keepOpen)) {
                writer.WriteLine("{0}", skeleton.Data.bonesAbs);
                writer.WriteLine("version 1");
                writer.WriteLine("nodes");
                for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                {
                    writer.WriteLine("{0} \"bone_{1:X4}\" {2}", i, skeleton.IDs[i], hierarchy[i]);
                }
                writer.WriteLine("end");
                writer.WriteLine("skeleton");
                writer.WriteLine("time 0");
                for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                {
                    Matrix3x4    bone  = skeleton.Matrices34Inverted[i];
                    Quaternion3D quat  = new Quaternion3D(bone[0, 3], bone[0, 0], bone[0, 1], bone[0, 2]);
                    Vector3D     rot   = C3D.ToEulerAngles(quat);
                    Vector3      scale = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                    Vector3      pos   = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                    if (nodeMap.ContainsKey(i))
                    {
                        HTLC.ClothNode thisNode = nodeMap[i];
                        if (weightedParNodes.Contains((short)i))
                        {
                            Vector3 pos2 = GetGlobalPos(skeleton.Matrices34Inverted, hierarchy[i], hierarchy);
                            pos.X = thisNode.X - pos2.X;
                            pos.Y = thisNode.Y - pos2.Y;
                            pos.Z = thisNode.Z - pos2.Z;
                        }
                        else if (nodeMap.ContainsKey(hierarchy[i]))
                        {
                            HTLC.ClothNode parentNode = nodeMap[hierarchy[i]];
                            pos.X = thisNode.X - parentNode.X;
                            pos.Y = thisNode.Y - parentNode.Y;
                            pos.Z = thisNode.Z - parentNode.Z;
                        }
                        else
                        {
                            pos.X = thisNode.X;
                            pos.Y = thisNode.Y;
                            pos.Z = thisNode.Z;
                        }
                    }
                    if (rot.X == -3.14159274f && rot.Y == 0 && rot.Z == 0)
                    {
                        rot = new Vector3D(0, 3.14159274f, 3.14159274f); // effectively the same but you know, eulers.
                    }
                    writer.WriteLine(String.Format(CultureInfo.InvariantCulture, "{0}  {1:0.000000} {2:0.000000} {3:0.000000}  {4:0.000000} {5:0.000000} {6:0.000000}  {7:0.000000} {8:0.000000} {9:0.000000}", i, pos.X, pos.Y, pos.Z, rot.X, rot.Y, rot.Z, scale.X, scale.Y, scale.Z));
                }
            }
            return(true);
        }
コード例 #7
0
        public static void ConvertAnimation(string refpose, string input, string output)
        {
            NumberFormatInfo format = new NumberFormatInfo();

            format.NumberDecimalSeparator = ".";
            StreamReader          refpose_reader    = new StreamReader(refpose);
            int                   refpose_bonecount = Convert.ToInt32(refpose_reader.ReadLine());
            Dictionary <int, int> refpose_parentmap = new Dictionary <int, int>();
            Dictionary <int, int> refpose_indexmap  = new Dictionary <int, int>();

            int[] refpose_bonearray = new int[refpose_bonecount];
            int[] refpose_hierarchy = new int[refpose_bonecount];
            refpose_reader.ReadLine();
            refpose_reader.ReadLine();
            for (int index = 0; index < refpose_bonecount; ++index)
            {
                string[] array = refpose_reader.ReadLine().Replace("\"", string.Empty).Split(' ');
                refpose_bonearray[index] = Convert.ToInt32(array[1].Split('_').Last(), 16);
                refpose_hierarchy[index] = Convert.ToInt32(array[2]);
            }

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (refpose_hierarchy[index] != -1)
                {
                    refpose_parentmap.Add(refpose_bonearray[index], refpose_bonearray[refpose_hierarchy[index]]);
                }
                else
                {
                    refpose_parentmap.Add(refpose_bonearray[index], -1);
                }
                refpose_indexmap.Add(refpose_bonearray[index], index);
            }
            refpose_reader.ReadLine();
            refpose_reader.ReadLine();
            refpose_reader.ReadLine();
            Vector3D[] refpose_position = new Vector3D[refpose_bonecount];
            Vector3D[] refpose_rotation = new Vector3D[refpose_bonecount];
            Vector3D[] refpose_scale    = new Vector3D[refpose_bonecount];
            for (int index = 0; index < refpose_bonecount; ++index)
            {
                refpose_position[index] = new Vector3D();
                refpose_rotation[index] = new Vector3D();
                refpose_scale[index]    = new Vector3D(1, 1, 1);
                string[] array = refpose_reader.ReadLine().Replace("\"", string.Empty).Split(' ');
                refpose_position[index].X = Convert.ToSingle(array[2], format);
                refpose_position[index].Y = Convert.ToSingle(array[3], format);
                refpose_position[index].Z = Convert.ToSingle(array[4], format);
                refpose_rotation[index].X = Convert.ToSingle(array[6], format);
                refpose_rotation[index].Y = Convert.ToSingle(array[7], format);
                refpose_rotation[index].Z = Convert.ToSingle(array[8], format);
            }
            refpose_reader.Close();
            FileStream   inputStream  = new FileStream(input, FileMode.Open);
            BinaryReader input_reader = new BinaryReader(inputStream);

            input_reader.ReadInt32();
            float  duration   = input_reader.ReadSingle();
            float  fps        = input_reader.ReadSingle();
            ushort bone_count = input_reader.ReadUInt16();

            input_reader.ReadUInt16();
            int frame_count = (int)(fps * (double)duration) + 1;

            inputStream.Seek(24L, SeekOrigin.Current);
            long offset_bone_list  = input_reader.ReadInt64();
            long offset_info_table = input_reader.ReadInt64();

            inputStream.Seek(24L, SeekOrigin.Current);
            StreamWriter output_writer = new StreamWriter(output);

            output_writer.WriteLine("version 1");
            output_writer.WriteLine("nodes");
            int[] bone_list = new int[bone_count];
            inputStream.Seek(offset_bone_list, SeekOrigin.Begin);
            Dictionary <int, int> bone_translation_map = new Dictionary <int, int>();
            int bone_id;

            for (int index = 0; index < bone_count; ++index)
            {
                bone_id          = input_reader.ReadInt32();
                bone_list[index] = bone_id;
                bone_translation_map.Add(bone_id, index);
            }
            for (int index = 0; index < bone_count; ++index)
            {
                bone_id = bone_list[index];
                int num3 = -1;
                if (refpose_parentmap.ContainsKey(bone_id))
                {
                    int key2 = refpose_parentmap[bone_id];
                    num3 = !bone_translation_map.ContainsKey(key2) ? -1 : bone_translation_map[key2];
                }
                output_writer.WriteLine(index.ToString() + " \"bone_" + bone_id.ToString("X4") + "\" " + num3);
            }
            int last_bone_index = bone_count;
            Dictionary <int, int> secondary_bone_translation_map = new Dictionary <int, int>();

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (!bone_translation_map.ContainsKey(refpose_bonearray[index]))
                {
                    secondary_bone_translation_map.Add(refpose_bonearray[index], last_bone_index);
                }
            }

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (!bone_translation_map.ContainsKey(refpose_bonearray[index]))
                {
                    int key2 = refpose_parentmap[refpose_bonearray[index]];
                    int num3 = !bone_translation_map.ContainsKey(key2) ? (!secondary_bone_translation_map.ContainsKey(key2) ? -1 : secondary_bone_translation_map[key2]) : bone_translation_map[key2];
                    output_writer.WriteLine(last_bone_index.ToString() + " \"bone_" + refpose_bonearray[index].ToString("X4") + "\" " + num3);
                    ++last_bone_index;
                }
            }
            output_writer.WriteLine("end");
            float[,] x_array           = new float[last_bone_index, frame_count];
            float[,] y_array           = new float[last_bone_index, frame_count];
            float[,] z_array           = new float[last_bone_index, frame_count];
            float[,] sx_array          = new float[last_bone_index, frame_count];
            float[,] sy_array          = new float[last_bone_index, frame_count];
            float[,] sz_array          = new float[last_bone_index, frame_count];
            float[,] rx_array          = new float[last_bone_index, frame_count];
            float[,] ry_array          = new float[last_bone_index, frame_count];
            float[,] rz_array          = new float[last_bone_index, frame_count];
            float[,] rw_array          = new float[last_bone_index, frame_count];
            bool[,] has_rotation_frame = new bool[last_bone_index, frame_count];
            bool[,] has_position_frame = new bool[last_bone_index, frame_count];
            bool[,] has_scale_frame    = new bool[last_bone_index, frame_count];
            output_writer.WriteLine("skeleton");
            output_writer.WriteLine("time 0");
            for (int index = 0; index < bone_count; ++index)
            {
                if (refpose_indexmap.ContainsKey(bone_list[index]))
                {
                    bone_id = refpose_indexmap[bone_list[index]];
                    output_writer.Write(index);
                    output_writer.Write(" " + refpose_position[bone_id].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[bone_id].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[bone_id].Z.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[bone_id].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[bone_id].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[bone_id].Z.ToString("0.000000", format));
                    output_writer.WriteLine();
                }
                else
                {
                    output_writer.WriteLine(index.ToString() + " 0 0 0 0 0 0");
                }
            }
            int num4 = bone_count;

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (!bone_translation_map.ContainsKey(refpose_bonearray[index]))
                {
                    output_writer.Write(num4++);
                    output_writer.Write(" " + refpose_position[index].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[index].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[index].Z.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[index].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[index].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[index].Z.ToString("0.000000", format));
                    output_writer.WriteLine();
                }
            }
            Quaternion3D q        = new Quaternion3D();
            Vector3D     vector3D = new Vector3D();

            inputStream.Seek(offset_info_table, SeekOrigin.Begin);
            for (int index1 = 0; index1 < bone_count; ++index1)
            {
                long  position                = inputStream.Position;
                int   scale_count             = input_reader.ReadInt16();
                int   position_count          = input_reader.ReadInt16();
                int   rotation_count          = input_reader.ReadInt16();
                int   flags                   = input_reader.ReadInt16();
                long  scale_indices_offset    = input_reader.ReadInt32() * 4 + position;
                long  position_indices_offset = input_reader.ReadInt32() * 4 + position;
                long  rotation_indices_offset = input_reader.ReadInt32() * 4 + position;
                long  scale_data_offset       = input_reader.ReadInt32() * 4 + position;
                long  position_data_offset    = input_reader.ReadInt32() * 4 + position;
                long  rotation_data_offset    = input_reader.ReadInt32() * 4 + position;
                int[] scale_indices           = new int[scale_count];
                inputStream.Seek(scale_indices_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < scale_count; ++index2)
                {
                    scale_indices[index2] = frame_count > byte.MaxValue ? input_reader.ReadInt16() : input_reader.ReadByte();
                }
                inputStream.Seek(scale_data_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < scale_count; ++index2)
                {
                    int index3 = scale_indices[index2];
                    has_scale_frame[index1, index3] = true;
                    float x = input_reader.ReadUInt16() / 1024.0f;
                    sx_array[index1, index3] = x;
                    float y = input_reader.ReadUInt16() / 1024.0f;
                    sy_array[index1, index3] = y;
                    float z = input_reader.ReadUInt16() / 1024.0f;
                    sz_array[index1, index3] = z;
                }
                int[] position_indices = new int[position_count];
                inputStream.Seek(position_indices_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < position_count; ++index2)
                {
                    position_indices[index2] = frame_count > byte.MaxValue ? input_reader.ReadInt16() : input_reader.ReadByte();
                }
                inputStream.Seek(position_data_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < position_count; ++index2)
                {
                    int index3 = position_indices[index2];
                    has_position_frame[index1, index3] = true;
                    float x = input_reader.ReadSingle();
                    x_array[index1, index3] = x;
                    float y = input_reader.ReadSingle();
                    y_array[index1, index3] = y;
                    float z = input_reader.ReadSingle();
                    z_array[index1, index3] = z;
                }
                int[] rotation_indices = new int[rotation_count];
                inputStream.Seek(rotation_indices_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < rotation_count; ++index2)
                {
                    rotation_indices[index2] = frame_count > byte.MaxValue ? input_reader.ReadInt16() : input_reader.ReadByte();
                }
                inputStream.Seek(rotation_data_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < rotation_count; ++index2)
                {
                    ushort rot_a  = input_reader.ReadUInt16();
                    ushort rot_b  = input_reader.ReadUInt16();
                    ushort rot_c  = input_reader.ReadUInt16();
                    Vec4d  rot    = Animation.UnpackRotation(rot_a, rot_b, rot_c);
                    int    index3 = rotation_indices[index2];
                    has_rotation_frame[index1, index3] = true;
                    rx_array[index1, index3]           = (float)rot.x;
                    ry_array[index1, index3]           = (float)rot.y;
                    rz_array[index1, index3]           = (float)rot.z;
                    rw_array[index1, index3]           = (float)rot.w;
                }
                inputStream.Seek(position + 32L, SeekOrigin.Begin);
            }
            for (int index1 = 0; index1 < frame_count; ++index1)
            {
                output_writer.WriteLine($"time {index1 + 1}");
                for (int index2 = 0; index2 < last_bone_index; ++index2)
                {
                    if (has_position_frame[index2, index1] || has_rotation_frame[index2, index1] || has_scale_frame[index2, index1])
                    {
                        if (!has_position_frame[index2, index1])
                        {
                            int index3 = index1;
                            int index4 = index1;
                            while (!has_position_frame[index2, index3])
                            {
                                --index3;
                            }
                            while (index4 < frame_count && !has_position_frame[index2, index4])
                            {
                                ++index4;
                            }
                            if (index4 == frame_count)
                            {
                                x_array[index2, index1] = x_array[index2, index3];
                                y_array[index2, index1] = y_array[index2, index3];
                                z_array[index2, index1] = z_array[index2, index3];
                            }
                            else
                            {
                                float num3 = (index1 - index3) / (float)(index4 - index3);
                                x_array[index2, index1] = (x_array[index2, index4] - x_array[index2, index3]) * num3 + x_array[index2, index3];
                                y_array[index2, index1] = (y_array[index2, index4] - y_array[index2, index3]) * num3 + y_array[index2, index3];
                                z_array[index2, index1] = (z_array[index2, index4] - z_array[index2, index3]) * num3 + z_array[index2, index3];
                            }
                        }
                        if (!has_scale_frame[index2, index1])
                        {
                            int index3 = index1;
                            int index4 = index1;
                            while (!has_scale_frame[index2, index3])
                            {
                                --index3;
                            }
                            while (index4 < frame_count && !has_scale_frame[index2, index4])
                            {
                                ++index4;
                            }
                            if (index4 == frame_count)
                            {
                                sx_array[index2, index1] = sx_array[index2, index3];
                                sy_array[index2, index1] = sy_array[index2, index3];
                                sz_array[index2, index1] = sz_array[index2, index3];
                            }
                            else
                            {
                                float num3 = (index1 - index3) / (float)(index4 - index3);
                                sx_array[index2, index1] = (sx_array[index2, index4] - sx_array[index2, index3]) * num3 + sx_array[index2, index3];
                                sy_array[index2, index1] = (sy_array[index2, index4] - sy_array[index2, index3]) * num3 + sy_array[index2, index3];
                                sz_array[index2, index1] = (sz_array[index2, index4] - sz_array[index2, index3]) * num3 + sz_array[index2, index3];
                            }
                        }
                        if (!has_rotation_frame[index2, index1])
                        {
                            int index3 = index1;
                            int index4 = index1;
                            while (!has_rotation_frame[index2, index3])
                            {
                                --index3;
                            }
                            while (index4 < frame_count && !has_rotation_frame[index2, index4])
                            {
                                ++index4;
                            }
                            if (index4 == frame_count)
                            {
                                rx_array[index2, index1] = rx_array[index2, index3];
                                ry_array[index2, index1] = ry_array[index2, index3];
                                rz_array[index2, index1] = rz_array[index2, index3];
                                rw_array[index2, index1] = rw_array[index2, index3];
                            }
                            else
                            {
                                double num3 = rx_array[index2, index4] * (double)rx_array[index2, index3] + ry_array[index2, index4] * (double)ry_array[index2, index3] + rz_array[index2, index4] * (double)rz_array[index2, index3] + rw_array[index2, index4] * (double)rw_array[index2, index3];
                                float  num9 = (index1 - index3) / (float)(index4 - index3);
                                if (num3 < 0.0)
                                {
                                    rx_array[index2, index1] = (-rx_array[index2, index4] - rx_array[index2, index3]) * num9 + rx_array[index2, index3];
                                    ry_array[index2, index1] = (-ry_array[index2, index4] - ry_array[index2, index3]) * num9 + ry_array[index2, index3];
                                    rz_array[index2, index1] = (-rz_array[index2, index4] - rz_array[index2, index3]) * num9 + rz_array[index2, index3];
                                    rw_array[index2, index1] = (-rw_array[index2, index4] - rw_array[index2, index3]) * num9 + rw_array[index2, index3];
                                }
                                else
                                {
                                    rx_array[index2, index1] = (rx_array[index2, index4] - rx_array[index2, index3]) * num9 + rx_array[index2, index3];
                                    ry_array[index2, index1] = (ry_array[index2, index4] - ry_array[index2, index3]) * num9 + ry_array[index2, index3];
                                    rz_array[index2, index1] = (rz_array[index2, index4] - rz_array[index2, index3]) * num9 + rz_array[index2, index3];
                                    rw_array[index2, index1] = (rw_array[index2, index4] - rw_array[index2, index3]) * num9 + rw_array[index2, index3];
                                }
                            }
                        }
                        output_writer.Write(index2);
                        output_writer.Write(" " + x_array[index2, index1].ToString("0.000000", format));
                        output_writer.Write(" " + y_array[index2, index1].ToString("0.000000", format));
                        output_writer.Write(" " + z_array[index2, index1].ToString("0.000000", format));
                        q.i    = rx_array[index2, index1];
                        q.j    = ry_array[index2, index1];
                        q.k    = rz_array[index2, index1];
                        q.real = rw_array[index2, index1];
                        Vector3D eulerAngles = C3D.ToEulerAngles(q);
                        output_writer.Write(" " + eulerAngles.X.ToString("0.000000", format));
                        output_writer.Write(" " + eulerAngles.Y.ToString("0.000000", format));
                        output_writer.Write(" " + eulerAngles.Z.ToString("0.000000", format));
                        output_writer.WriteLine();
                    }
                }
            }
            output_writer.WriteLine("end");
            output_writer.Close();
        }