Example #1
0
        private void ReadMaterialAnimations(Anim animFile, AnimGroup animGroup, SBAnimation animation)
        {
            var decoder = new SsbhAnimTrackDecoder(animFile);

            foreach (AnimNode animNode in animGroup.Nodes)
            {
                foreach (AnimTrack track in animNode.Tracks)
                {
                    SBMaterialAnimation matAnim = new SBMaterialAnimation()
                    {
                        MaterialName  = animNode.Name,
                        AttributeName = track.Name
                    };
                    object[] MaterialAnim = decoder.ReadTrack(track);

                    // only get vectors for now
                    if (MaterialAnim == null || MaterialAnim.Length == 0 || MaterialAnim[0] == null || MaterialAnim[0].GetType() != typeof(AnimTrackCustomVector4))
                    {
                        continue;
                    }
                    animation.MaterialNodes.Add(matAnim);
                    for (int i = 0; i < MaterialAnim.Length; i++)
                    {
                        var vec = (AnimTrackCustomVector4)MaterialAnim[i];
                        matAnim.Keys.AddKey(i, new Vector4(vec.X, vec.Y, vec.Z, vec.W));
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="animation"></param>
        /// <param name="skeleton"></param>
        private void ExportAnimJoint(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            HSDRawFile  file = new HSDRawFile();
            HSDRootNode root = new HSDRootNode();

            if (HSDSettings.RootName == "" || HSDSettings.RootName == null)
            {
                HSDSettings.RootName = System.IO.Path.GetFileNameWithoutExtension(FileName);
            }

            if (HSDSettings.RootName == "" || HSDSettings.RootName == null)
            {
                HSDSettings.RootName = animation.Name;
            }

            root.Name = HSDSettings.RootName;

            if (root.Name == null)
            {
                System.Windows.Forms.MessageBox.Show($"Warning, the root name does not end with \"_figatree\"\n{root.Name}");
            }

            file.Roots.Add(root);

            var joint = new HSD_AnimJoint();

            EncodeAnimJoint(skeleton.Bones[0], joint, animation);
            root.Data = joint;

            file.Save(FileName);
        }
Example #3
0
        private void ReadVisibilityAnimations(Anim animFile, AnimGroup animGroup, SBAnimation animation)
        {
            var decoder = new SsbhAnimTrackDecoder(animFile);

            foreach (AnimNode animNode in animGroup.Nodes)
            {
                SBVisibilityAnimation visAnim = new SBVisibilityAnimation()
                {
                    MeshName = animNode.Name
                };
                foreach (AnimTrack track in animNode.Tracks)
                {
                    if (track.Name.Equals("Visibility"))
                    {
                        object[] Visibility = decoder.ReadTrack(track);

                        for (int i = 0; i < Visibility.Length; i++)
                        {
                            visAnim.Visibility.AddKey(i, (bool)Visibility[i]);
                        }
                    }
                }
                animation.VisibilityNodes.Add(visAnim);
            }
        }
Example #4
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            SBAnimation anim = new SBAnimation();

            SsbhFile File;

            if (Ssbh.TryParseSsbhFile(FileName, out File))
            {
                if (File is Anim animation)
                {
                    anim.Name       = animation.Name;
                    anim.FrameCount = animation.FinalFrameIndex + 1;

                    foreach (var group in animation.Animations)
                    {
                        if (group.Type == AnimType.Visibility)
                        {
                            ReadVisibilityAnimations(animation, group, anim);
                        }
                        if (group.Type == AnimType.Transform)
                        {
                            ReadTransformAnimations(animation, group, anim);
                        }
                        if (group.Type == AnimType.Material)
                        {
                            ReadMaterialAnimations(animation, group, anim);
                        }
                    }
                }
            }

            return(anim);
        }
Example #5
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            SBAnimation anim = new SBAnimation();

            ISSBH_File File;

            if (SSBH.TryParseSSBHFile(FileName, out File))
            {
                if (File is ANIM animation)
                {
                    anim.Name       = animation.Name;
                    anim.FrameCount = animation.FrameCount;

                    foreach (var group in animation.Animations)
                    {
                        if (group.Type == ANIM_TYPE.Visibilty)
                        {
                            ReadVisibilityAnimations(animation, group, anim);
                        }
                        if (group.Type == ANIM_TYPE.Transform)
                        {
                            ReadTransformAnimations(animation, group, anim);
                        }
                        if (group.Type == ANIM_TYPE.Material)
                        {
                            ReadMaterialAnimations(animation, group, anim);
                        }
                    }
                }
            }

            return(anim);
        }
Example #6
0
        private void ReadTransformAnimations(ANIM animFile, AnimGroup animGroup, SBAnimation animation)
        {
            var decoder = new SSBHAnimTrackDecoder(animFile);

            foreach (AnimNode animNode in animGroup.Nodes)
            {
                SBTransformAnimation tfrmAnim = new SBTransformAnimation()
                {
                    Name = animNode.Name
                };
                foreach (AnimTrack track in animNode.Tracks)
                {
                    object[] Transform = decoder.ReadTrack(track);

                    if (track.Name.Equals("Transform"))
                    {
                        for (int i = 0; i < Transform.Length; i++)
                        {
                            AnimTrackTransform t = (AnimTrackTransform)Transform[i];
                            tfrmAnim.Transform.Keys.Add(new SBAnimKey <Matrix4>()
                            {
                                Frame = i,
                                Value = GetMatrix((AnimTrackTransform)Transform[i]),
                            });
                        }
                    }
                }
                animation.TransformNodes.Add(tfrmAnim);
            }
        }
Example #7
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="FileName"></param>
 /// <param name="animation"></param>
 /// <param name="skeleton"></param>
 public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
 {
     if (HSDSettings.FigaTree)
     {
         ExportFigaTree(FileName, animation, skeleton);
     }
     else
     {
         ExportAnimJoint(FileName, animation, skeleton);
     }
 }
Example #8
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            IO_MayaANIM anim = new IO_MayaANIM();

            anim.Open(FileName);

            var animation = new SBAnimation();

            animation.Name       = Path.GetFileNameWithoutExtension(FileName);
            animation.FrameCount = anim.header.endTime - 1;

            foreach (var node in anim.Bones)
            {
                SBTransformAnimation a = new SBTransformAnimation();
                a.Name = node.name;
                animation.TransformNodes.Add(a);

                foreach (var att in node.atts)
                {
                    if (!trackTypeConversion.ContainsKey(att.type))
                    {
                        continue;
                    }

                    SBTransformTrack track = new SBTransformTrack(trackTypeConversion[att.type]);
                    a.Tracks.Add(track);

                    foreach (var key in att.keys)
                    {
                        InterpolationType itype  = InterpolationType.Linear;
                        float             intan  = 0;
                        float             outtan = 0;
                        if (key.intan == "fixed")
                        {
                            itype = InterpolationType.Hermite;
                            intan = key.t1;
                        }
                        if (key.outtan == "fixed")
                        {
                            itype  = InterpolationType.Hermite;
                            outtan = key.t2;
                        }
                        track.AddKey(key.input - header.startTime,
                                     GetOutputValue(anim, att, key.output),
                                     itype,
                                     intan
                                     , outtan);
                    }
                }
            }

            return(animation);
        }
Example #9
0
        public static void ExportIOAnimationAsANIM(string fname, SBAnimation animation, SBSkeleton Skeleton, bool ordinal = false)
        {
            IO_MayaANIM anim = new IO_MayaANIM();

            anim.header.endTime = animation.FrameCount + 1;

            // get bone order
            List <SBBone> BonesInOrder = getBoneTreeOrder(Skeleton);

            if (ordinal)
            {
                BonesInOrder = BonesInOrder.OrderBy(f => f.Name, StringComparer.Ordinal).ToList();
            }

            foreach (SBBone b in BonesInOrder)
            {
                AnimBone animBone = new AnimBone()
                {
                    name = b.Name
                };
                anim.Bones.Add(animBone);
                // Add Tracks
                SBTransformAnimation node = null;
                foreach (var animNode in animation.TransformNodes)
                {
                    if (animNode.Name.Equals(b.Name))
                    {
                        node = animNode;
                        break;
                    }
                }
                if (node == null)
                {
                    continue;
                }

                AddAnimData(animBone, node.Transform, ControlType.translate, TrackType.translateX);
                AddAnimData(animBone, node.Transform, ControlType.translate, TrackType.translateY);
                AddAnimData(animBone, node.Transform, ControlType.translate, TrackType.translateZ);

                AddAnimData(animBone, node.Transform, ControlType.rotate, TrackType.rotateX);
                AddAnimData(animBone, node.Transform, ControlType.rotate, TrackType.rotateY);
                AddAnimData(animBone, node.Transform, ControlType.rotate, TrackType.rotateZ);

                AddAnimData(animBone, node.Transform, ControlType.scale, TrackType.scaleX);
                AddAnimData(animBone, node.Transform, ControlType.scale, TrackType.scaleY);
                AddAnimData(animBone, node.Transform, ControlType.scale, TrackType.scaleZ);
            }


            anim.Save(fname);
        }
Example #10
0
        private void ReadTransformAnimations(Anim animFile, AnimGroup animGroup, SBAnimation animation)
        {
            var decoder = new SsbhAnimTrackDecoder(animFile);

            foreach (AnimNode animNode in animGroup.Nodes)
            {
                SBTransformAnimation tfrmAnim = new SBTransformAnimation()
                {
                    Name = animNode.Name
                };
                SBTransformTrack X  = new SBTransformTrack(SBTrackType.TranslateX);
                SBTransformTrack Y  = new SBTransformTrack(SBTrackType.TranslateY);
                SBTransformTrack Z  = new SBTransformTrack(SBTrackType.TranslateZ);
                SBTransformTrack RX = new SBTransformTrack(SBTrackType.RotateX);
                SBTransformTrack RY = new SBTransformTrack(SBTrackType.RotateY);
                SBTransformTrack RZ = new SBTransformTrack(SBTrackType.RotateZ);
                SBTransformTrack SX = new SBTransformTrack(SBTrackType.ScaleX);
                SBTransformTrack SY = new SBTransformTrack(SBTrackType.ScaleY);
                SBTransformTrack SZ = new SBTransformTrack(SBTrackType.ScaleZ);
                SBTransformTrack CompensateScale = new SBTransformTrack(SBTrackType.CompensateScale);
                tfrmAnim.Tracks.AddRange(new SBTransformTrack[] { X, Y, Z, RX, RY, RZ, SX, SY, SZ, CompensateScale });

                foreach (AnimTrack track in animNode.Tracks)
                {
                    object[] Transform = decoder.ReadTrack(track);

                    if (track.Name.Equals("Transform"))
                    {
                        for (int i = 0; i < Transform.Length; i++)
                        {
                            AnimTrackTransform t = (AnimTrackTransform)Transform[i];

                            SBBone transform = new SBBone();
                            transform.Transform = GetMatrix((AnimTrackTransform)Transform[i]);
                            X.AddKey(i, transform.X);
                            Y.AddKey(i, transform.Y);
                            Z.AddKey(i, transform.Z);
                            RX.AddKey(i, transform.RX);
                            RY.AddKey(i, transform.RY);
                            RZ.AddKey(i, transform.RZ);
                            SX.AddKey(i, transform.SX);
                            SY.AddKey(i, transform.SY);
                            SZ.AddKey(i, transform.SZ);
                            CompensateScale.AddKey(i, t.CompensateScale);
                        }
                    }
                }
                animation.TransformNodes.Add(tfrmAnim);
            }
        }
Example #11
0
        public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            SMD file = new SMD();

            var bonelist = new List <SBBone>(skeleton.Bones);

            foreach (var bone in bonelist)
            {
                file.nodes.Add(new SMDNode()
                {
                    Name = bone.Name, ID = bonelist.IndexOf(bone), ParentID = bonelist.IndexOf(bone.Parent)
                });
            }

            for (int i = 0; i < animation.FrameCount; i++)
            {
                var group = new SMDSkeletonFrame();
                group.time = i;
                file.skeleton.Add(group);

                foreach (var bone in bonelist)
                {
                    bool found = false;
                    foreach (var animbone in animation.TransformNodes)
                    {
                        if (animbone.Name.Equals(bone.Name))
                        {
                            var tempBone = new SBBone();
                            tempBone.Transform = animbone.GetTransformAt(i, skeleton);
                            group.skeletons.Add(new SMDSkeleton()
                            {
                                BoneID = bonelist.IndexOf(bone), Position = tempBone.Translation, Rotation = tempBone.RotationEuler
                            });
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        group.skeletons.Add(new SMDSkeleton()
                        {
                            BoneID = bonelist.IndexOf(bone), Position = bone.Translation, Rotation = bone.RotationEuler
                        });
                    }
                }
            }

            file.Save(FileName);
        }
Example #12
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            SMD smd = new SMD();

            smd.Open(FileName);

            SBAnimation animation = new SBAnimation();

            animation.Name = Path.GetFileNameWithoutExtension(FileName);
            Dictionary <int, SBTransformAnimation> idToAnim = new Dictionary <int, SBTransformAnimation>();

            foreach (var node in smd.nodes)
            {
                var nodeAnim = new SBTransformAnimation()
                {
                    Name = node.Name
                };
                idToAnim.Add(node.ID, nodeAnim);

                animation.TransformNodes.Add(nodeAnim);
            }

            var frameCount = 0;

            foreach (var v in smd.skeleton)
            {
                frameCount = Math.Max(v.time, frameCount);
                foreach (var node in v.skeletons)
                {
                    var animNode = idToAnim[node.BoneID];

                    animNode.AddKey(v.time, node.Position.X, SBTrackType.TranslateX);
                    animNode.AddKey(v.time, node.Position.Y, SBTrackType.TranslateY);
                    animNode.AddKey(v.time, node.Position.Z, SBTrackType.TranslateZ);
                    animNode.AddKey(v.time, node.Rotation.X, SBTrackType.RotateX);
                    animNode.AddKey(v.time, node.Rotation.Y, SBTrackType.RotateY);
                    animNode.AddKey(v.time, node.Rotation.Z, SBTrackType.RotateZ);
                }
            }

            animation.FrameCount = frameCount;

            return(animation);
        }
