Beispiel #1
0
        public GfxCameraAnimation(H3DAnimation Anm) : base(Anm)
        {
            if (Anm.AnimationType != H3DAnimationType.Camera)
            {
                throw new ArgumentException("Tried to construct a camera animation from a non-camera animation.");
            }
            else
            {
                foreach (H3DAnimationElement Elem in Anm.Elements)
                {
                    switch (Elem.TargetType)
                    {
                    case H3DTargetType.CameraViewRotation:
                        ViewType = GfxCameraAnimationViewType.Rotate;
                        break;

                    case H3DTargetType.CameraTwist:
                        ViewType = GfxCameraAnimationViewType.Aim;
                        break;

                    case H3DTargetType.CameraUpVector:
                        ViewType = GfxCameraAnimationViewType.LookAt;
                        break;

                    case H3DTargetType.CameraHeight:
                        ProjectionType = GfxCameraAnimationProjectionType.Orthogonal;
                        break;
                    }
                }
            }
        }
Beispiel #2
0
        private bool GetBoneRT(
            H3DAnimation Anim,
            H3DDict <H3DBone> Skeleton,
            string Name,
            int Frame,
            out Vector3 Rotation,
            out Vector3 Translation)
        {
            if (!Skeleton.Contains(Name))
            {
                Rotation    = Vector3.Zero;
                Translation = Vector3.Zero;

                return(false);
            }

            H3DBone PoseBone = Skeleton[Name];

            Rotation    = PoseBone.Rotation;
            Translation = PoseBone.Translation;

            H3DAnimationElement Bone = Anim.Elements.Find(x => x.Name == Name);

            if (Bone != null)
            {
                H3DAnimTransform Transform = (H3DAnimTransform)Bone.Content;

                if (Transform.RotationX.Exists)
                {
                    Rotation.X = Transform.RotationX.GetFrameValue(Frame);
                }
                if (Transform.RotationY.Exists)
                {
                    Rotation.Y = Transform.RotationY.GetFrameValue(Frame);
                }
                if (Transform.RotationZ.Exists)
                {
                    Rotation.Z = Transform.RotationZ.GetFrameValue(Frame);
                }

                if (Transform.TranslationX.Exists)
                {
                    Translation.X = Transform.TranslationX.GetFrameValue(Frame);
                }
                if (Transform.TranslationY.Exists)
                {
                    Translation.Y = Transform.TranslationY.GetFrameValue(Frame);
                }
                if (Transform.TranslationZ.Exists)
                {
                    Translation.Z = Transform.TranslationZ.GetFrameValue(Frame);
                }
            }

            return(true);
        }
Beispiel #3
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header)
        {
            H3D Output;

            //Model
            byte[] Buffer = new byte[Header.Entries[0].Length];

            Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

            Input.Read(Buffer, 0, Buffer.Length);

            using (MemoryStream MS = new MemoryStream(Buffer))
            {
                Output = H3D.Open(MS);
            }

            //Skeletal Animations
            if (Header.Entries.Length > 1)
            {
                Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin);

                GF1MotionPack MotPack = new GF1MotionPack(Input);

                foreach (GF1Motion Mot in MotPack)
                {
                    H3DAnimation SklAnim = Mot.ToH3DSkeletalAnimation(Output.Models[0].Skeleton);

                    SklAnim.Name = $"Motion_{Mot.Index}";

                    Output.SkeletalAnimations.Add(SklAnim);
                }
            }

            //Material Animations
            if (Header.Entries.Length > 2)
            {
                Input.Seek(Header.Entries[2].Address, SeekOrigin.Begin);

                byte[] Data = new byte[Header.Entries[2].Length];

                Input.Read(Data, 0, Data.Length);

                H3D MatAnims = H3D.Open(Data);

                Output.Merge(MatAnims);
            }

            return(Output);
        }
Beispiel #4
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, H3DDict <H3DBone> Skeleton)
        {
            H3D Output = new H3D();

            BinaryReader Reader = new BinaryReader(Input);

            int Index = 0;

            foreach (GFPackage.Entry Entry in Header.Entries)
            {
                Input.Seek(Entry.Address, SeekOrigin.Begin);

                if (Index == 20)
                {
                    break;
                }

                if (Index == 0)
                {
                    GF1MotionPack MotPack = new GF1MotionPack(Reader);

                    foreach (GF1Motion Mot in MotPack)
                    {
                        H3DAnimation Anim = Mot.ToH3DSkeletalAnimation(Skeleton);

                        Anim.Name = $"Motion_{Index++}";

                        Output.SkeletalAnimations.Add(Anim);
                    }
                }
                else
                {
                    byte[] Data = Reader.ReadBytes(Entry.Length);

                    if (Data.Length > 4 &&
                        Data[0] == 'B' &&
                        Data[1] == 'C' &&
                        Data[2] == 'H' &&
                        Data[3] == '\0')
                    {
                        Output.Merge(H3D.Open(Data));
                    }
                }
            }

            return(Output);
        }
        public H3DSkeletalAnimWrapper(H3DAnimation h3dAnim, BCH bch)
        {
            ImageKey         = "anim";
            SelectedImageKey = "anim";

            BCHParent = bch;
            Text      = h3dAnim.Name;

            H3DAnimation         = h3dAnim;
            Animation.FrameCount = h3dAnim.FramesCount;
            Animation.Name       = h3dAnim.Name;
            Animation.Loop       = h3dAnim.AnimationFlags.HasFlag(H3DAnimationFlags.IsLooping);
            foreach (var bone in h3dAnim.Elements)
            {
                Animation.AnimGroups.Add(new H3DBoneAnimGroup(bone));
            }
        }
Beispiel #6
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, H3DDict <H3DBone> Skeleton)
        {
            H3D Output = new H3D();

            //Skeletal Animations
            Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

            GF1MotionPack MotPack = new GF1MotionPack(Input);

            foreach (GF1Motion Mot in MotPack)
            {
                H3DAnimation SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton);

                SklAnim.Name = $"Motion_{Mot.Index}";

                Output.SkeletalAnimations.Add(SklAnim);
            }

            //Material Animations
            Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin);

            GFPackage.Header PackHeader = GFPackage.GetPackageHeader(Input);

            foreach (GFPackage.Entry Entry in PackHeader.Entries)
            {
                Input.Seek(Entry.Address, SeekOrigin.Begin);

                if (Entry.Length > 0)
                {
                    byte[] Data = new byte[Entry.Length];

                    Input.Read(Data, 0, Data.Length);

                    H3D MatAnims = H3D.Open(Data);

                    Output.Merge(MatAnims);
                }
            }

            return(Output);
        }
Beispiel #7
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, H3DDict <H3DBone> Skeleton = null)
        {
            BinaryReader Reader = new BinaryReader(Input);

            GFModelPack  MdlPack = new GFModelPack();
            GFMotionPack MotPack = new GFMotionPack();

            ReadModelsBG(Header.Entries[0], Reader, MdlPack); //Textures
            ReadModelsBG(Header.Entries[1], Reader, MdlPack); //Shaders
            ReadModelsBG(Header.Entries[2], Reader, MdlPack); //Models
            ReadModelsBG(Header.Entries[3], Reader, MdlPack); //Models?
            ReadModelsBG(Header.Entries[4], Reader, MdlPack); //More models
            ReadAnimsBG(Header.Entries[5], Reader, MotPack);  //Animations
            ReadAnimsBG(Header.Entries[6], Reader, MotPack);  //More animations

            H3D Output = MdlPack.ToH3D();

            foreach (GFMotion Mot in MotPack)
            {
                H3DMaterialAnim MatAnim = Mot.ToH3DMaterialAnimation();
                H3DAnimation    VisAnim = Mot.ToH3DVisibilityAnimation();

                if (MatAnim != null)
                {
                    MatAnim.Name = $"Motion_{Mot.Index}";

                    Output.MaterialAnimations.Add(MatAnim);
                }

                if (VisAnim != null)
                {
                    VisAnim.Name = $"Motion_{Mot.Index}";

                    Output.VisibilityAnimations.Add(VisAnim);
                }
            }

            return(Output);
        }
Beispiel #8
0
        public H3DAnimation ToH3DAnimation(GFMotion Motion)
        {
            H3DAnimation Output = new H3DAnimation()
            {
                Name           = "GFMotion",
                FramesCount    = Motion.FramesCount,
                AnimationType  = H3DAnimationType.Visibility,
                AnimationFlags = Motion.IsLooping ? H3DAnimationFlags.IsLooping : 0
            };

            ushort Index = 0;

            foreach (GFMotBoolean Vis in Visibilities)
            {
                H3DAnimBoolean Anim = new H3DAnimBoolean();

                Anim.StartFrame = 0;
                Anim.EndFrame   = Motion.FramesCount;
                Anim.CurveIndex = Index++;

                foreach (bool Visibility in Vis.Values)
                {
                    Anim.Values.Add(Visibility);
                }

                Output.Elements.Add(new H3DAnimationElement()
                {
                    Name          = Vis.Name,
                    PrimitiveType = H3DPrimitiveType.Boolean,
                    TargetType    = H3DTargetType.MeshNodeVisibility,
                    Content       = Anim
                });
            }

            return(Output);
        }