Example #13
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="animation"></param>
        /// <param name="skeleton"></param>
        public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            SEAnim seOut = new SEAnim();                   //init new SEAnim

            foreach (var node in animation.TransformNodes) //iterate through each node
            {
                for (int i = 0; i < animation.FrameCount; i++)
                {
                    SBBone temp = new SBBone();

                    temp.Transform = node.GetTransformAt(i, skeleton);

                    seOut.AddTranslationKey(node.Name, i, temp.X, temp.Y, temp.Z);
                    seOut.AddRotationKey(node.Name, i, temp.RotationQuaternion.X, temp.RotationQuaternion.Y, temp.RotationQuaternion.Z, temp.RotationQuaternion.W);
                    seOut.AddScaleKey(node.Name, i, temp.SX, temp.SY, temp.SZ);
                }
            }

            seOut.Write(FileName); //write it!
        }
Example #14
0
        public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            using (StreamWriter w = new StreamWriter(new FileStream(FileName, FileMode.Create)))
            {
                w.WriteLine("#SBAnimation Version 1");

                w.WriteLine($"FrameCount {animation.FrameCount}");

                foreach (var visNode in animation.VisibilityNodes)
                {
                    w.WriteLine($"visibility {visNode.MeshName}");
                    w.WriteLine("{");
                    bool prev = false;
                    foreach (var key in visNode.Visibility.Keys)
                    {
                        if (key.Frame == 0 || prev != key.Value)
                        {
                            w.WriteLine($"{key.Frame} : {key.Value}");
                        }
                        prev = key.Value;
                    }
                    w.WriteLine("}");
                }

                foreach (var matNode in animation.MaterialNodes)
                {
                    w.WriteLine($"material {matNode.MaterialName} {matNode.AttributeName}");
                    w.WriteLine("{");
                    Vector4 prev = Vector4.Zero;
                    foreach (var key in matNode.Keys.Keys)
                    {
                        if (key.Frame == 0 || prev != key.Value)
                        {
                            w.WriteLine($"{key.Frame} : {key.Value.ToString()}");
                        }
                        prev = key.Value;
                    }
                    w.WriteLine("}");
                }
            }
        }