Beispiel #9
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header)
        {
            H3D Output;

            //Model
            Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

            GFModelPack MdlPack = new GFModelPack(Input);

            Output = MdlPack.ToH3D();

            //Animations
            Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin);

            GFMotionPack MotPack = new GFMotionPack(Input);

            foreach (GFMotion Mot in MotPack)
            {
                H3DAnimation    SklAnim = Mot.ToH3DSkeletalAnimation(MdlPack.Models[0].Skeleton);
                H3DMaterialAnim MatAnim = Mot.ToH3DMaterialAnimation();
                H3DAnimation    VisAnim = Mot.ToH3DVisibilityAnimation();

                if (SklAnim != null)
                {
                    SklAnim.Name = $"Motion_{Mot.Index}";

                    Output.SkeletalAnimations.Add(SklAnim);
                }

                if (MatAnim != null)
                {
                    MatAnim.Name = $"Motion_{Mot.Index}";

                    Output.MaterialAnimations.Add(MatAnim);
                }

                if (VisAnim != null)
                {
                    VisAnim.Name = $"Motion_{Mot.Index}";

                    Output.VisibilityAnimations.Add(VisAnim);
                }
            }

            //Texture
            if (Header.Entries.Length > 3 && Header.Entries[3].Length >= 4)
            {
                Input.Seek(Header.Entries[3].Address, SeekOrigin.Begin);

                BinaryReader Reader = new BinaryReader(Input);

                uint MagicNum = Reader.ReadUInt32();

                if (MagicNum == 0x15041213)
                {
                    Input.Seek(-4, SeekOrigin.Current);

                    GFTexture Tex = new GFTexture(Reader);

                    Output.Textures.Add(Tex.ToH3DTexture());
                }
            }

            return(Output);
        }
Beispiel #10
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, H3DDict <H3DBone> Skeleton = null)
        {
            H3D Output = default(H3D);

            BinaryReader Reader = new BinaryReader(Input);

            if (Input.Length <= Header.Entries[0].Address)
            {
                return(null);
            }

            Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

            uint MagicNum = Reader.ReadUInt32();

            switch (MagicNum)
            {
            case GFModelConstant:
                GFModelPack MdlPack = new GFModelPack();

                //High Poly Pokémon model
                Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

                MdlPack.Models.Add(new GFModel(Reader, "PM_HighPoly"));

                //Low Poly Pokémon model
                Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin);

                MdlPack.Models.Add(new GFModel(Reader, "PM_LowPoly"));

                //Pokémon Shader package
                Input.Seek(Header.Entries[2].Address, SeekOrigin.Begin);

                GFPackage.Header PSHeader = GFPackage.GetPackageHeader(Input);

                foreach (GFPackage.Entry Entry in PSHeader.Entries)
                {
                    Input.Seek(Entry.Address, SeekOrigin.Begin);

                    MdlPack.Shaders.Add(new GFShader(Reader));
                }

                //More shaders
                Input.Seek(Header.Entries[3].Address, SeekOrigin.Begin);

                if (GFPackage.IsValidPackage(Input))
                {
                    GFPackage.Header PCHeader = GFPackage.GetPackageHeader(Input);

                    foreach (GFPackage.Entry Entry in PCHeader.Entries)
                    {
                        Input.Seek(Entry.Address, SeekOrigin.Begin);

                        MdlPack.Shaders.Add(new GFShader(Reader));
                    }
                }

                Output = MdlPack.ToH3D();

                break;

            case GFTextureConstant:
                Output = new H3D();

                foreach (GFPackage.Entry Entry in Header.Entries)
                {
                    Input.Seek(Entry.Address, SeekOrigin.Begin);

                    Output.Textures.Add(new GFTexture(Reader).ToH3DTexture());
                }

                break;

            case GFMotionConstant:
                Output = new H3D();

                if (Skeleton == null)
                {
                    break;
                }

                for (int Index = 0; Index < Header.Entries.Length; Index++)
                {
                    Input.Seek(Header.Entries[Index].Address, SeekOrigin.Begin);

                    if (Input.Position + 4 > Input.Length)
                    {
                        break;
                    }
                    if (Reader.ReadUInt32() != GFMotionConstant)
                    {
                        continue;
                    }

                    Input.Seek(-4, SeekOrigin.Current);

                    GFMotion Mot = new GFMotion(Reader, Index);

                    H3DAnimation    SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton);
                    H3DMaterialAnim MatAnim = Mot.ToH3DMaterialAnimation();
                    H3DAnimation    VisAnim = Mot.ToH3DVisibilityAnimation();

                    if (SklAnim != null)
                    {
                        SklAnim.Name = $"Motion_{Mot.Index}";

                        Output.SkeletalAnimations.Add(SklAnim);
                    }

                    if (MatAnim != null)
                    {
                        MatAnim.Name = $"Motion_{Mot.Index}";

                        Output.MaterialAnimations.Add(MatAnim);
                    }

                    if (VisAnim != null)
                    {
                        VisAnim.Name = $"Motion_{Mot.Index}";

                        Output.VisibilityAnimations.Add(VisAnim);
                    }
                }

                break;

            case BCHConstant:
                Output = new H3D();

                foreach (GFPackage.Entry Entry in Header.Entries)
                {
                    Input.Seek(Entry.Address, SeekOrigin.Begin);

                    MagicNum = Reader.ReadUInt32();

                    if (MagicNum != BCHConstant)
                    {
                        continue;
                    }

                    Input.Seek(-4, SeekOrigin.Current);

                    byte[] Buffer = Reader.ReadBytes(Entry.Length);

                    Output.Merge(H3D.Open(Buffer));
                }

                break;
            }

            return(Output);
        }
Beispiel #11
0
        private void BuildAnimations(H3DAnimation anim, H3DModel model)
        {
            // Note: Because bones and armatures in Blender are an immense calvary, the animations are exported as a separate XML file, that we can re-import in the final engine (Unity for instance) as a readable format.

            animationXml = new XmlDocument();

            var xmlRoot = animationXml.CreateElement("animation");

            var rootName = animationXml.CreateAttribute("name");

            rootName.Value = anim.Name;

            var rootLength = animationXml.CreateAttribute("framesCount");

            rootLength.Value = (anim.FramesCount + 1).ToString();

            xmlRoot.Attributes.Append(rootName);
            xmlRoot.Attributes.Append(rootLength);
            animationXml.AppendChild(xmlRoot);

            for (int frame = 0; frame <= anim.FramesCount; ++frame)
            {
                var xmlFrame = animationXml.CreateElement("frame");

                var frameNumber = animationXml.CreateAttribute("number");
                frameNumber.Value = frame.ToString();

                xmlFrame.Attributes.Append(frameNumber);
                xmlRoot.AppendChild(xmlFrame);
            }

            pythonScript.AppendLine($"act1 = bpy.data.actions.new('{anim.Name}')");
            pythonScript.AppendLine($"root.animation_data_create()");
            pythonScript.AppendLine($"root.animation_data.action = act1");

            foreach (var element in anim.Elements)
            {
                var fc = new BLENDFCurve(element.Content);

                if (fc.IsNull || fc.NothingExists())
                {
                    continue;
                }

                var bone = model.Skeleton.FirstOrDefault(x => x.Name == element.Name);
                Matrix4x4.Decompose(bone.Transform, out var _, out var lr, out var ll);
                Matrix4x4.Decompose(bone.GetWorldTransform(model.Skeleton), out var _, out var wr, out var wl);

                H3DBone parentbone = null;

                if (bone.ParentIndex != -1)
                {
                    parentbone = model.Skeleton[bone.ParentIndex];
                }

                var bData = $"pose.bones[\"{element.Name}\"]";

                pythonScript.AppendLine($"flx = act1.fcurves.new(data_path='{bData}.location', index=0)");
                pythonScript.AppendLine($"fly = act1.fcurves.new(data_path='{bData}.location', index=1)");
                pythonScript.AppendLine($"flz = act1.fcurves.new(data_path='{bData}.location', index=2)");

                if (fc.IsQuaternion)
                {
                    pythonScript.AppendLine($"root.pose.bones['{element.Name}'].rotation_mode = 'QUATERNION'");
                    pythonScript.AppendLine($"frw = act1.fcurves.new(data_path='{bData}.rotation_quaternion', index=0)");
                    pythonScript.AppendLine($"frx = act1.fcurves.new(data_path='{bData}.rotation_quaternion', index=1)");
                    pythonScript.AppendLine($"fry = act1.fcurves.new(data_path='{bData}.rotation_quaternion', index=2)");
                    pythonScript.AppendLine($"frz = act1.fcurves.new(data_path='{bData}.rotation_quaternion', index=3)");
                }
                else
                {
                    pythonScript.AppendLine($"root.pose.bones['{element.Name}'].rotation_mode = 'XYZ'");
                    pythonScript.AppendLine($"frx = act1.fcurves.new(data_path='{bData}.rotation_euler', index=0)");
                    pythonScript.AppendLine($"fry = act1.fcurves.new(data_path='{bData}.rotation_euler', index=1)");
                    pythonScript.AppendLine($"frz = act1.fcurves.new(data_path='{bData}.rotation_euler', index=2)");
                }

                pythonScript.AppendLine($"fsx = act1.fcurves.new(data_path='{bData}.scale', index=0)");
                pythonScript.AppendLine($"fsy = act1.fcurves.new(data_path='{bData}.scale', index=1)");
                pythonScript.AppendLine($"fsz = act1.fcurves.new(data_path='{bData}.scale', index=2)");

                for (int frame = 0; frame <= anim.FramesCount; ++frame)
                {
                    var xmlElement = animationXml.CreateElement("element");

                    var elemName = animationXml.CreateAttribute("name");
                    elemName.Value = element.Name;

                    var elemPath = animationXml.CreateAttribute("path");
                    elemPath.Value = GetBonePath(bone, model.Skeleton);

                    xmlElement.Attributes.Append(elemName);
                    xmlElement.Attributes.Append(elemPath);

                    var l = ll * SCALE - fc.GetLocationAtFrame(frame) * SCALE;

                    pythonScript.AppendLine($"flx.keyframe_points.insert({frame + 1}, {l.Z})");
                    pythonScript.AppendLine($"fly.keyframe_points.insert({frame + 1}, {-l.Y})");
                    pythonScript.AppendLine($"flz.keyframe_points.insert({frame + 1}, {-l.X})");

                    var locAttr = animationXml.CreateAttribute("location");
                    locAttr.Value = $"{l.X},{l.Y},{l.Z}";
                    xmlElement.Attributes.Append(locAttr);

                    var r = fc.GetRotationAtFrame(frame);

                    if (r is Vector3 rv)
                    {
                        //pythonScript.AppendLine($"frx.keyframe_points.insert({frame + 1}, {rv.Z})");
                        //pythonScript.AppendLine($"fry.keyframe_points.insert({frame + 1}, {-rv.Y})");
                        //pythonScript.AppendLine($"frz.keyframe_points.insert({frame + 1}, {-rv.X})");

                        var rotAttr = animationXml.CreateAttribute("rotation");
                        rotAttr.Value = $"{rv.X},{rv.Y},{rv.Z}";
                        xmlElement.Attributes.Append(rotAttr);
                    }
                    else if (r is Quaternion rq)
                    {
                        //rq = Quaternion.Multiply(lr, Quaternion.Inverse(rq));
                        //pythonScript.AppendLine($"frw.keyframe_points.insert({frame + 1}, {rq.W})");
                        //pythonScript.AppendLine($"frx.keyframe_points.insert({frame + 1}, {rq.X})");
                        //pythonScript.AppendLine($"fry.keyframe_points.insert({frame + 1}, {rq.Y})");
                        //pythonScript.AppendLine($"frz.keyframe_points.insert({frame + 1}, {rq.Z})");

                        var rotAttr = animationXml.CreateAttribute("rotation");
                        rotAttr.Value = $"{rq.X},{rq.Y},{rq.Z},{rq.W}";
                        xmlElement.Attributes.Append(rotAttr);
                    }

                    var s = fc.GetScaleAtFrame(frame);
                    pythonScript.AppendLine($"fsx.keyframe_points.insert({frame + 1}, {s.X})");
                    pythonScript.AppendLine($"fsy.keyframe_points.insert({frame + 1}, {s.Y})");
                    pythonScript.AppendLine($"fsz.keyframe_points.insert({frame + 1}, {s.Z})");

                    var scaleAttr = animationXml.CreateAttribute("scale");
                    scaleAttr.Value = $"{s.X},{s.Y},{s.Z}";
                    xmlElement.Attributes.Append(scaleAttr);

                    xmlRoot.SelectSingleNode($"frame[@number={frame}]").AppendChild(xmlElement);
                }
            }
        }
Beispiel #12
0
        public H3DAnimation ToH3DAnimation(List <GFBone> Skeleton, GFMotion Motion)
        {
            H3DAnimation Output = new H3DAnimation()
            {
                Name           = "GFMotion",
                FramesCount    = Motion.FramesCount,
                AnimationType  = H3DAnimationType.Skeletal,
                AnimationFlags = Motion.IsLooping ? H3DAnimationFlags.IsLooping : 0
            };

            foreach (GFMotBoneTransform Bone in Bones)
            {
                H3DAnimQuatTransform QuatTransform = new H3DAnimQuatTransform();

                int BoneIndex = Skeleton.FindIndex(x => x.Name == Bone.Name);

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

                for (float Frame = 0; Frame < Motion.FramesCount; Frame++)
                {
                    Vector3 Scale       = Skeleton[BoneIndex].Scale;
                    Vector3 Rotation    = Skeleton[BoneIndex].Rotation;
                    Vector3 Translation = Skeleton[BoneIndex].Translation;

                    GFMotBoneTransform.SetFrameValue(Bone.ScaleX, Frame, ref Scale.X);
                    GFMotBoneTransform.SetFrameValue(Bone.ScaleY, Frame, ref Scale.Y);
                    GFMotBoneTransform.SetFrameValue(Bone.ScaleZ, Frame, ref Scale.Z);

                    GFMotBoneTransform.SetFrameValue(Bone.RotationX, Frame, ref Rotation.X);
                    GFMotBoneTransform.SetFrameValue(Bone.RotationY, Frame, ref Rotation.Y);
                    GFMotBoneTransform.SetFrameValue(Bone.RotationZ, Frame, ref Rotation.Z);

                    GFMotBoneTransform.SetFrameValue(Bone.TranslationX, Frame, ref Translation.X);
                    GFMotBoneTransform.SetFrameValue(Bone.TranslationY, Frame, ref Translation.Y);
                    GFMotBoneTransform.SetFrameValue(Bone.TranslationZ, Frame, ref Translation.Z);

                    /*
                     * gdkchan Note:
                     * When the game uses Axis Angle for rotation,
                     * I believe that the original Euler rotation can be ignored,
                     * because otherwise we would need to either convert Euler to Axis Angle or Axis to Euler,
                     * and both conversions are pretty expensive.
                     * The vector is already halved as a optimization (needs * 2).
                     */
                    Quaternion QuatRotation;

                    if (Bone.IsAxisAngle)
                    {
                        float Angle = Rotation.Length() * 2;

                        QuatRotation = Angle > 0
                            ? Quaternion.CreateFromAxisAngle(Vector3.Normalize(Rotation), Angle)
                            : Quaternion.Identity;
                    }
                    else
                    {
                        QuatRotation =
                            Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) *
                            Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) *
                            Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X);
                    }

                    QuatTransform.Scales.Add(Scale);
                    QuatTransform.Rotations.Add(QuatRotation);
                    QuatTransform.Translations.Add(Translation);
                }

                Output.Elements.Add(new H3DAnimationElement()
                {
                    Name          = Bone.Name,
                    Content       = QuatTransform,
                    TargetType    = H3DTargetType.Bone,
                    PrimitiveType = H3DPrimitiveType.QuatTransform
                });
            }

            return(Output);
        }
Beispiel #13
0
        public static H3D IdentifyByMagic(Stream Stream, H3DDict <H3DBone> Skeleton, string FileName)
        {
            H3D Output = null;

            if (Stream.Length > 4)
            {
                BinaryReader Reader = new BinaryReader(Stream);

                uint MagicNum = Reader.ReadUInt32();

                Stream.Seek(-4, SeekOrigin.Current);

                string Magic = Encoding.ASCII.GetString(Reader.ReadBytes(4));

                Stream.Seek(0, SeekOrigin.Begin);

                if (Magic.StartsWith("BCH"))
                {
                    return(H3D.Open(Reader.ReadBytes((int)Stream.Length)));
                }
                else if (Magic.StartsWith("MOD") && FileName != null)
                {
                    return(LoadMTModel(Reader, FileName, Path.GetDirectoryName(FileName)));
                }
                else if (Magic.StartsWith("TEX") && FileName != null)
                {
                    return(new MTTexture(Reader, Path.GetFileNameWithoutExtension(FileName)).ToH3D());
                }
                else if (Magic.StartsWith("MFX"))
                {
                    MTShader = new MTShaderEffects(Reader);
                }
                else if (Magic.StartsWith("CGFX"))
                {
                    return(Gfx.Open(Stream));
                }
                else if (Magic.StartsWith("CMIF"))
                {
                    return(new CMIFFile(Stream).ToH3D());
                }
                else
                {
                    switch (MagicNum)
                    {
                    case GFModel.MagicNum:
                        GFModel Model = new GFModel(Reader, "Model");
                        Output = Model.ToH3D();
                        Output.SourceData.Add(Model);

                        break;

                    case GFTexture.MagicNum:
                        //Can be GFShader or GFTexture
                        Reader.BaseStream.Seek(0x8, SeekOrigin.Current);

                        string GFMagicStr = StringUtils.ReadPaddedString(Reader, 8);

                        if (GFMagicStr == GFTexture.MagicStr)
                        {
                            Reader.BaseStream.Seek(-0x10, SeekOrigin.Current);
                            Output = new H3D();
                            Output.Textures.Add(new GFTexture(Reader).ToH3DTexture());
                        }
                        else
                        {
                            Reader.BaseStream.Seek(0x8, SeekOrigin.Current);
                            GFMagicStr = StringUtils.ReadPaddedString(Reader, 8);

                            if (GFMagicStr == GFShader.MagicStr)
                            {
                                Reader.BaseStream.Seek(-0x18, SeekOrigin.Current);
                                Output = new H3D();
                                Output.SourceData.Add(new GFShader(Reader));
                            }
                        }

                        break;

                    case GFModelPack.MagicNum:
                        if (GFModelPack.IsModelPack(Reader))
                        {
                            Output = new GFModelPack(Reader).ToH3D();
                        }
                        break;

                    case GFMotion.MagicNum:
                        if (Skeleton != null)
                        {
                            Output = new H3D();

                            GFMotion Motion = new GFMotion(Reader, 0);

                            H3DAnimation    SklAnim = Motion.ToH3DSkeletalAnimation(Skeleton);
                            H3DMaterialAnim MatAnim = Motion.ToH3DMaterialAnimation();
                            H3DAnimation    VisAnim = Motion.ToH3DVisibilityAnimation();

                            if (SklAnim != null)
                            {
                                Output.SkeletalAnimations.Add(SklAnim);
                            }
                            if (MatAnim != null)
                            {
                                Output.MaterialAnimations.Add(MatAnim);
                            }
                            if (VisAnim != null)
                            {
                                Output.VisibilityAnimations.Add(VisAnim);
                            }
                        }

                        break;
                    }

                    if (GFMotionPack.IsGFL2MotionPack(Reader))
                    {
                        GFMotionPack Pack = new GFMotionPack(Reader);
                        Output = Pack.ToH3D(Skeleton);
                    }
                    if (GF1MotionPack.IsGFL1MotionPack(Reader))
                    {
                        Output = new GF1MotionPack(Reader).ToH3D(Skeleton);
                    }
                }
            }

            return(Output);
        }