Example #15
0
        public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            SEAnim seOut = new SEAnim();                   //init new SEAnim

            foreach (var node in animation.TransformNodes) //iterate through each node
            {
                for (int i = 0; i < animation.FrameCount; i++)
                {
                    SBBone temp = new SBBone();
                    temp.Transform = node.Transform.GetValue(i);

                    OpenTK.Vector3    pos = temp.Translation;
                    OpenTK.Quaternion rot = temp.RotationQuaternion;
                    OpenTK.Vector3    sca = temp.Scale;

                    seOut.AddTranslationKey(node.Name, i, pos.X, pos.Y, pos.Z);
                    seOut.AddRotationKey(node.Name, i, rot.X, rot.Y, rot.Z, rot.W);
                    seOut.AddScaleKey(node.Name, i, sca.X, sca.Y, sca.Z);
                }
            }

            seOut.Write(FileName); //write it!
        }
Example #16
0
        public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            // The final frame index is one less than the number of frames.
            // Empty animations have a final frame index of 1, so clamp to 1.
            int finalFrameIndex          = Math.Max((int)animation.FrameCount - 1, 1);
            SsbhAnimTrackEncoder encoder = new SsbhAnimTrackEncoder(finalFrameIndex);

            encoder.CompressVector4 = ExportSettings.CompressVector4;
            encoder.SetCompressionLevel(ExportSettings.CompressionLevel);

            var animNodes = animation.TransformNodes.OrderBy(e => e.Name, StringComparer.Ordinal);

            foreach (var node in animNodes)
            {
                if (node.Name.StartsWith("H_") || node.Name.EndsWith("_null")) // skip helper bones and null swing bones
                {
                    continue;
                }

                List <object> transforms = new List <object>();

                for (int i = 0; i < animation.FrameCount; i++)
                {
                    transforms.Add(MatrixToTransform(node.GetTransformAt(i, skeleton)));
                }

                encoder.AddTrack(node.Name, "Transform", AnimType.Transform, transforms);
            }


            var visNodes = animation.VisibilityNodes.OrderBy(e => e.MeshName, StringComparer.Ordinal);

            foreach (var node in visNodes)
            {
                List <object> visibilities = new List <object>();
                bool          AllSame      = true;
                bool          first        = node.Visibility.GetValue(0);
                for (int i = 0; i < animation.FrameCount; i++)
                {
                    visibilities.Add(node.Visibility.GetValue(i));
                    if (AllSame && node.Visibility.GetValue(i) != first)
                    {
                        AllSame = false;
                    }
                }
                if (AllSame)
                {
                    visibilities.Clear();
                    visibilities.Add(first);
                }
                encoder.AddTrack(node.MeshName, "Visibility", AnimType.Visibility, visibilities);
            }

            var matNodes = animation.MaterialNodes.OrderBy(e => e.MaterialName, StringComparer.Ordinal);

            foreach (var mat in  matNodes)
            {
                var     list    = new List <object>();
                bool    AllSame = true;
                Vector4 first   = mat.Keys.GetValue(0);
                for (int i = 0; i < animation.FrameCount; i++)
                {
                    var value = mat.Keys.GetValue(i);
                    list.Add(new AnimTrackCustomVector4(value.X, value.Y, value.Z, value.W));
                    if (AllSame && mat.Keys.GetValue(i) != first)
                    {
                        AllSame = false;
                    }
                }
                if (AllSame)
                {
                    list.Clear();
                    list.Add(new AnimTrackCustomVector4(first.X, first.Y, first.Z, first.W));
                }
                encoder.AddTrack(mat.MaterialName, mat.AttributeName, AnimType.Material, list);
            }

            try
            {
                encoder.Save(FileName);
            } catch (Exception)
            {
                System.Windows.Forms.MessageBox.Show("Error creating Anim file: try using a larger compression level");
            }
        }