Beispiel #14
0
        public DAE(H3D Scene, int MdlIndex, int AnimIndex = -1)
        {
            if (MdlIndex != -1)
            {
                library_visual_scenes = new List <DAEVisualScene>();

                H3DModel Mdl = Scene.Models[MdlIndex];

                DAEVisualScene VN = new DAEVisualScene();

                VN.name = $"{Mdl.Name}_{MdlIndex.ToString("D2")}";
                VN.id   = $"{VN.name}_id";

                //Materials
                if (Mdl.Materials.Count > 0)
                {
                    library_materials = new List <DAEMaterial>();
                    library_effects   = new List <DAEEffect>();
                }

                foreach (H3DMaterial Mtl in Mdl.Materials)
                {
                    string MtlName = $"{MdlIndex.ToString("D2")}_{Mtl.Name}";

                    DAEEffect Effect = new DAEEffect();

                    Effect.name = $"{Mtl.Name}_eff";
                    Effect.id   = $"{Effect.name}_id";

                    DAEEffectParam ImgSurface = new DAEEffectParam();
                    DAEEffectParam ImgSampler = new DAEEffectParam();

                    ImgSurface.surface   = new DAEEffectParamSurfaceElement();
                    ImgSampler.sampler2D = new DAEEffectParamSampler2DElement();

                    ImgSurface.sid               = $"{Mtl.Name}_surf";
                    ImgSurface.surface.type      = "2D";
                    ImgSurface.surface.init_from = Mtl.Texture0Name;
                    ImgSurface.surface.format    = "PNG";

                    ImgSampler.sid = $"{Mtl.Name}_samp";
                    ImgSampler.sampler2D.source    = ImgSurface.sid;
                    ImgSampler.sampler2D.wrap_s    = Mtl.TextureMappers[0].WrapU.ToDAEWrap();
                    ImgSampler.sampler2D.wrap_t    = Mtl.TextureMappers[0].WrapV.ToDAEWrap();
                    ImgSampler.sampler2D.minfilter = Mtl.TextureMappers[0].MinFilter.ToDAEFilter();
                    ImgSampler.sampler2D.magfilter = Mtl.TextureMappers[0].MagFilter.ToDAEFilter();
                    ImgSampler.sampler2D.mipfilter = DAEFilter.LINEAR;

                    Effect.profile_COMMON.newparam.Add(ImgSurface);
                    Effect.profile_COMMON.newparam.Add(ImgSampler);

                    Effect.profile_COMMON.technique.sid = $"{Mtl.Name}_tech";
                    Effect.profile_COMMON.technique.phong.diffuse.texture.texture = ImgSampler.sid;

                    library_effects.Add(Effect);

                    DAEMaterial Material = new DAEMaterial();

                    Material.name = $"{Mtl.Name}_mat";
                    Material.id   = $"{Material.name}_id";

                    Material.instance_effect.url = $"#{Effect.id}";

                    library_materials.Add(Material);
                }

                //Skeleton nodes
                string RootBoneId = string.Empty;

                if ((Mdl.Skeleton?.Count ?? 0) > 0)
                {
                    Queue <Tuple <H3DBone, DAENode> > ChildBones = new Queue <Tuple <H3DBone, DAENode> >();

                    DAENode RootNode = new DAENode();

                    ChildBones.Enqueue(Tuple.Create(Mdl.Skeleton[0], RootNode));

                    RootBoneId = $"#{Mdl.Skeleton[0].Name}_bone_id";

                    while (ChildBones.Count > 0)
                    {
                        Tuple <H3DBone, DAENode> Bone_Node = ChildBones.Dequeue();

                        H3DBone Bone = Bone_Node.Item1;

                        Bone_Node.Item2.id   = $"{Bone.Name}_bone_id";
                        Bone_Node.Item2.name = Bone.Name;
                        Bone_Node.Item2.sid  = Bone.Name;
                        Bone_Node.Item2.type = DAENodeType.JOINT;
                        Bone_Node.Item2.SetBoneEuler(Bone.Translation, Bone.Rotation, Bone.Scale);

                        foreach (H3DBone B in Mdl.Skeleton)
                        {
                            if (B.ParentIndex == -1)
                            {
                                continue;
                            }

                            H3DBone ParentBone = Mdl.Skeleton[B.ParentIndex];

                            if (ParentBone == Bone)
                            {
                                DAENode Node = new DAENode();

                                ChildBones.Enqueue(Tuple.Create(B, Node));

                                if (Bone_Node.Item2.Nodes == null)
                                {
                                    Bone_Node.Item2.Nodes = new List <DAENode>();
                                }

                                Bone_Node.Item2.Nodes.Add(Node);
                            }
                        }
                    }

                    VN.node.Add(RootNode);
                }

                //Mesh
                if (Mdl.Meshes.Count > 0)
                {
                    library_geometries = new List <DAEGeometry>();
                }

                for (int MeshIndex = 0; MeshIndex < Mdl.Meshes.Count; MeshIndex++)
                {
                    if (Mdl.Meshes[MeshIndex].Type == H3DMeshType.Silhouette)
                    {
                        continue;
                    }

                    H3DMesh Mesh = Mdl.Meshes[MeshIndex];

                    PICAVertex[] Vertices = MeshTransform.GetWorldSpaceVertices(Mdl.Skeleton, Mesh);

                    string MtlName = $"Mdl_{MdlIndex}_Mtl_{Mdl.Materials[Mesh.MaterialIndex].Name}";
                    string MtlTgt  = library_materials[Mesh.MaterialIndex].id;

                    for (int SMIndex = 0; SMIndex < Mesh.SubMeshes.Count; SMIndex++)
                    {
                        H3DSubMesh SM = Mesh.SubMeshes[SMIndex];

                        string ShortName = string.Empty;

                        if (Mdl.MeshNodesTree != null && Mesh.NodeIndex < Mdl.MeshNodesTree.Count)
                        {
                            ShortName = Mdl.MeshNodesTree.Find(Mesh.NodeIndex);
                        }

                        string MeshName = $"{ShortName}_{MeshIndex}_{SMIndex}";

                        DAEGeometry Geometry = new DAEGeometry();

                        Geometry.name = MeshName;
                        Geometry.id   = $"{Geometry.name}_geo_id";

                        //Geometry
                        string VertsId = $"{MeshName}_vtx_id";

                        Geometry.mesh.vertices.id        = VertsId;
                        Geometry.mesh.triangles.material = MtlName;
                        Geometry.mesh.triangles.AddInput("VERTEX", $"#{VertsId}");
                        Geometry.mesh.triangles.Set_p(SM.Indices);

                        foreach (PICAAttribute Attr in Mesh.Attributes)
                        {
                            if (Attr.Name >= PICAAttributeName.BoneIndex)
                            {
                                continue;
                            }

                            string[] Values = new string[Vertices.Length];

                            for (int Index = 0; Index < Vertices.Length; Index++)
                            {
                                PICAVertex v = Vertices[Index];

                                switch (Attr.Name)
                                {
                                case PICAAttributeName.Position:  Values[Index] = DAEUtils.Vector3Str(v.Position);  break;

                                case PICAAttributeName.Normal:    Values[Index] = DAEUtils.Vector3Str(v.Normal);    break;

                                case PICAAttributeName.Tangent:   Values[Index] = DAEUtils.Vector3Str(v.Tangent);   break;

                                case PICAAttributeName.Color:     Values[Index] = DAEUtils.Vector4Str(v.Color);     break;

                                case PICAAttributeName.TexCoord0: Values[Index] = DAEUtils.Vector2Str(v.TexCoord0); break;

                                case PICAAttributeName.TexCoord1: Values[Index] = DAEUtils.Vector2Str(v.TexCoord1); break;

                                case PICAAttributeName.TexCoord2: Values[Index] = DAEUtils.Vector2Str(v.TexCoord2); break;
                                }
                            }

                            int Elements = 0;

                            switch (Attr.Name)
                            {
                            case PICAAttributeName.Position:  Elements = 3; break;

                            case PICAAttributeName.Normal:    Elements = 3; break;

                            case PICAAttributeName.Tangent:   Elements = 3; break;

                            case PICAAttributeName.Color:     Elements = 4; break;

                            case PICAAttributeName.TexCoord0: Elements = 2; break;

                            case PICAAttributeName.TexCoord1: Elements = 2; break;

                            case PICAAttributeName.TexCoord2: Elements = 2; break;
                            }

                            DAESource Source = new DAESource();

                            Source.name = $"{MeshName}_{Attr.Name}";
                            Source.id   = $"{Source.name}_id";

                            Source.float_array = new DAEArray()
                            {
                                id    = $"{Source.name}_array_id",
                                count = (uint)(Vertices.Length * Elements),
                                data  = string.Join(" ", Values)
                            };

                            DAEAccessor Accessor = new DAEAccessor()
                            {
                                source = $"#{Source.float_array.id}",
                                count  = (uint)Vertices.Length,
                                stride = (uint)Elements
                            };

                            switch (Elements)
                            {
                            case 2: Accessor.AddParams("float", "S", "T");           break;

                            case 3: Accessor.AddParams("float", "X", "Y", "Z");      break;

                            case 4: Accessor.AddParams("float", "R", "G", "B", "A"); break;
                            }

                            Source.technique_common.accessor = Accessor;

                            Geometry.mesh.source.Add(Source);

                            if (Attr.Name < PICAAttributeName.Color)
                            {
                                string Semantic = string.Empty;

                                switch (Attr.Name)
                                {
                                case PICAAttributeName.Position: Semantic = "POSITION"; break;

                                case PICAAttributeName.Normal:   Semantic = "NORMAL";   break;

                                case PICAAttributeName.Tangent:  Semantic = "TANGENT";  break;
                                }

                                Geometry.mesh.vertices.AddInput(Semantic, $"#{Source.id}");
                            }
                            else if (Attr.Name == PICAAttributeName.Color)
                            {
                                Geometry.mesh.triangles.AddInput("COLOR", $"#{Source.id}", 0);
                            }
                            else
                            {
                                Geometry.mesh.triangles.AddInput("TEXCOORD", $"#{Source.id}", 0, (uint)Attr.Name - 4);
                            }
                        } //Attributes Loop

                        library_geometries.Add(Geometry);

                        //Controller
                        bool HasController = SM.BoneIndicesCount > 0 && (Mdl.Skeleton?.Count ?? 0) > 0;

                        DAEController Controller = new DAEController();

                        if (HasController)
                        {
                            if (library_controllers == null)
                            {
                                library_controllers = new List <DAEController>();
                            }

                            Controller.name = $"{MeshName}_ctrl";
                            Controller.id   = $"{Controller.name}_id";

                            Controller.skin.source = $"#{Geometry.id}";
                            Controller.skin.vertex_weights.count = (uint)Vertices.Length;

                            string[] BoneNames = new string[Mdl.Skeleton.Count];
                            string[] BindPoses = new string[Mdl.Skeleton.Count];

                            for (int Index = 0; Index < Mdl.Skeleton.Count; Index++)
                            {
                                BoneNames[Index] = Mdl.Skeleton[Index].Name;
                                BindPoses[Index] = DAEUtils.MatrixStr(Mdl.Skeleton[Index].InverseTransform);
                            }

                            //4 is the max number of bones per vertex
                            int[] v      = new int[Vertices.Length * 4 * 2];
                            int[] vcount = new int[Vertices.Length];

                            Dictionary <string, int> Weights = new Dictionary <string, int>();

                            int vi = 0, vci = 0;

                            if (SM.Skinning == H3DSubMeshSkinning.Smooth)
                            {
                                foreach (PICAVertex Vertex in Vertices)
                                {
                                    int Count = 0;

                                    for (int Index = 0; Index < 4; Index++)
                                    {
                                        int   BIndex = Vertex.Indices[Index];
                                        float Weight = Vertex.Weights[Index];

                                        if (Weight == 0)
                                        {
                                            break;
                                        }

                                        if (BIndex < SM.BoneIndices.Length && BIndex > -1)
                                        {
                                            BIndex = SM.BoneIndices[BIndex];
                                        }
                                        else
                                        {
                                            BIndex = 0;
                                        }

                                        string WStr = Weight.ToString(CultureInfo.InvariantCulture);

                                        v[vi++] = BIndex;

                                        if (Weights.ContainsKey(WStr))
                                        {
                                            v[vi++] = Weights[WStr];
                                        }
                                        else
                                        {
                                            v[vi++] = Weights.Count;

                                            Weights.Add(WStr, Weights.Count);
                                        }

                                        Count++;
                                    }

                                    vcount[vci++] = Count;
                                }
                            }
                            else
                            {
                                foreach (PICAVertex Vertex in Vertices)
                                {
                                    int BIndex = Vertex.Indices[0];

                                    if (BIndex < SM.BoneIndices.Length && BIndex > -1)
                                    {
                                        BIndex = SM.BoneIndices[BIndex];
                                    }
                                    else
                                    {
                                        BIndex = 0;
                                    }

                                    v[vi++] = BIndex;
                                    v[vi++] = 0;

                                    vcount[vci++] = 1;
                                }

                                Weights.Add("1", 0);
                            }

                            Array.Resize(ref v, vi);

                            Controller.skin.src.Add(new DAESource($"{Controller.name}_names", 1, BoneNames, "JOINT", "Name"));
                            Controller.skin.src.Add(new DAESource($"{Controller.name}_poses", 16, BindPoses, "TRANSFORM", "float4x4"));
                            Controller.skin.src.Add(new DAESource($"{Controller.name}_weights", 1, Weights.Keys.ToArray(), "WEIGHT", "float"));

                            Controller.skin.joints.AddInput("JOINT", $"#{Controller.skin.src[0].id}");
                            Controller.skin.joints.AddInput("INV_BIND_MATRIX", $"#{Controller.skin.src[1].id}");

                            Controller.skin.vertex_weights.AddInput("JOINT", $"#{Controller.skin.src[0].id}", 0);
                            Controller.skin.vertex_weights.AddInput("WEIGHT", $"#{Controller.skin.src[2].id}", 1);

                            Controller.skin.vertex_weights.vcount = string.Join(" ", vcount);
                            Controller.skin.vertex_weights.v      = string.Join(" ", v);

                            library_controllers.Add(Controller);
                        }

                        //Mesh node
                        DAENode Node = new DAENode();

                        Node.name   = $"{MeshName}_node";
                        Node.id     = $"{Node.name}_id";
                        Node.matrix = DAEMatrix.Identity;

                        DAENodeInstance NodeInstance = new DAENodeInstance();

                        NodeInstance.url = $"#{(HasController ? Controller.id : Geometry.id)}";
                        NodeInstance.bind_material.technique_common.instance_material.symbol = MtlName;
                        NodeInstance.bind_material.technique_common.instance_material.target = $"#{MtlTgt}";

                        if (HasController)
                        {
                            NodeInstance.skeleton    = $"#{VN.node[0].id}";
                            Node.instance_controller = NodeInstance;
                        }
                        else
                        {
                            Node.instance_geometry = NodeInstance;
                        }

                        VN.node.Add(Node);
                    } //SubMesh Loop
                }     //Mesh Loop

                library_visual_scenes.Add(VN);

                if (library_visual_scenes.Count > 0)
                {
                    scene.instance_visual_scene.url = $"#{library_visual_scenes[0].id}";
                }

                library_images = new List <DAEImage>();

                foreach (H3DTexture Tex in Scene.Textures)
                {
                    //library_images.Add(new DAEImage()
                    //{
                    //    id        = Tex.Name,
                    //    init_from = $"./{Tex.Name}.png"
                    //});
                }

                foreach (var mat in Scene.Models[MdlIndex].Materials)
                {
                    if (mat.Texture0Name != null && !LibImgContainsThing(mat.Texture0Name))
                    {
                        library_images.Add(new DAEImage()
                        {
                            id        = mat.Texture0Name,
                            init_from = $"./{mat.Texture0Name}.png"
                        });
                    }
                    if (mat.Texture1Name != null && !LibImgContainsThing(mat.Texture1Name))
                    {
                        library_images.Add(new DAEImage()
                        {
                            id        = mat.Texture0Name,
                            init_from = $"./{mat.Texture0Name}.png"
                        });
                    }
                    if (mat.Texture2Name != null && !LibImgContainsThing(mat.Texture2Name))
                    {
                        library_images.Add(new DAEImage()
                        {
                            id        = mat.Texture0Name,
                            init_from = $"./{mat.Texture0Name}.png"
                        });
                    }
                }
            } //MdlIndex != -1

            if (AnimIndex != -1)
            {
                library_animations = new List <DAEAnimation>();

                string[] AnimElemNames = { "translate", "rotateX", "rotateY", "rotateZ", "scale" };

                H3DAnimation SklAnim = Scene.SkeletalAnimations[AnimIndex];

                H3DDict <H3DBone> Skeleton = Scene.Models[0].Skeleton;

                int FramesCount = (int)SklAnim.FramesCount + 1;

                foreach (H3DAnimationElement Elem in SklAnim.Elements)
                {
                    if (Elem.PrimitiveType != H3DPrimitiveType.Transform &&
                        Elem.PrimitiveType != H3DPrimitiveType.QuatTransform)
                    {
                        continue;
                    }

                    H3DBone SklBone = Skeleton.FirstOrDefault(x => x.Name == Elem.Name);
                    H3DBone Parent  = null;

                    if (SklBone != null && SklBone.ParentIndex != -1)
                    {
                        Parent = Skeleton[SklBone.ParentIndex];
                    }

                    for (int i = 0; i < 5; i++)
                    {
                        string[] AnimTimes = new string[FramesCount];
                        string[] AnimPoses = new string[FramesCount];
                        string[] AnimLerps = new string[FramesCount];

                        bool IsRotation = i > 0 && i < 4; //1, 2, 3

                        bool Skip =
                            Elem.PrimitiveType != H3DPrimitiveType.Transform &&
                            Elem.PrimitiveType != H3DPrimitiveType.QuatTransform;

                        if (!Skip)
                        {
                            if (Elem.Content is H3DAnimTransform Transform)
                            {
                                switch (i)
                                {
                                case 0: Skip = !Transform.TranslationExists; break;

                                case 1: Skip = !Transform.RotationX.Exists;  break;

                                case 2: Skip = !Transform.RotationY.Exists;  break;

                                case 3: Skip = !Transform.RotationZ.Exists;  break;

                                case 4: Skip = !Transform.ScaleExists;       break;
                                }
                            }
                            else if (Elem.Content is H3DAnimQuatTransform QuatTransform)
                            {
                                switch (i)
                                {
                                case 0: Skip = !QuatTransform.HasTranslation; break;

                                case 1: Skip = !QuatTransform.HasRotation;    break;

                                case 2: Skip = !QuatTransform.HasRotation;    break;

                                case 3: Skip = !QuatTransform.HasRotation;    break;

                                case 4: Skip = !QuatTransform.HasScale;       break;
                                }
                            }
                        }

                        if (Skip)
                        {
                            continue;
                        }

                        for (int Frame = 0; Frame < FramesCount; Frame++)
                        {
                            string StrTrans = string.Empty;

                            H3DAnimationElement PElem = SklAnim.Elements.FirstOrDefault(x => x.Name == Parent?.Name);

                            Vector3 InvScale = Vector3.One;

                            if (Elem.Content is H3DAnimTransform Transform)
                            {
                                //Compensate parent bone scale (basically, don't inherit scales)
                                if (Parent != null && (SklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0)
                                {
                                    if (PElem != null)
                                    {
                                        H3DAnimTransform PTrans = (H3DAnimTransform)PElem.Content;

                                        InvScale /= new Vector3(
                                            PTrans.ScaleX.Exists ? PTrans.ScaleX.GetFrameValue(Frame) : Parent.Scale.X,
                                            PTrans.ScaleY.Exists ? PTrans.ScaleY.GetFrameValue(Frame) : Parent.Scale.Y,
                                            PTrans.ScaleZ.Exists ? PTrans.ScaleZ.GetFrameValue(Frame) : Parent.Scale.Z);
                                    }
                                    else
                                    {
                                        InvScale /= Parent.Scale;
                                    }
                                }

                                switch (i)
                                {
                                //Translation
                                case 0:
                                    StrTrans = DAEUtils.VectorStr(new Vector3(
                                                                      Transform.TranslationX.Exists //X
                                            ? Transform.TranslationX.GetFrameValue(Frame) : SklBone.Translation.X,
                                                                      Transform.TranslationY.Exists //Y
                                            ? Transform.TranslationY.GetFrameValue(Frame) : SklBone.Translation.Y,
                                                                      Transform.TranslationZ.Exists //Z
                                            ? Transform.TranslationZ.GetFrameValue(Frame) : SklBone.Translation.Z));
                                    break;

                                //Scale
                                case 4:
                                    StrTrans = DAEUtils.VectorStr(InvScale * new Vector3(
                                                                      Transform.ScaleX.Exists //X
                                            ? Transform.ScaleX.GetFrameValue(Frame) : SklBone.Scale.X,
                                                                      Transform.ScaleY.Exists //Y
                                            ? Transform.ScaleY.GetFrameValue(Frame) : SklBone.Scale.Y,
                                                                      Transform.ScaleZ.Exists //Z
                                            ? Transform.ScaleZ.GetFrameValue(Frame) : SklBone.Scale.Z));
                                    break;

                                //Rotation
                                case 1: StrTrans = DAEUtils.RadToDegStr(Transform.RotationX.GetFrameValue(Frame)); break;

                                case 2: StrTrans = DAEUtils.RadToDegStr(Transform.RotationY.GetFrameValue(Frame)); break;

                                case 3: StrTrans = DAEUtils.RadToDegStr(Transform.RotationZ.GetFrameValue(Frame)); break;
                                }
                            }
                            else if (Elem.Content is H3DAnimQuatTransform QuatTransform)
                            {
                                //Compensate parent bone scale (basically, don't inherit scales)
                                if (Parent != null && (SklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0)
                                {
                                    if (PElem != null)
                                    {
                                        InvScale /= ((H3DAnimQuatTransform)PElem.Content).GetScaleValue(Frame);
                                    }
                                    else
                                    {
                                        InvScale /= Parent.Scale;
                                    }
                                }

                                switch (i)
                                {
                                case 0: StrTrans = DAEUtils.VectorStr(QuatTransform.GetTranslationValue(Frame));            break;

                                case 1: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().X); break;

                                case 2: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().Y); break;

                                case 3: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().Z); break;

                                case 4: StrTrans = DAEUtils.VectorStr(InvScale * QuatTransform.GetScaleValue(Frame));       break;
                                }
                            }

                            //This is the Time in seconds, so we divide by the target FPS
                            AnimTimes[Frame] = (Frame / 30f).ToString(CultureInfo.InvariantCulture);
                            AnimPoses[Frame] = StrTrans;
                            AnimLerps[Frame] = "LINEAR";
                        }

                        DAEAnimation Anim = new DAEAnimation();

                        Anim.name = $"{SklAnim.Name}_{Elem.Name}_{AnimElemNames[i]}";
                        Anim.id   = $"{Anim.name}_id";

                        Anim.src.Add(new DAESource($"{Anim.name}_frame", 1, AnimTimes, "TIME", "float"));
                        Anim.src.Add(new DAESource($"{Anim.name}_interp", 1, AnimLerps, "INTERPOLATION", "Name"));

                        Anim.src.Add(IsRotation
                            ? new DAESource($"{Anim.name}_pose", 1, AnimPoses, "ANGLE", "float")
                            : new DAESource($"{Anim.name}_pose", 3, AnimPoses,
                                            "X", "float",
                                            "Y", "float",
                                            "Z", "float"));

                        Anim.sampler.AddInput("INPUT", $"#{Anim.src[0].id}");
                        Anim.sampler.AddInput("INTERPOLATION", $"#{Anim.src[1].id}");
                        Anim.sampler.AddInput("OUTPUT", $"#{Anim.src[2].id}");

                        Anim.sampler.id     = $"{Anim.name}_samp_id";
                        Anim.channel.source = $"#{Anim.sampler.id}";
                        Anim.channel.target = $"{Elem.Name}_bone_id/{AnimElemNames[i]}";

                        if (IsRotation)
                        {
                            Anim.channel.target += ".ANGLE";
                        }

                        library_animations.Add(Anim);
                    } //Axis 0-5
                }     //SklAnim.Elements
            }         //AnimIndex != -1
        }
Beispiel #15
0
        public static H3D IdentifyAndOpen(string FileName, H3DDict <H3DBone> Skeleton = null)
        {
            //Formats that can by identified by extensions
            string FilePath = Path.GetDirectoryName(FileName);

            switch (Path.GetExtension(FileName).ToLower())
            {
            case ".txt":
                H3D AllFiles = new H3D();

                string[] files = File.ReadAllLines(FileName);

                string Parent = FilePath;

                foreach (string File in files)
                {
                    AllFiles.Merge(IdentifyAndOpen(Path.Combine(Parent, File)));
                }

                return(AllFiles);

            case ".gmp":
                H3D           OutputH3D = new H3D();
                GF1MotionPack MotPack   = new GF1MotionPack(new BinaryReader(new FileStream(FileName, FileMode.Open)));
                foreach (GF1Motion Mot in MotPack)
                {
                    H3DAnimation SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton);

                    SklAnim.Name = $"Motion_{Mot.Index}";

                    OutputH3D.SkeletalAnimations.Add(SklAnim);
                }
                return(OutputH3D);

            case ".smd": return(new SMD(FileName).ToH3D(FilePath));

            case ".obj": return(new OBJ(FileName).ToH3D(FilePath));

            case ".mtl": return(new OBJ(FileName).ToH3D(FilePath));

            case ".cmif": return(new CMIFFile(new FileStream(FileName, FileMode.Open)).ToH3D());

            case ".png":
                H3D Out = new H3D();
                Out.Textures.Add(new H3DTexture(FileName, true));
                return(Out);

            case ".gfbmdl":
                H3DModel model = new GFModel(new BinaryReader(new FileStream(FileName, FileMode.Open)), Path.GetFileNameWithoutExtension(FileName)).ToH3DModel();
                H3D      Scene = new H3D();
                Scene.Models.Add(model);
                return(Scene);

            case ".mbn":
                using (FileStream Input = new FileStream(FileName, FileMode.Open))
                {
                    H3D BaseScene = H3D.Open(File.ReadAllBytes(FileName.Replace(".mbn", ".bch")));

                    MBn ModelBinary = new MBn(new BinaryReader(Input), BaseScene);

                    return(ModelBinary.ToH3D());
                }
            }

            //Formats that can only be indetified by "magic numbers"
            H3D Output = null;

            using (FileStream FS = new FileStream(FileName, FileMode.Open))
            {
                if (FS.Length > 4)
                {
                    BinaryReader Reader = new BinaryReader(FS);

                    uint MagicNum = Reader.ReadUInt32();

                    FS.Seek(-4, SeekOrigin.Current);

                    string Magic = Encoding.ASCII.GetString(Reader.ReadBytes(4));

                    FS.Seek(0, SeekOrigin.Begin);

                    if (Magic.StartsWith("BCH"))
                    {
                        return(H3D.Open(Reader.ReadBytes((int)FS.Length)));
                    }
                    else if (Magic.StartsWith("MOD"))
                    {
                        return(LoadMTModel(Reader, FileName, Path.GetDirectoryName(FileName)));
                    }
                    else if (Magic.StartsWith("TEX"))
                    {
                        return(new MTTexture(Reader, Path.GetFileNameWithoutExtension(FileName)).ToH3D());
                    }
                    else if (Magic.StartsWith("MFX"))
                    {
                        MTShader = new MTShaderEffects(Reader);
                    }
                    else if (Magic.StartsWith("CGFX"))
                    {
                        return(Gfx.Open(FS));
                    }
                    else if (Magic.StartsWith("CMIF"))
                    {
                        return(new CMIFFile(new FileStream(FileName, FileMode.Open)).ToH3D());
                    }
                    else
                    {
                        if (GFPackage.IsValidPackage(FS))
                        {
                            GFPackage.Header PackHeader = GFPackage.GetPackageHeader(FS);

                            switch (PackHeader.Magic)
                            {
                            case "AL": Output = GFAreaLOD.OpenAsH3D(FS, PackHeader, 1); break;

                            case "AD": Output = GFPackedTexture.OpenAsH3D(FS, PackHeader, 1); break;

                            //case "BG": Output = GFL2OverWorld.OpenAsH3D(FS, PackHeader, Skeleton); break;
                            case "BS": Output = GFBtlSklAnim.OpenAsH3D(FS, PackHeader, Skeleton); break;

                            case "CM": Output = GFCharaModel.OpenAsH3D(FS, PackHeader); break;

                            case "GR": Output = GFOWMapModel.OpenAsH3D(FS, PackHeader); break;

                            case "MM": Output = GFOWCharaModel.OpenAsH3D(FS, PackHeader); break;

                            case "PC": Output = GFPkmnModel.OpenAsH3D(FS, PackHeader, Skeleton); break;

                            case "LL":
                            default:
                            case "PT": Output = GFPackedTexture.OpenAsH3D(FS, PackHeader, 0); break;

                            case "PK":
                            case "PB":
                                Output = GFPkmnSklAnim.OpenAsH3D(FS, PackHeader, Skeleton); break;
                            }
                        }
                        else
                        {
                            switch (MagicNum)
                            {
                            case 0x15122117:
                                Output = new H3D();

                                Output.Models.Add(new GFModel(Reader, "Model").ToH3DModel());

                                break;

                            case 0x15041213:
                                Output = new H3D();

                                Output.Textures.Add(new GFTexture(Reader).ToH3DTexture());

                                break;

                            case 0x00010000: Output = new GFModelPack(Reader).ToH3D(); break;

                            case 0x00060000:
                                if (Skeleton != null)
                                {
                                    Output = new H3D();

                                    GFMotion Motion = new GFMotion(Reader, 0);

                                    H3DAnimation    SklAnim = Motion.ToH3DSkeletalAnimation(Skeleton);
                                    H3DMaterialAnim MatAnim = Motion.ToH3DMaterialAnimation();
                                    H3DAnimation    VisAnim = Motion.ToH3DVisibilityAnimation();

                                    if (SklAnim != null)
                                    {
                                        Output.SkeletalAnimations.Add(SklAnim);
                                    }
                                    if (MatAnim != null)
                                    {
                                        Output.MaterialAnimations.Add(MatAnim);
                                    }
                                    if (VisAnim != null)
                                    {
                                        Output.VisibilityAnimations.Add(VisAnim);
                                    }
                                }

                                break;
                            }
                        }
                    }
                }
            }

            return(Output);
        }