Example #17
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            SBAnimation anim = new SBAnimation();

            HSDRawFile f = new HSDRawFile(FileName);

            foreach (var root in f.Roots)
            {
                if (root == null || root.Data == null)
                {
                    continue;
                }
                anim.Name = root.Name;
                if (root.Data is HSD_AnimJoint joint)
                {
                    var joints = joint.BreathFirstList;

                    int nodeIndex = -1;
                    foreach (var j in joints)
                    {
                        nodeIndex++;
                        if (j.AOBJ == null || j.AOBJ.FObjDesc == null)
                        {
                            continue;
                        }

                        SBConsole.WriteLine(nodeIndex + " " + j.Flags.ToString("X8") + " " + j.AOBJ.Flags.ToString());

                        SBTransformAnimation a = new SBTransformAnimation();
                        if (nodeIndex < skeleton.Bones.Length)
                        {
                            a.Name = skeleton.Bones[nodeIndex].Name;
                        }
                        else
                        {
                            a.Name = "JOBJ_" + nodeIndex;
                        }
                        anim.TransformNodes.Add(a);

                        anim.FrameCount = Math.Max(anim.FrameCount, j.AOBJ.EndFrame);

                        foreach (var fobj in j.AOBJ.FObjDesc.List)
                        {
                            a.Tracks.Add(DecodeFOBJ(fobj.ToFOBJ()));
                        }
                    }
                }
                if (root.Data is HSD_FigaTree tree)
                {
                    anim.FrameCount = tree.FrameCount;
                    int nodeIndex = 0;
                    foreach (var node in tree.Nodes)
                    {
                        SBTransformAnimation a = new SBTransformAnimation();
                        a.Name = skeleton.Bones[nodeIndex++].Name;
                        anim.TransformNodes.Add(a);

                        foreach (var att in node.Tracks)
                        {
                            if (att.FOBJ == null)
                            {
                                continue;
                            }

                            a.Tracks.Add(DecodeFOBJ(att.FOBJ));
                        }
                    }
                }
                if (root.Data is HSD_MatAnimJoint matjoint)
                {
                    var joints = matjoint.BreathFirstList;

                    anim.FrameCount = 0;

                    int nodeIndex = -1;
                    foreach (var j in joints)
                    {
                        if (j.MaterialAnimation == null)
                        {
                            continue;
                        }

                        var matAnims = j.MaterialAnimation.List;

                        foreach (var manim in matAnims)
                        {
                            nodeIndex++;
                            var aobj = manim.AnimationObject;
                            if (aobj != null)
                            {
                                anim.FrameCount = Math.Max(anim.FrameCount, aobj.EndFrame);
                            }

                            var texanim = manim.TextureAnimation;

                            if (texanim == null)
                            {
                                continue;
                            }
                            var texAOBJ = texanim.AnimationObject;

                            if (texAOBJ == null || texAOBJ.FObjDesc == null)
                            {
                                continue;
                            }

                            anim.FrameCount = Math.Max(anim.FrameCount, texAOBJ.EndFrame);

                            //TODO: tex anim is a list
                            if (texanim != null)
                            {
                                SBTextureAnimation textureAnim = new SBTextureAnimation();
                                anim.TextureNodes.Add(textureAnim);
                                textureAnim.MeshName        = "DOBJ_" + nodeIndex;
                                textureAnim.TextureAttibute = texanim.GXTexMapID.ToString();

                                textureAnim.Keys = DecodeFOBJ(texAOBJ.FObjDesc.ToFOBJ()).Keys;

                                for (int i = 0; i < texanim.ImageCount; i++)
                                {
                                    HSD_TOBJ tobj = new HSD_TOBJ();
                                    tobj.ImageData = texanim.ImageBuffers.Array[i].Data;
                                    if (texanim.TlutCount > i)
                                    {
                                        tobj.TlutData = texanim.TlutBuffers.Array[i].Data;
                                    }
                                    var surface = new SBSurface();
                                    surface.Arrays.Add(new MipArray()
                                    {
                                        Mipmaps = new List <byte[]>()
                                        {
                                            tobj.GetDecodedImageData()
                                        }
                                    });
                                    surface.Width          = tobj.ImageData.Width;
                                    surface.Height         = tobj.ImageData.Height;
                                    surface.PixelFormat    = PixelFormat.Bgra;
                                    surface.PixelType      = PixelType.UnsignedByte;
                                    surface.InternalFormat = InternalFormat.Rgba;
                                    textureAnim.Surfaces.Add(surface);
                                }
                            }
                        }
                    }

                    SBConsole.WriteLine(nodeIndex);
                }
            }

            return(anim);
        }
Example #18
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="animation"></param>
        /// <param name="skeleton"></param>
        private void ExportFigaTree(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            HSDRawFile  file = new HSDRawFile();
            HSDRootNode root = new HSDRootNode();

            if (HSDSettings.RootName == "" || HSDSettings.RootName == null)
            {
                HSDSettings.RootName = System.IO.Path.GetFileNameWithoutExtension(FileName);
            }

            if (HSDSettings.RootName == "" || HSDSettings.RootName == null)
            {
                HSDSettings.RootName = animation.Name;
            }

            root.Name = HSDSettings.RootName;

            if (root.Name == null || !root.Name.EndsWith("_figatree"))
            {
                System.Windows.Forms.MessageBox.Show($"Warning, the root name does not end with \"_figatree\"\n{root.Name}");
            }

            file.Roots.Add(root);

            var nodes = new List <FigaTreeNode>();

            int boneIndex = -1;

            foreach (var skelnode in skeleton.Bones)
            {
                FigaTreeNode animNode = new FigaTreeNode();
                nodes.Add(animNode);

                boneIndex++;
                // skip trans n and rotn tracks
                if (boneIndex == 0)
                {
                    continue;
                }

                var node = animation.TransformNodes.Find(e => e.Name == skelnode.Name);
                if (node == null)
                {
                    continue;
                }

                foreach (var track in node.Tracks)
                {
                    HSD_Track animTrack = new HSD_Track();
                    animTrack.FOBJ       = EncodeFOBJ(track);
                    animTrack.DataLength = (short)animTrack.FOBJ.Buffer.Length;
                    animNode.Tracks.Add(animTrack);
                }
            }

            HSD_FigaTree tree = new HSD_FigaTree();

            tree.FrameCount = animation.FrameCount;
            tree.Type       = 1;
            tree.Nodes      = nodes;

            root.Data = tree;
            file.Save(FileName);
        }
Example #19
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="skeleton"></param>
        /// <returns></returns>
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            SEAnim anim = SEAnim.Read(FileName);

            var sbAnim = new SBAnimation();

            sbAnim.FrameCount = anim.FrameCount;
            sbAnim.Name       = anim.DeltaTagName;

            Dictionary <string, SBTransformAnimation> nameToAnim = new Dictionary <string, SBTransformAnimation>();

            foreach (var v in anim.AnimationPositionKeys)
            {
                if (!nameToAnim.ContainsKey(v.Key))
                {
                    SBTransformAnimation an = new SBTransformAnimation();
                    an.Name = v.Key;
                    nameToAnim.Add(v.Key, an);
                    sbAnim.TransformNodes.Add(an);
                }

                var a = nameToAnim[v.Key];

                foreach (var k in v.Value)
                {
                    if (k.Data is SELib.Utilities.Vector2 vc)
                    {
                        a.AddKey(k.Frame, (float)vc.X, SBTrackType.TranslateX, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc.Y, SBTrackType.TranslateY, InterpolationType.Linear);
                    }
                    if (k.Data is SELib.Utilities.Vector3 vc3)
                    {
                        a.AddKey(k.Frame, (float)vc3.X, SBTrackType.TranslateX, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc3.Y, SBTrackType.TranslateY, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc3.Z, SBTrackType.TranslateZ, InterpolationType.Linear);
                    }
                }
            }

            foreach (var v in anim.AnimationRotationKeys)
            {
                if (!nameToAnim.ContainsKey(v.Key))
                {
                    SBTransformAnimation an = new SBTransformAnimation();
                    an.Name = v.Key;
                    nameToAnim.Add(v.Key, an);
                    sbAnim.TransformNodes.Add(an);
                }

                var a = nameToAnim[v.Key];

                foreach (var k in v.Value)
                {
                    if (k.Data is SELib.Utilities.Quaternion q)
                    {
                        var euler = Tools.CrossMath.ToEulerAngles(new OpenTK.Quaternion((float)q.X, (float)q.Y, (float)q.Z, (float)q.W).Inverted());

                        a.AddKey(k.Frame, (float)q.X, SBTrackType.RotateX, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)q.Y, SBTrackType.RotateY, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)q.Z, SBTrackType.RotateZ, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)q.W, SBTrackType.RotateW, InterpolationType.Linear);
                    }
                    if (k.Data is SELib.Utilities.Vector3 vc)
                    {
                        a.AddKey(k.Frame, (float)vc.X, SBTrackType.RotateX, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc.Y, SBTrackType.RotateY, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc.Z, SBTrackType.RotateZ, InterpolationType.Linear);
                    }
                }
            }


            foreach (var v in anim.AnimationScaleKeys)
            {
                if (!nameToAnim.ContainsKey(v.Key))
                {
                    SBTransformAnimation an = new SBTransformAnimation();
                    an.Name = v.Key;
                    nameToAnim.Add(v.Key, an);
                    sbAnim.TransformNodes.Add(an);
                }

                var a = nameToAnim[v.Key];

                foreach (var k in v.Value)
                {
                    if (k.Data is SELib.Utilities.Vector3 vc3)
                    {
                        a.AddKey(k.Frame, (float)vc3.X, SBTrackType.ScaleX, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc3.Y, SBTrackType.ScaleY, InterpolationType.Linear);
                        a.AddKey(k.Frame, (float)vc3.Z, SBTrackType.ScaleZ, InterpolationType.Linear);
                    }
                }
            }

            return(sbAnim);
        }
Example #20
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="animation"></param>
 /// <param name="outputPath"></param>
 /// <param name="skeleton"></param>
 /// <param name="animType"></param>
 public static void ConvertAnim(SBAnimation animation, string outputPath, SBSkeleton skeleton, IExportableAnimation animType)
 {
     animType.ExportSBAnimation(outputPath, animation, skeleton);
 }