Beispiel #16
0
        public H3DAnimation ToH3DSkeletalAnimation(H3DDict <H3DBone> Skeleton)
        {
            H3DAnimation Output = new H3DAnimation()
            {
                Name          = "GFMotion",
                FramesCount   = FramesCount,
                AnimationType = H3DAnimationType.Skeletal
            };

            foreach (GF1MotBoneTransform Bone in Bones)
            {
                H3DAnimTransform Transform = new H3DAnimTransform();

                SetKeyFrameGroup(Bone.TranslationX, Transform.TranslationX, 0);
                SetKeyFrameGroup(Bone.TranslationY, Transform.TranslationY, 1);
                SetKeyFrameGroup(Bone.TranslationZ, Transform.TranslationZ, 2);

                SetKeyFrameGroup(Bone.RotationX, Transform.RotationX, 3);
                SetKeyFrameGroup(Bone.RotationY, Transform.RotationY, 4);
                SetKeyFrameGroup(Bone.RotationZ, Transform.RotationZ, 5);

                SetKeyFrameGroup(Bone.ScaleX, Transform.ScaleX, 6);
                SetKeyFrameGroup(Bone.ScaleY, Transform.ScaleY, 7);
                SetKeyFrameGroup(Bone.ScaleZ, Transform.ScaleZ, 8);

                Output.Elements.Add(new H3DAnimationElement()
                {
                    Name          = Bone.Name,
                    Content       = Transform,
                    TargetType    = H3DTargetType.Bone,
                    PrimitiveType = H3DPrimitiveType.Transform
                });
            }

            //If we don't have a Skeleton then can't convert anything, just return with
            //what we have.
            if (Skeleton == null)
            {
                return(Output);
            }

            /*
             * Transform World Space bones to Local Space.
             * Not all animations have those.
             * This can be improved, for example, by supporting Scales aswell,
             * and checking for the special case where the World Space bone have no parent.
             * Those cases doesn't actually happen in any of the observed animations,
             * but it's always good pratice to check all fail paths.
             */
            int AnimIdx = 0;

            foreach (GF1MotBoneTransform Bone in Bones)
            {
                if (Bone.IsWorldSpace)
                {
                    if (!Skeleton.Contains(Bone.Name))
                    {
                        break;
                    }

                    H3DBone PoseBone = Skeleton[Bone.Name];

                    Vector3[] LocalTrans = new Vector3[FramesCount + 1];
                    Vector3[] ParentRot  = new Vector3[FramesCount + 1];

                    int    BoneIndex   = Skeleton.Find(Bone.Name);
                    int    ParentIndex = Skeleton[BoneIndex].ParentIndex;
                    string ParentName  = Skeleton[ParentIndex].Name;

                    for (int Frame = 0; Frame < FramesCount + 1; Frame++)
                    {
                        Matrix4x4 Transform = Matrix4x4.Identity;

                        int b = BoneIndex;

                        while ((b = Skeleton[b].ParentIndex) != -1)
                        {
                            GetBoneRT(
                                Output,
                                Skeleton,
                                Skeleton[b].Name,
                                Frame,
                                out Vector3 R,
                                out Vector3 T);

                            Transform *= Matrix4x4.CreateRotationX(R.X);
                            Transform *= Matrix4x4.CreateRotationY(R.Y);
                            Transform *= Matrix4x4.CreateRotationZ(R.Z);
                            Transform *= Matrix4x4.CreateTranslation(T);
                        }

                        GetBoneRT(
                            Output,
                            Skeleton,
                            ParentName,
                            Frame,
                            out Vector3 PR,
                            out Vector3 PT);

                        GetBoneRT(
                            Output,
                            Skeleton,
                            Bone.Name,
                            Frame,
                            out Vector3 BR,
                            out Vector3 BT);

                        Matrix4x4.Invert(Transform, out Matrix4x4 ITransform);

                        BT = Vector3.Transform(BT, ITransform);

                        Quaternion Rotation = VectorExtensions.CreateRotationBetweenVectors(PT, BT);

                        LocalTrans[Frame] = Vector3.Transform(BT, Quaternion.Inverse(Rotation));

                        ParentRot[Frame] = Rotation.ToEuler();
                    }

                    H3DAnimationElement B_Anim = Output.Elements[AnimIdx];
                    H3DAnimationElement P_Anim = Output.Elements.Find(x => x.Name == ParentName);

                    if (P_Anim == null)
                    {
                        P_Anim = new H3DAnimationElement()
                        {
                            Name          = ParentName,
                            Content       = new H3DAnimTransform(),
                            TargetType    = H3DTargetType.Bone,
                            PrimitiveType = H3DPrimitiveType.Transform
                        };

                        Output.Elements.Add(P_Anim);
                    }

                    H3DAnimTransform B_AT = (H3DAnimTransform)B_Anim.Content;
                    H3DAnimTransform P_AT = (H3DAnimTransform)P_Anim.Content;

                    AddVectors(LocalTrans, B_AT.TranslationX, B_AT.TranslationY, B_AT.TranslationZ);

                    if (!P_AT.RotationExists)
                    {
                        AddVectors(ParentRot, P_AT.RotationX, P_AT.RotationY, P_AT.RotationZ);
                    }
                }

                AnimIdx++;
            }

            return(Output);
        }
Beispiel #17
0
        public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, int FileIndex, int AnimCount, H3DDict <H3DBone> Skeleton = null)
        {
            int fileIndex = FileIndex;
            H3D Output    = default(H3D);

            BinaryReader Reader = new BinaryReader(Input);

            try
            {
                Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

                uint MagicNum = Reader.ReadUInt32();

                switch (MagicNum)
                {
                case GFModelConstant:
                    GFModelPack MdlPack = new GFModelPack();

                    //High Poly Pokémon model
                    Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin);

                    MdlPack.Models.Add(new GFModel(Reader, "PM_HighPoly"));

                    //Low Poly Pokémon model
                    Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin);

                    MdlPack.Models.Add(new GFModel(Reader, "PM_LowPoly"));

                    //Pokémon Shader package
                    Input.Seek(Header.Entries[2].Address, SeekOrigin.Begin);

                    GFPackage.Header PSHeader = GFPackage.GetPackageHeader(Input);

                    foreach (GFPackage.Entry Entry in PSHeader.Entries)
                    {
                        Input.Seek(Entry.Address, SeekOrigin.Begin);

                        MdlPack.Shaders.Add(new GFShader(Reader));
                    }

                    //More shaders
                    Input.Seek(Header.Entries[3].Address, SeekOrigin.Begin);

                    if (GFPackage.IsValidPackage(Input))
                    {
                        GFPackage.Header PCHeader = GFPackage.GetPackageHeader(Input);

                        foreach (GFPackage.Entry Entry in PCHeader.Entries)
                        {
                            Input.Seek(Entry.Address, SeekOrigin.Begin);

                            MdlPack.Shaders.Add(new GFShader(Reader));
                        }
                    }

                    Output = MdlPack.ToH3D();

                    break;

                case GFTextureConstant:
                    Output = new H3D();

                    foreach (GFPackage.Entry Entry in Header.Entries)
                    {
                        Input.Seek(Entry.Address, SeekOrigin.Begin);

                        Output.Textures.Add(new GFTexture(Reader).ToH3DTexture());
                    }

                    break;

                case GFMotionConstant:
                    Output = new H3D();

                    if (Skeleton == null)
                    {
                        break;
                    }
                    HashSet <uint> sklAdresses        = new HashSet <uint>();
                    HashSet <uint> materialAdresses   = new HashSet <uint>();
                    HashSet <uint> visibilityAdresses = new HashSet <uint>();
                    for (int Index = 0; Index < Header.Entries.Length; Index++)
                    {
                        Input.Seek(Header.Entries[Index].Address, SeekOrigin.Begin);
                        if (Input.Position + 4 > Input.Length)
                        {
                            break;
                        }
                        if (Reader.ReadUInt32() != GFMotionConstant)
                        {
                            continue;
                        }

                        Input.Seek(-4, SeekOrigin.Current);

                        GFMotion Mot = new GFMotion(Reader, Index);

                        H3DAnimation    SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton);
                        H3DMaterialAnim MatAnim = Mot.ToH3DMaterialAnimation();
                        H3DAnimation    VisAnim = Mot.ToH3DVisibilityAnimation();

                        if (SklAnim != null)
                        {
                            // SklAnim.Name = $"Motion_{Mot.Index}";

                            // Output.SkeletalAnimations.Add(SklAnim);

                            if (!sklAdresses.Contains(Header.Entries[Index].Address))
                            {
                                Output.SkeletalAnimations.Add(SklAnim);
                                sklAdresses.Add(Header.Entries[Index].Address);
                                Console.WriteLine("skeletal " + Header.Entries[Index].Address);
                            }
                        }

                        if (MatAnim != null)
                        {
                            //MatAnim.Name = $"Motion_{Mot.Index}";

                            if (!materialAdresses.Contains(Header.Entries[Index].Address))
                            {
                                Output.MaterialAnimations.Add(MatAnim);
                                materialAdresses.Add(Header.Entries[Index].Address);
                                Console.WriteLine("material " + Header.Entries[Index].Address);
                            }
                        }

                        if (VisAnim != null)
                        {
                            //VisAnim.Name = $"Motion_{Mot.Index}";

                            Output.VisibilityAnimations.Add(VisAnim);
                            if (!visibilityAdresses.Contains(Header.Entries[Index].Address))
                            {
                                Output.VisibilityAnimations.Add(VisAnim);
                                visibilityAdresses.Add(Header.Entries[Index].Address);
                                Console.WriteLine("visibility " + Header.Entries[Index].Address);
                            }
                        }
                    }
                    // Console.WriteLine(Output.SkeletalAnimations.Count);
                    // Console.WriteLine(AnimCount);
                    while (Output.SkeletalAnimations.Count > AnimCount)
                    {
                        Output.SkeletalAnimations.Remove(Output.SkeletalAnimations.Count - 1);
                    }
                    // if (fileIndex == 4)
                    // {
                    //
                    // }
                    //todo здесь проверку
                    // if (Output.SkeletalAnimations.Any())
                    // {
                    //     Output.SkeletalAnimations.Remove(Output.SkeletalAnimations.Count-1);
                    // }

                    break;

                case BCHConstant:
                    Output = new H3D();

                    foreach (GFPackage.Entry Entry in Header.Entries)
                    {
                        Input.Seek(Entry.Address, SeekOrigin.Begin);

                        MagicNum = Reader.ReadUInt32();

                        if (MagicNum != BCHConstant)
                        {
                            continue;
                        }

                        Input.Seek(-4, SeekOrigin.Current);

                        byte[] Buffer = Reader.ReadBytes(Entry.Length);

                        Output.Merge(H3D.Open(Buffer));
                    }

                    break;
                }

                return(Output);
            }
            catch (EndOfStreamException e)
            {
                return(new H3D());

                throw;
            }
        }