Example #21
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="animation"></param>
        /// <param name="skeleton"></param>
        public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
        {
            var jointTable = GetJointTable(Settings.JVCPath).ToList();

            Anim a = new Anim();

            a.EndTime   = animation.FrameCount / Settings.FrameScale;
            a.PlaySpeed = 0.01f;

            a.Joints.Add(new Joint()
            {
                BoneID  = -1,
                Flag3   = 0x40,
                MaxTime = a.EndTime,
            });

            List <double> AllKeys = new List <double>();

            foreach (var v in animation.TransformNodes)
            {
                if (skeleton[v.Name] == null)
                {
                    continue;
                }

                var sb = skeleton[v.Name];
                if (sb == null)
                {
                    continue;
                }

                var index = (short)jointTable.IndexOf((short)skeleton.IndexOfBone(sb));

                Console.WriteLine(v.Name + " " + index);

                if (index == -1)
                {
                    continue;
                }

                Joint Position = null;
                Joint Rotation = null;
                Joint Scale    = null;

                if (v.HasTranslation)
                {
                    Position = new Joint();
                    var j = Position;
                    j.Flag1   = 0x02;
                    j.Flag2   = 0x02;
                    j.Flag3   = 0x21;
                    j.BoneID  = index;
                    j.MaxTime = a.EndTime;
                }
                if (v.HasRotation)
                {
                    Rotation = new Joint();
                    var j = Rotation;
                    j.Flag1   = 0x02;
                    j.Flag2   = 0x02;
                    j.Flag3   = 0x28;
                    j.BoneID  = index;
                    j.MaxTime = a.EndTime;
                }
                if (v.HasScale)
                {
                    Scale = new Joint();
                    var j = Scale;
                    j.Flag1   = 0x02;
                    j.Flag2   = 0x02;
                    j.Flag3   = 0x22;
                    j.BoneID  = index;
                    j.MaxTime = a.EndTime;
                }

                // gather baked nodes
                List <Vector3> Positions = new List <Vector3>();
                List <Vector4> Rotations = new List <Vector4>();
                List <Vector3> Scales    = new List <Vector3>();
                for (int i = 0; i <= animation.FrameCount; i++)
                {
                    var t = v.GetTransformAt(i, skeleton);

                    if (v.HasTranslation)
                    {
                        Positions.Add(t.ExtractTranslation() - sb.Translation);
                    }

                    if (v.HasScale)
                    {
                        Positions.Add(t.ExtractScale() - sb.Scale);
                    }

                    if (v.HasRotation)
                    {
                        var quat = (t.ExtractRotation().Inverted() * sb.RotationQuaternion).Inverted();

                        var inv = new Quaternion(quat.X, 0, 0, quat.W).Normalized().Inverted();

                        var dir   = Vector3.TransformNormal(Vector3.UnitX, Matrix4.CreateFromQuaternion(quat * inv));
                        var angle = Tools.CrossMath.ToEulerAngles(inv).X * 180 / (float)Math.PI;

                        Rotations.Add(new Vector4(dir, angle));
                    }
                }

                // now we convert the bake nodes into linear tracks in the new time scale range
                if (Positions.Count > 0)
                {
                    var X = SimplifyLines(Positions.Select(e => e.X));
                    var Y = SimplifyLines(Positions.Select(e => e.Y));
                    var Z = SimplifyLines(Positions.Select(e => e.Z));

                    var frames = X.Select(e => e.Item1).Union(Y.Select(e => e.Item1).Union(Z.Select(e => e.Item1))).ToList();
                    frames.Sort();
                    if (frames[frames.Count - 1] != animation.FrameCount)
                    {
                        frames.Add(animation.FrameCount);
                    }

                    AllKeys = AllKeys.Union(frames).ToList();

                    foreach (var f in frames)
                    {
                        Position.Keys.Add(new Key()
                        {
                            Time = (float)f / Settings.FrameScale,
                            X    = Positions[(int)f].X,
                            Y    = Positions[(int)f].Y,
                            Z    = Positions[(int)f].Z,
                            W    = 0
                        });
                    }
                }
                if (Rotations.Count > 0)
                {
                    var X = SimplifyLines(Rotations.Select(e => e.X));
                    var Y = SimplifyLines(Rotations.Select(e => e.Y));
                    var Z = SimplifyLines(Rotations.Select(e => e.Z));
                    var W = SimplifyLines(Rotations.Select(e => e.W));

                    var frames = X.Select(e => e.Item1).Union(Y.Select(e => e.Item1).Union(Z.Select(e => e.Item1))).Union(W.Select(e => e.Item1)).ToList();
                    frames.Sort();
                    if (frames[frames.Count - 1] != animation.FrameCount)
                    {
                        frames.Add(animation.FrameCount);
                    }

                    AllKeys = AllKeys.Union(frames).ToList();

                    foreach (var f in frames)
                    {
                        Rotation.Keys.Add(new Key()
                        {
                            Time = (float)f / Settings.FrameScale,
                            X    = Rotations[(int)f].X,
                            Y    = Rotations[(int)f].Y,
                            Z    = Rotations[(int)f].Z,
                            W    = Rotations[(int)f].W,
                        });
                    }
                }

                if (Position != null)
                {
                    a.Joints.Add(Position);
                }
                if (Rotation != null)
                {
                    a.Joints.Add(Rotation);
                }
                if (Scale != null)
                {
                    a.Joints.Add(Scale);
                }
            }

            AllKeys.Sort();

            foreach (var v in AllKeys)
            {
                a.Joints[0].Keys.Add(new Key()
                {
                    Time = (float)v / Settings.FrameScale
                });
            }

            a.Save(FileName);
        }
Example #22
0
 public SBAnimAttachment(SBAnimation animation)
 {
     this.animation = animation;
 }
Example #23
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="bone"></param>
        /// <param name="joint"></param>
        /// <param name="animation"></param>
        private void EncodeAnimJoint(SBBone bone, HSD_AnimJoint joint, SBAnimation animation)
        {
            var node = animation.TransformNodes.Find(e => e.Name == bone.Name);

            if (node != null)
            {
                // encode tracks
                joint.Flags         = 1;
                joint.AOBJ          = new HSD_AOBJ();
                joint.AOBJ.EndFrame = animation.FrameCount;
                joint.AOBJ.Flags    = AOBJ_Flags.ANIM_LOOP;

                if (!HSDSettings.LoopAnimation)
                {
                    joint.AOBJ.Flags = AOBJ_Flags.FIRST_PLAY;
                }

                if (node.Tracks.Count == 0)
                {
                    joint.AOBJ.Flags = AOBJ_Flags.NO_ANIM;
                }

                var prev = new HSD_FOBJDesc();

                foreach (var track in node.Tracks)
                {
                    var fobjdesc = new HSD_FOBJDesc();
                    fobjdesc.FromFOBJ(EncodeFOBJ(track));
                    fobjdesc.DataLength = fobjdesc.ToFOBJ().Buffer.Length;

                    if (joint.AOBJ.FObjDesc == null)
                    {
                        joint.AOBJ.FObjDesc = fobjdesc;
                    }
                    else
                    {
                        prev.Next = fobjdesc;
                    }

                    prev = fobjdesc;
                }
            }

            // continue adding children
            var prevChild = new HSD_AnimJoint();

            foreach (var c in bone.Children)
            {
                HSD_AnimJoint child = new HSD_AnimJoint();
                EncodeAnimJoint(c, child, animation);
                if (joint.Child == null)
                {
                    joint.Child = child;
                }
                else
                {
                    prevChild.Next = child;
                }
                prevChild = child;
            }
        }