Beispiel #18
0
 public void LoadAnimation(H3DAnimation animation)
 {
     bchUserDataEditor1.LoadUserData(animation.MetaData);
 }
Beispiel #19
0
        private AnimationContent ImportSkeletalAnimation(H3DModel model, H3DAnimation animation)
        {
            var framesCount = (int)animation.FramesCount + 1;

            var animationNode = new AnimationContent
            {
                Name     = animation.Name,
                Identity = _identity,
                Duration = TimeSpan.FromSeconds((float)1 / (float)30 * (float)framesCount)
            };


            foreach (var elem in animation.Elements)
            {
                if (elem.PrimitiveType != H3DPrimitiveType.Transform && elem.PrimitiveType != H3DPrimitiveType.QuatTransform)
                {
                    continue;
                }

                var sklBone = model.Skeleton.FirstOrDefault(x => x.Name == elem.Name);
                var parent  = sklBone != null && sklBone.ParentIndex != -1 ? model.Skeleton[sklBone.ParentIndex] : null;

                var channel = new AnimationChannel();
                for (var frame = 0; frame < framesCount; frame++)
                {
                    var translation = Matrix.Identity;
                    if (elem.Content is H3DAnimTransform transform0)
                    {
                        if (!transform0.TranslationExists)
                        {
                            continue;
                        }

                        translation = Matrix.CreateTranslation(new Vector3(
                                                                   transform0.TranslationX.Exists ? transform0.TranslationX.GetFrameValue(frame) : sklBone.Translation.X,
                                                                   transform0.TranslationY.Exists ? transform0.TranslationY.GetFrameValue(frame) : sklBone.Translation.Y,
                                                                   transform0.TranslationZ.Exists ? transform0.TranslationZ.GetFrameValue(frame) : sklBone.Translation.Z));
                    }
                    else if (elem.Content is H3DAnimQuatTransform quatTransform)
                    {
                        if (!quatTransform.HasTranslation)
                        {
                            continue;
                        }

                        translation = Matrix.CreateTranslation(quatTransform.GetTranslationValue(frame).ToXNA());
                    }

                    var rotation = Matrix.Identity;
                    if (elem.Content is H3DAnimTransform transform1)
                    {
                        if (!(transform1.RotationX.Exists || transform1.RotationY.Exists ||
                              transform1.RotationZ.Exists))
                        {
                            continue;
                        }

                        rotation = Matrix.CreateRotationX(transform1.RotationX.GetFrameValue(frame)) *
                                   Matrix.CreateRotationY(transform1.RotationY.GetFrameValue(frame)) *
                                   Matrix.CreateRotationZ(transform1.RotationZ.GetFrameValue(frame));
                    }
                    else if (elem.Content is H3DAnimQuatTransform quatTransform)
                    {
                        if (!quatTransform.HasRotation)
                        {
                            continue;
                        }

                        rotation = Matrix.CreateFromQuaternion(quatTransform.GetRotationValue(frame).ToXNA());
                    }

                    var scale    = Matrix.Identity;
                    var invScale = System.Numerics.Vector3.One;
                    var pElem    = animation.Elements.FirstOrDefault(x => x.Name == parent?.Name);
                    if (elem.Content is H3DAnimTransform transform2)
                    {
                        if (!transform2.ScaleExists)
                        {
                            continue;
                        }

                        //Compensate parent bone scale (basically, don't inherit scales)
                        if (parent != null && (sklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0)
                        {
                            if (pElem != null)
                            {
                                var pTrans = (H3DAnimTransform)pElem.Content;

                                invScale /= new System.Numerics.Vector3(
                                    pTrans.ScaleX.Exists ? pTrans.ScaleX.GetFrameValue(frame) : parent.Scale.X,
                                    pTrans.ScaleY.Exists ? pTrans.ScaleY.GetFrameValue(frame) : parent.Scale.Y,
                                    pTrans.ScaleZ.Exists ? pTrans.ScaleZ.GetFrameValue(frame) : parent.Scale.Z);
                            }
                            else
                            {
                                invScale /= parent.Scale;
                            }
                        }

                        scale = Matrix.CreateScale((invScale * new System.Numerics.Vector3(
                                                        transform2.ScaleX.Exists ? transform2.ScaleX.GetFrameValue(frame) : sklBone.Scale.X,
                                                        transform2.ScaleY.Exists ? transform2.ScaleY.GetFrameValue(frame) : sklBone.Scale.Y,
                                                        transform2.ScaleZ.Exists ? transform2.ScaleZ.GetFrameValue(frame) : sklBone.Scale.Z)).ToXNA());
                    }
                    else if (elem.Content is H3DAnimQuatTransform quatTransform)
                    {
                        if (!quatTransform.HasScale)
                        {
                            continue;
                        }

                        //Compensate parent bone scale (basically, don't inherit scales)
                        if (parent != null && (sklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0)
                        {
                            if (pElem != null)
                            {
                                invScale /= ((H3DAnimQuatTransform)pElem.Content).GetScaleValue(frame);
                            }
                            else
                            {
                                invScale /= parent.Scale;
                            }
                        }

                        scale = Matrix.CreateScale((invScale * quatTransform.GetScaleValue(frame)).ToXNA());
                    }

                    channel.Add(new AnimationKeyframe(TimeSpan.FromSeconds((float)frame / 30f), scale * rotation * translation));
                }

                animationNode.Channels[elem.Name] = channel;
            }

            return(animationNode);
        }