Example #24
0
 public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
 {
     ExportIOAnimationAsANIM(FileName, animation, skeleton);
 }
Example #25
0
        public static void ExportIOAnimationAsANIM(string fname, SBAnimation animation, SBSkeleton Skeleton)
        {
            IO_MayaANIM anim = new IO_MayaANIM();

            anim.header.endTime = animation.FrameCount + 1;
            if (!MayaSettings.UseRadians)
            {
                anim.header.angularUnit = "deg";
            }

            // get bone order
            List <SBBone> BonesInOrder = getBoneTreeOrder(Skeleton);

            if (MayaSettings.Maya2015)
            {
                BonesInOrder = BonesInOrder.OrderBy(f => f.Name, StringComparer.Ordinal).ToList();
            }

            if (MayaSettings.RemoveRedundantFrames)
            {
                animation.Optimize();
            }

            foreach (SBBone b in BonesInOrder)
            {
                AnimBone animBone = new AnimBone()
                {
                    name = b.Name
                };
                anim.Bones.Add(animBone);
                // Add Tracks
                SBTransformAnimation node = null;
                foreach (var animNode in animation.TransformNodes)
                {
                    if (animNode.Name.Equals(b.Name))
                    {
                        node = animNode;
                        break;
                    }
                }
                if (node == null)
                {
                    continue;
                }

                //TODO: bake scale for compensate scale...

                foreach (var track in node.Tracks)
                {
                    switch (track.Type)
                    {
                    case SBTrackType.TranslateX:
                        AddAnimData(animBone, track.Keys, ControlType.translate, TrackType.translateX);
                        break;

                    case SBTrackType.TranslateY:
                        AddAnimData(animBone, track.Keys, ControlType.translate, TrackType.translateY);
                        break;

                    case SBTrackType.TranslateZ:
                        AddAnimData(animBone, track.Keys, ControlType.translate, TrackType.translateZ);
                        break;

                    case SBTrackType.RotateX:
                        AddAnimData(animBone, track.Keys, ControlType.rotate, TrackType.rotateX);
                        break;

                    case SBTrackType.RotateY:
                        AddAnimData(animBone, track.Keys, ControlType.rotate, TrackType.rotateY);
                        break;

                    case SBTrackType.RotateZ:
                        AddAnimData(animBone, track.Keys, ControlType.rotate, TrackType.rotateZ);
                        break;

                    case SBTrackType.ScaleX:
                        AddAnimData(animBone, track.Keys, ControlType.scale, TrackType.scaleX);
                        break;

                    case SBTrackType.ScaleY:
                        AddAnimData(animBone, track.Keys, ControlType.scale, TrackType.scaleY);
                        break;

                    case SBTrackType.ScaleZ:
                        AddAnimData(animBone, track.Keys, ControlType.scale, TrackType.scaleZ);
                        break;
                    }
                }
            }


            anim.Save(fname);
        }
Example #26
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="FileName"></param>
 /// <param name="animation"></param>
 /// <param name="skeleton"></param>
 public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton)
 {
     using (StreamWriter file = new StreamWriter(FileName))
         Write(file, animation, skeleton);
 }
Example #27
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton)
        {
            SBAnimation anim = new SBAnimation();

            using (StreamReader r = new StreamReader(new FileStream(FileName, FileMode.Open)))
            {
                if (r.ReadLine() != "#SBAnimation Version 1")
                {
                    return(anim);
                }

                while (!r.EndOfStream)
                {
                    var line = r.ReadLine();
                    var args = line.Trim().Split(' ');

                    switch (args[0])
                    {
                    case "comment":
                        break;

                    case "FrameCount":
                        anim.FrameCount = int.Parse(args[1]);
                        break;

                    case "visibility":
                        SBVisibilityAnimation visAnim = new SBVisibilityAnimation();
                        visAnim.MeshName = args[1];
                        var visLien = r.ReadLine();
                        if (visLien == "{")
                        {
                            visLien = r.ReadLine();
                            while (!r.EndOfStream && visLien != "}")
                            {
                                visLien = visLien.Replace(" ", "");
                                var frame = visLien.Substring(0, visLien.IndexOf(":")).Trim();
                                var value = visLien.Substring(visLien.IndexOf(":") + 1, visLien.Length - (visLien.IndexOf(":") + 1)).Trim();
                                visAnim.Visibility.AddKey(float.Parse(frame), bool.Parse(value));
                                visLien = r.ReadLine();
                            }
                        }
                        anim.VisibilityNodes.Add(visAnim);
                        break;

                    case "bone":
                        if (args[1].Contains(".anim"))
                        {
                            IO_MayaANIM manim = new IO_MayaANIM();
                            var         bones = manim.ImportSBAnimation(Path.GetDirectoryName(FileName) + "/" + args[1], skeleton);
                            anim.TransformNodes.AddRange(bones.TransformNodes);
                        }
                        break;

                    case "material":
                        SBMaterialAnimation matAnim = new SBMaterialAnimation();
                        matAnim.MaterialName  = args[1];
                        matAnim.AttributeName = args[2];
                        var matLien = r.ReadLine();
                        if (matLien == "{")
                        {
                            matLien = r.ReadLine();
                            while (!r.EndOfStream && matLien != "}")
                            {
                                matLien = matLien.Replace(" ", "");
                                var frame = matLien.Substring(0, matLien.IndexOf(":")).Trim();
                                var value = matLien.Substring(matLien.IndexOf(":") + 1, matLien.Length - (matLien.IndexOf(":") + 1)).Trim();

                                var vector = value.Replace(")", "").Replace("(", "").Split(',');
                                if (vector.Length != 4)
                                {
                                    continue;
                                }

                                matAnim.Keys.AddKey(float.Parse(frame), new Vector4(float.Parse(vector[0]), float.Parse(vector[1]), float.Parse(vector[2]), float.Parse(vector[3])));
                                matLien = r.ReadLine();
                            }
                        }
                        anim.MaterialNodes.Add(matAnim);
                        break;
                    }
                }
            }

            return(anim);
        }
Example #28
0
        public void Write(StreamWriter file, SBAnimation animation, SBSkeleton skeleton)
        {
            List <Bone> roots = CreateRoots(skeleton.Roots.ToList());

            file.WriteLine("HIERARCHY");
            foreach (var root in roots)
            {
                Vector3 offset = Vector3.TransformPosition(Vector3.Zero, root.head.WorldTransform);
                file.WriteLine("ROOT " + root.name);
                file.WriteLine("{");
                file.WriteLine("\tOFFSET " + offset.X + " " + offset.Y + " " + offset.Z);
                file.WriteLine("\tCHANNELS 6 Xposition Yposition Zposition Zrotation Yrotation Xrotation");
                foreach (var child in root.children)
                {
                    WriteChildBone(file, child, "\t");
                }
                file.WriteLine("}");
            }

            int nFrames = !Settings.SkeletonOnly ? (int)animation.FrameCount : 1;

            file.WriteLine("MOTION");
            file.WriteLine("Frames: " + nFrames);
            file.WriteLine("Frame Time: .0083333");

            if (Settings.SkeletonOnly)
            {
                String line = "";
                for (int i = 0; i < roots.Count; i++)
                {
                    Bone    root   = roots[i];
                    Vector3 offset = Vector3.TransformPosition(Vector3.Zero, root.head.WorldTransform);
                    line += offset.X + " " + offset.Y + " " + offset.Z + " 0 0 0";
                    if (root.children.Count > 0)
                    {
                        line += " " + AnimateSkeletonOnly(root.children);
                    }
                    if (i < roots.Count - 1)
                    {
                        line += " ";
                    }
                }
                file.WriteLine(line);
                return;
            }

            Dictionary <String, SBTransformAnimation> transformNodes = new Dictionary <string, SBTransformAnimation>();

            foreach (var v in animation.TransformNodes)
            {
                transformNodes[v.Name] = v;
            }

            for (int frame = 0; frame < nFrames; frame++)
            {
                String line = "";
                UpdateSBSkeleton(skeleton, transformNodes, frame);
                for (int i = 0; i < roots.Count; i++)
                {
                    Bone    root = roots[i];
                    Vector3 pos  = root.offset;
                    line += pos.X + " " + pos.Y + " " + pos.Z + " 0 0 0";

                    foreach (var child in root.children)
                    {
                        line += " " + Animate(child);
                    }
                    if (i < roots.Count - 1)
                    {
                        line += " ";
                    }
                }
                file.WriteLine(line);
            }
        }
Example #29
0
        public SBAnimation ImportSBAnimation(string FileName, SBSkeleton skeleton, string jvcPath)
        {
            var sbAnim = new SBAnimation();

            var jointTable = GetJointTable(jvcPath);

            var anim = new Anim();

            using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(FileName, FileMode.Open)))
                anim.Parse(r);

            float scale = Settings.FrameScale;

            sbAnim.FrameCount = (float)(scale * anim.EndTime);

            foreach (var j in anim.Joints)
            {
                if (j.BoneID == -1)
                {
                    continue;
                }

                if (j.BoneID >= jointTable.Length || jointTable[j.BoneID] == -1 || jointTable[j.BoneID] >= skeleton.Bones.Length)
                {
                    continue;
                }

                var bone = skeleton.Bones[jointTable[j.BoneID]];


                SBTransformAnimation node = sbAnim.TransformNodes.Find(e => e.Name == bone.Name);
                if (node == null)
                {
                    node      = new SBTransformAnimation();
                    node.Name = bone.Name;
                    sbAnim.TransformNodes.Add(node);
                }
                //Console.WriteLine(bone.Name);

                if (j.Flag3 == 0x21)
                {
                    foreach (var k in j.Keys)
                    {
                        //Console.WriteLine($"\t{k.Time} {k.X} {k.Y} {k.Z} {k.W}");
                        node.AddKey((float)Math.Ceiling(k.Time * scale), bone.X + k.X, SBTrackType.TranslateX);
                        node.AddKey((float)Math.Ceiling(k.Time * scale), bone.Y + k.Y, SBTrackType.TranslateY);
                        node.AddKey((float)Math.Ceiling(k.Time * scale), bone.Z + k.Z, SBTrackType.TranslateZ);
                    }
                }
                else
                if (j.Flag3 == 0x28)
                {
                    var eul0 = ToQuat(bone.RotationQuaternion, j.Keys[0].W, new Vector3(j.Keys[0].X, j.Keys[0].Y, j.Keys[0].Z));
                    node.AddKey(0, eul0.X, SBTrackType.RotateX, InterpolationType.Step);
                    node.AddKey(0, eul0.Y, SBTrackType.RotateY, InterpolationType.Step);
                    node.AddKey(0, eul0.Z, SBTrackType.RotateZ, InterpolationType.Step);
                    node.AddKey(0, eul0.W, SBTrackType.RotateW, InterpolationType.Step);
                    foreach (var k in j.Keys)
                    {
                        var eul = ToQuat(bone.RotationQuaternion, k.W, new Vector3(k.X, k.Y, k.Z));

                        node.AddKey((float)Math.Ceiling(k.Time * scale), eul.X, SBTrackType.RotateX);
                        node.AddKey((float)Math.Ceiling(k.Time * scale), eul.Y, SBTrackType.RotateY);
                        node.AddKey((float)Math.Ceiling(k.Time * scale), eul.Z, SBTrackType.RotateZ);
                        node.AddKey((float)Math.Ceiling(k.Time * scale), eul.W, SBTrackType.RotateW);
                    }
                }
                else
                {
                    SBConsole.WriteLine("Unknown MOT Track Type " + j.Flag3.ToString("X"));
                }
            }

            sbAnim.ConvertRotationKeysToEuler();

            return(sbAnim);
        }