/// <summary> /// /// </summary> /// <param name="animJoint"></param> public static int AdaptiveCompressAnimation(HSD_AnimJoint j, JointMap map, int index = 0) { float error = map == null ? 0.001f : map.GetError(index); if (j.AOBJ != null) { foreach (var t in j.AOBJ.FObjDesc.List) { var player = new FOBJ_Player(); player.Keys = t.GetDecodedKeys(); BakeTrack(player); CompressTrack(player, error); t.SetKeys(player.Keys, t.TrackType); } } if (j.Child != null) { foreach (var c in j.Children) { index = AdaptiveCompressAnimation(c, map, index + 1); } } return(index); }
/// <summary> /// /// </summary> /// <param name="animJoint"></param> public static void OptimizeTracks(HSD_JOBJ model, HSD_AnimJoint animJoint, float epsilon = 0.001f) { var joints = model.BreathFirstList; var anim_joints = animJoint.BreathFirstList; if (joints.Count != anim_joints.Count) { return; } for (int i = 0; i < joints.Count; i++) { if (anim_joints[i].AOBJ != null) { Dictionary <JointTrackType, float> typeToDefaultValue = new Dictionary <JointTrackType, float>(); typeToDefaultValue.Add(JointTrackType.HSD_A_J_TRAX, joints[i].TX); typeToDefaultValue.Add(JointTrackType.HSD_A_J_TRAY, joints[i].TY); typeToDefaultValue.Add(JointTrackType.HSD_A_J_TRAZ, joints[i].TZ); typeToDefaultValue.Add(JointTrackType.HSD_A_J_ROTX, joints[i].RX); typeToDefaultValue.Add(JointTrackType.HSD_A_J_ROTY, joints[i].RY); typeToDefaultValue.Add(JointTrackType.HSD_A_J_ROTZ, joints[i].RZ); typeToDefaultValue.Add(JointTrackType.HSD_A_J_SCAX, joints[i].SX); typeToDefaultValue.Add(JointTrackType.HSD_A_J_SCAY, joints[i].SY); typeToDefaultValue.Add(JointTrackType.HSD_A_J_SCAZ, joints[i].SZ); var tracks = anim_joints[i].AOBJ.FObjDesc.List; HSD_FOBJDesc prev = null; foreach (var t in tracks) { var keys = t.GetDecodedKeys(); if (typeToDefaultValue.ContainsKey(t.JointTrackType) && ConstantTrack(keys, typeToDefaultValue[t.JointTrackType], epsilon)) { if (prev != null) { prev.Next = t; } else { anim_joints[i].AOBJ.FObjDesc = t; } } else { prev = t; } } if (anim_joints[i].AOBJ.FObjDesc != null) { System.Diagnostics.Debug.WriteLine($"{tracks.Count} -> {anim_joints[i].AOBJ.FObjDesc.List.Count}"); } else { anim_joints[i].AOBJ = null; } } } }
/// <summary> /// /// </summary> /// <param name="joint"></param> public void FromAnimJoint(HSD_AnimJoint joint) { Nodes.Clear(); FrameCount = 0; if (joint == null) { return; } foreach (var j in joint.BreathFirstList) { AnimNode n = new AnimNode(); if (j.AOBJ != null) { FrameCount = (int)Math.Max(FrameCount, j.AOBJ.EndFrame + 1); foreach (var fdesc in j.AOBJ.FObjDesc.List) { var players = new FOBJ_Player(fdesc); if (players.Keys != null && players.Keys.Count > 0) { FrameCount = Math.Max(FrameCount, players.Keys.Max(e => e.Frame + 1)); } n.Tracks.Add(players); } } Nodes.Add(n); } }
/// <summary> /// /// </summary> /// <param name="joint"></param> public int SetAnimJoint(HSD_AnimJoint joint) { Nodes.Clear(); int max = 0; if (joint == null) { return(0); } foreach (var j in joint.BreathFirstSearch) { AnimNode n = new AnimNode(); if (j.AOBJ != null) { max = (int)Math.Max(max, j.AOBJ.EndFrame); foreach (var fdesc in j.AOBJ.FObjDesc.List) { AnimTrack track = new AnimTrack(); track.TrackType = fdesc.AnimationType; track.Keys = fdesc.GetDecodedKeys(); n.Tracks.Add(track); } } Nodes.Add(n); } return(max); }
/// <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); }
/* * * def flip_euler(euler, rotation_mode): * ret = euler.copy() * inner_axis = rotation_mode[0] * outer_axis = rotation_mode[2] * middle_axis = rotation_mode[1] * * ret[euler_axis_index(z)] += pi * ret[euler_axis_index(x)] += pi * ret[euler_axis_index(y)] *= -1 * ret[euler_axis_index(y)] += pi * return ret * */ /// <summary> /// /// </summary> private static void RemoveUnusedTracks(HSD_JOBJ model, HSD_AnimJoint animJoint) { JointAnimManager manager = new JointAnimManager(); manager.FromAnimJoint(animJoint); var joints = model.BreathFirstList; if (joints.Count != manager.Nodes.Count) { return; } for (int i = 0; i < joints.Count; i++) { var fobjs = manager.Nodes[i].Tracks; var toRem = new List <FOBJ_Player>(); foreach (var f in fobjs) { bool remove = false; switch (f.JointTrackType) { case JointTrackType.HSD_A_J_TRAX: remove = RemoveTrack(f, joints[i].TX); break; case JointTrackType.HSD_A_J_TRAY: remove = RemoveTrack(f, joints[i].TY); break; case JointTrackType.HSD_A_J_TRAZ: remove = RemoveTrack(f, joints[i].TZ); break; case JointTrackType.HSD_A_J_ROTX: remove = RemoveTrack(f, joints[i].RX); break; case JointTrackType.HSD_A_J_ROTY: remove = RemoveTrack(f, joints[i].RY); break; case JointTrackType.HSD_A_J_ROTZ: remove = RemoveTrack(f, joints[i].RZ); break; case JointTrackType.HSD_A_J_SCAX: remove = RemoveTrack(f, joints[i].SX); break; case JointTrackType.HSD_A_J_SCAY: remove = RemoveTrack(f, joints[i].SY); break; case JointTrackType.HSD_A_J_SCAZ: remove = RemoveTrack(f, joints[i].SZ); break; } if (remove) { toRem.Add(f); } } foreach (var v in toRem) { fobjs.Remove(v); } } var newAnimJoint = manager.ToAnimJoint(model, AOBJ_Flags.ANIM_LOOP); animJoint._s = newAnimJoint._s; }
/// <summary> /// /// </summary> /// <param name="node"></param> /// <returns></returns> public static HSD_AnimJoint GenerateAnimJointFromJOBJ(HSD_JOBJ node) { HSD_AnimJoint joint = new HSD_AnimJoint(); foreach (var v in node.Children) { joint.AddChild(GenerateAnimJointFromJOBJ(v)); } return(joint); }
/// <summary> /// /// </summary> /// <param name="root"></param> /// <param name="nodes"></param> /// <param name="flags"></param> /// <returns></returns> private HSD_AnimJoint ToAnimJointRecursive(HSD_JOBJ root, AOBJ_Flags flags) { HSD_AnimJoint joint = new HSD_AnimJoint(); joint.Flags = 1; AnimNode n = null; if (index >= Nodes.Count) { n = new AnimNode(); } else { n = Nodes[index++]; } // set flags if (n.Tracks.Count > 0) { joint.AOBJ = new HSD_AOBJ(); joint.AOBJ.Flags = flags; } // add all tracks foreach (var t in n.Tracks) { joint.AOBJ.EndFrame = Math.Max(joint.AOBJ.EndFrame, t.FrameCount); HSD_FOBJDesc fobj = t.ToFobjDesc(); if (joint.AOBJ.FObjDesc == null) { joint.AOBJ.FObjDesc = fobj; } else { joint.AOBJ.FObjDesc.Add(fobj); } } // set particle flag if (n.Tracks.Any(e => e.JointTrackType == JointTrackType.HSD_A_J_PTCL)) { joint.AOBJ.EndFrame += 0.1f; } foreach (var c in root.Children) { joint.AddChild(ToAnimJointRecursive(c, flags)); } return(joint); }
/// <summary> /// /// </summary> /// <param name="root"></param> /// <param name="nodes"></param> /// <param name="flags"></param> /// <returns></returns> private HSD_AnimJoint ToAnimJointRecursive(HSD_JOBJ root, AOBJ_Flags flags) { HSD_AnimJoint joint = new HSD_AnimJoint(); joint.Flags = 1; AnimNode n = null; if (index >= Nodes.Count) { n = new AnimNode(); } else { n = Nodes[index++]; } if (n.Tracks.Count > 0) { joint.AOBJ = new HSD_AOBJ(); joint.AOBJ.Flags = flags; } foreach (var t in n.Tracks) { joint.AOBJ.EndFrame = Math.Max(joint.AOBJ.EndFrame, t.FrameCount); HSD_FOBJDesc fobj = new HSD_FOBJDesc(); fobj.SetKeys(t.Keys, (byte)t.TrackType); if (joint.AOBJ.FObjDesc == null) { joint.AOBJ.FObjDesc = fobj; } else { joint.AOBJ.FObjDesc.Add(fobj); } } foreach (var c in root.Children) { joint.AddChild(ToAnimJointRecursive(c, flags)); } return(joint); }
/// <summary> /// /// </summary> /// <param name="animJoint"></param> public static void CompressAnimation(HSD_AnimJoint animJoint, float epsilon = 0.001f) { foreach (var j in animJoint.BreathFirstList) { if (j.AOBJ != null) { foreach (var t in j.AOBJ.FObjDesc.List) { var player = new FOBJ_Player(); player.Keys = t.GetDecodedKeys(); BakeTrack(player); CompressTrack(player, epsilon); t.SetKeys(player.Keys, t.TrackType); } } } }
/// <summary> /// /// </summary> /// <param name="icons"></param> /// <returns></returns> public static Tuple <HSD_JOBJ, HSD_AnimJoint, HSD_MatAnimJoint> GenerateIconModel(MEX_CSSIconEntry[] icons) { HSD_JOBJ position_joint = new HSD_JOBJ(); position_joint.Flags = JOBJ_FLAG.CLASSICAL_SCALING | JOBJ_FLAG.ROOT_XLU; position_joint.SX = 1; position_joint.SY = 1; position_joint.SZ = 1; HSD_AnimJoint anim_joint = new HSD_AnimJoint(); HSD_MatAnimJoint matanim_joint = new HSD_MatAnimJoint(); foreach (var ico in icons) { ico.Joint.Next = null; ico.AnimJoint.Next = null; ico.MatAnimJoint.Next = null; position_joint.AddChild(ico.Joint); anim_joint.AddChild(ico.AnimJoint); matanim_joint.AddChild(ico.MatAnimJoint); } return(new Tuple <HSD_JOBJ, HSD_AnimJoint, HSD_MatAnimJoint>(position_joint, anim_joint, matanim_joint)); }
/// <summary> /// /// </summary> /// <param name="joint"></param> public void FromAnimJoint(HSD_AnimJoint joint) { Nodes.Clear(); FrameCount = 0; if (joint == null) { return; } foreach (var j in joint.BreathFirstList) { AnimNode n = new AnimNode(); if (j.AOBJ != null) { FrameCount = (int)Math.Max(FrameCount, j.AOBJ.EndFrame); foreach (var fdesc in j.AOBJ.FObjDesc.List) { n.Tracks.Add(new FOBJ_Player(fdesc)); } } Nodes.Add(n); } }
/// <summary> /// /// </summary> /// <param name="stage"></param> /// <param name="icons"></param> public static MEX_mexMapData GenerateMexMap(SBM_MnSelectStageDataTable stage, IEnumerable <MEXStageIconEntry> icons) { MEX_mexMapData mapData = new MEX_mexMapData(); var nameTexAnim = new HSD_TexAnim(); var nameKeys = new List <FOBJKey>(); var iconTexAnim = new HSD_TexAnim(); var iconKeys = new List <FOBJKey>(); HSD_JOBJ root = new HSD_JOBJ() { SX = 1, SY = 1, SZ = 1, Flags = JOBJ_FLAG.CLASSICAL_SCALING }; HSD_AnimJoint animRoot = new HSD_AnimJoint(); // extra { var tobjs = stage.IconLargeMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation.ToTOBJs(); var index = iconTexAnim.AddImage(tobjs[0]); iconKeys.Add(new FOBJKey() { Frame = index, Value = index, InterpolationType = GXInterpolationType.HSD_A_OP_CON }); index = iconTexAnim.AddImage(tobjs[1]); iconKeys.Add(new FOBJKey() { Frame = index, Value = index, InterpolationType = GXInterpolationType.HSD_A_OP_CON }); } foreach (var v in icons) { var index = iconTexAnim.AddImage(v.IconTOBJ); if (index == -1) { index = 0; } iconKeys.Add(new FOBJKey() { Frame = index, Value = index, InterpolationType = GXInterpolationType.HSD_A_OP_CON }); index = nameTexAnim.AddImage(v.NameTOBJ); if (index == -1) { index = 0; } nameKeys.Add(new FOBJKey() { Frame = index, Value = index, InterpolationType = GXInterpolationType.HSD_A_OP_CON }); v.Joint.Next = null; v.Joint.Child = null; v.AnimJoint.Next = null; v.AnimJoint.Child = null; root.AddChild(v.Joint); animRoot.AddChild(v.AnimJoint); } iconKeys.Add(new FOBJKey() { Frame = 1600, Value = 0, InterpolationType = GXInterpolationType.HSD_A_OP_CON }); iconTexAnim.GXTexMapID = HSDRaw.GX.GXTexMapID.GX_TEXMAP0; iconTexAnim.AnimationObject = new HSD_AOBJ(); iconTexAnim.AnimationObject.EndFrame = 1600; iconTexAnim.AnimationObject.FObjDesc = new HSD_FOBJDesc(); iconTexAnim.AnimationObject.FObjDesc.SetKeys(iconKeys, (byte)TexTrackType.HSD_A_T_TIMG); iconTexAnim.AnimationObject.FObjDesc.Next = new HSD_FOBJDesc(); iconTexAnim.AnimationObject.FObjDesc.Next.SetKeys(iconKeys, (byte)TexTrackType.HSD_A_T_TCLT); var iconJOBJ = HSDAccessor.DeepClone <HSD_JOBJ>(stage.IconDoubleModel); iconJOBJ.Child = iconJOBJ.Child.Next; var iconAnimJoint = HSDAccessor.DeepClone <HSD_AnimJoint>(stage.IconDoubleAnimJoint); iconAnimJoint.Child = iconAnimJoint.Child.Next; var iconMatAnimJoint = HSDAccessor.DeepClone <HSD_MatAnimJoint>(stage.IconDoubleMatAnimJoint); iconMatAnimJoint.Child = iconMatAnimJoint.Child.Next; iconMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation = iconTexAnim; var iconNameAnim = HSDAccessor.DeepClone <HSD_MatAnimJoint>(stage.StageNameMatAnimJoint); nameTexAnim.AnimationObject = new HSD_AOBJ(); nameTexAnim.AnimationObject.EndFrame = 1600; nameTexAnim.AnimationObject.FObjDesc = new HSD_FOBJDesc(); nameTexAnim.AnimationObject.FObjDesc.SetKeys(nameKeys, (byte)TexTrackType.HSD_A_T_TIMG); iconNameAnim.Child.Child.MaterialAnimation.TextureAnimation = nameTexAnim; mapData.IconModel = iconJOBJ; mapData.IconAnimJoint = iconAnimJoint; mapData.IconMatAnimJoint = iconMatAnimJoint; mapData.PositionModel = root; mapData.PositionAnimJoint = animRoot; mapData.StageNameMaterialAnimation = iconNameAnim; return(mapData); }
/// <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; } }
/// <summary> /// /// </summary> public JointAnimManager(HSD_AnimJoint joint) { FromAnimJoint(joint); }
/// <summary> /// Builds simple mex menu animation from anim joint using assumptions about the animation /// </summary> /// <param name="j"></param> /// <returns></returns> public static MexMenuAnimation FromAnimJoint(HSD_AnimJoint j, HSD_JOBJ jobj) { var anim = new MexMenuAnimation() { StartFrame = 0, EndFrame = 0, StartingPositionX = jobj.TX, StartingPositionY = jobj.TY, StartingPositionZ = jobj.TZ, StartingRotationX = jobj.RX, StartingRotationY = jobj.RY, StartingRotationZ = jobj.RZ, StartingScaleX = jobj.SX, StartingScaleY = jobj.SY, StartingScaleZ = jobj.SZ, }; if (j.AOBJ != null && j.AOBJ.FObjDesc != null) { foreach (var fobj in j.AOBJ.FObjDesc.List) { // get when frame starts moving // get frame // get value // that's all we, we assume final position is what the joint is currently at var keys = fobj.GetDecodedKeys(); for (int i = 0; i < keys.Count; i++) { var k = keys[i]; if (k.InterpolationType != GXInterpolationType.HSD_A_OP_CON) { anim.StartFrame = (int)Math.Max(anim.StartFrame, k.Frame); anim.EndFrame = (int)Math.Max(anim.EndFrame, keys[i + 1].Frame); switch ((JointTrackType)fobj.TrackType) { case JointTrackType.HSD_A_J_TRAX: anim.StartingPositionX = k.Value; break; case JointTrackType.HSD_A_J_TRAY: anim.StartingPositionY = k.Value; break; case JointTrackType.HSD_A_J_TRAZ: anim.StartingPositionZ = k.Value; break; case JointTrackType.HSD_A_J_ROTX: anim.StartingRotationX = k.Value; break; case JointTrackType.HSD_A_J_ROTY: anim.StartingRotationY = k.Value; break; case JointTrackType.HSD_A_J_ROTZ: anim.StartingRotationZ = k.Value; break; case JointTrackType.HSD_A_J_SCAX: anim.StartingScaleX = k.Value; break; case JointTrackType.HSD_A_J_SCAY: anim.StartingScaleY = k.Value; break; case JointTrackType.HSD_A_J_SCAZ: anim.StartingScaleZ = k.Value; break; } break; } } } } return(anim); }
{/// <summary> /// /// </summary> /// <param name="space"></param> /// <returns></returns> public static HSD_AnimJoint GenerateAnimJoint(MexMenuAnimation anim, HSD_JOBJ joint) { HSD_AnimJoint aj = new HSD_AnimJoint(); if (anim == null || anim.StartFrame >= anim.EndFrame) { return(aj); } var aobj = new HSD_AOBJ(); aobj.EndFrame = 1600; aobj.Flags = AOBJ_Flags.FIRST_PLAY; if (anim.StartingPositionX != joint.TX) { GenerateFOBJ(aobj, anim.StartingPositionX, joint.TX, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_TRAX); } if (anim.StartingPositionY != joint.TY) { GenerateFOBJ(aobj, anim.StartingPositionY, joint.TY, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_TRAY); } if (anim.StartingPositionZ != joint.TZ) { GenerateFOBJ(aobj, anim.StartingPositionZ, joint.TZ, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_TRAZ); } if (anim.StartingRotationX != joint.RX) { GenerateFOBJ(aobj, anim.StartingRotationX, joint.RX, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_ROTX); } if (anim.StartingRotationY != joint.RY) { GenerateFOBJ(aobj, anim.StartingRotationY, joint.RY, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_ROTY); } if (anim.StartingRotationZ != joint.RZ) { GenerateFOBJ(aobj, anim.StartingRotationZ, joint.RZ, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_ROTZ); } if (anim.StartingScaleX != joint.SX) { GenerateFOBJ(aobj, anim.StartingRotationX, joint.SX, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_SCAX); } if (anim.StartingScaleY != joint.SY) { GenerateFOBJ(aobj, anim.StartingRotationY, joint.SY, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_SCAY); } if (anim.StartingScaleZ != joint.SZ) { GenerateFOBJ(aobj, anim.StartingRotationZ, joint.SZ, anim.StartFrame, anim.EndFrame, JointTrackType.HSD_A_J_SCAZ); } if (aobj.FObjDesc != null) { aj.AOBJ = aobj; } return(aj); // starting frame-600 // 1600 total frames /*if (space.AnimType == MexMapAnimType.SlideInFromRight) * joint.AOBJ = GenerateAOBJ(36, space.JOBJ.TX, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_TRAX); * if (space.AnimType == MexMapAnimType.SlideInFromLeft) * joint.AOBJ = GenerateAOBJ(-40, space.JOBJ.TX, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_TRAX); * if (space.AnimType == MexMapAnimType.SlideInFromTop) * joint.AOBJ = GenerateAOBJ(36, space.JOBJ.TY, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_TRAY); * if (space.AnimType == MexMapAnimType.SlideInFromBottom) * joint.AOBJ = GenerateAOBJ(-40, space.JOBJ.TY, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_TRAY); * if (space.AnimType == MexMapAnimType.GrowFromNothing) * { * joint.AOBJ = GenerateAOBJ(0, space.JOBJ.SX, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_SCAX); * joint.AOBJ.FObjDesc.Next = GenerateAOBJ(0, space.JOBJ.SY, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_SCAY).FObjDesc; * } * if (space.AnimType == MexMapAnimType.SpinIn) * { * joint.AOBJ = GenerateAOBJ(0, space.JOBJ.SX, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_SCAX); * joint.AOBJ.FObjDesc.Add(GenerateAOBJ(0, space.JOBJ.SY, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_SCAY).FObjDesc); * joint.AOBJ.FObjDesc.Add(GenerateAOBJ(-4, 0, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_ROTZ).FObjDesc); * } * if (space.AnimType == MexMapAnimType.FlipIn) * { * joint.AOBJ = GenerateAOBJ(0, space.JOBJ.SX, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_SCAX); * joint.AOBJ.FObjDesc.Add(GenerateAOBJ(0, space.JOBJ.SY, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_SCAY).FObjDesc); * joint.AOBJ.FObjDesc.Add(GenerateAOBJ(-4, 0, space.StartFrame, space.EndFrame, JointTrackType.HSD_A_J_ROTY).FObjDesc); * }*/ }
/// <summary> /// Opens dat file from stream /// </summary> /// <param name="stream"></param> public void Open(Stream stream) { using (BinaryReaderExt r = new BinaryReaderExt(stream)) { r.BigEndian = true; // Parse Header ----------------------------- var fsize = r.ReadInt32(); // dat size int relocOffset = r.ReadInt32() + 0x20; int relocCount = r.ReadInt32(); int rootCount = r.ReadInt32(); int refCount = r.ReadInt32(); VersionChars = r.ReadChars(4); // Parse Relocation Table ----------------------------- List <int> Offsets = new List <int>(); HashSet <int> OffsetContain = new HashSet <int>(); Dictionary <int, int> relocOffsets = new Dictionary <int, int>(); Offsets.Add(relocOffset); r.BaseStream.Position = relocOffset; for (int i = 0; i < relocCount; i++) { int offset = r.ReadInt32() + 0x20; var temp = r.BaseStream.Position; r.BaseStream.Position = offset; var objectOff = r.ReadInt32() + 0x20; // if we need to read past end of file then we need to include filesize as an offset // this fixes files that had previously been manually relocated to end of file if (objectOff > relocOffset && !Offsets.Contains(fsize)) { Offsets.Add(fsize); } // if (objectOff < 0) { r.BaseStream.Position = temp; continue; } relocOffsets.Add(offset, objectOff); if (!OffsetContain.Contains(objectOff)) { OffsetContain.Add(objectOff); Offsets.Add(objectOff); } r.BaseStream.Position = temp; } // Parse Roots--------------------------------- List <int> rootOffsets = new List <int>(); List <string> rootStrings = new List <string>(); List <int> refOffsets = new List <int>(); List <string> refStrings = new List <string>(); var stringStart = r.BaseStream.Position + (refCount + rootCount) * 8; for (int i = 0; i < rootCount; i++) { rootOffsets.Add(r.ReadInt32() + 0x20); rootStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); } for (int i = 0; i < refCount; i++) { var refp = r.ReadInt32() + 0x20; refOffsets.Add(refp); refStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); var temp = r.Position; var special = refp; while (true) { r.Seek((uint)special); special = r.ReadInt32(); if (special == 0 || special == -1) { break; } special += 0x20; relocOffsets.Add(refp, special); refp = special; if (!OffsetContain.Contains(special)) { OffsetContain.Add(special); Offsets.Add(special); } } r.Seek(temp); } foreach (var v in rootOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } foreach (var v in refOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } // Split Raw Struct Data-------------------------- Offsets.Sort(); Dictionary <int, HSDStruct> offsetToStruct = new Dictionary <int, HSDStruct>(); Dictionary <int, List <int> > offsetToOffsets = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > offsetToInnerOffsets = new Dictionary <int, List <int> >(); var relockeys = relocOffsets.Keys.ToList(); for (int i = 0; i < Offsets.Count - 1; i++) { r.BaseStream.Position = Offsets[i]; byte[] data = r.ReadBytes(Offsets[i + 1] - Offsets[i]); if (!offsetToOffsets.ContainsKey(Offsets[i])) { var relocKets = relockeys.FindAll(e => e >= Offsets[i] && e < Offsets[i + 1]); var list = new List <int>(); foreach (var k in relocKets) { list.Add(relocOffsets[k]); } offsetToOffsets.Add(Offsets[i], list); offsetToInnerOffsets.Add(Offsets[i], relocKets); } if (!offsetToStruct.ContainsKey(Offsets[i])) { var struture = new HSDStruct(data); offsetToStruct.Add(Offsets[i], struture); } } // set references------------------------- foreach (var str in offsetToStruct) { var offsets = offsetToOffsets[str.Key]; var innerOffsets = offsetToInnerOffsets[str.Key]; for (int i = 0; i < offsets.Count; i++) { if (offsetToStruct.ContainsKey(offsets[i]) && str.Value.Length >= innerOffsets[i] - str.Key + 4) { str.Value.SetReferenceStruct(innerOffsets[i] - str.Key, offsetToStruct[offsets[i]]); } } _structCache.Add(str.Value); _structCacheToOffset.Add(str.Value, str.Key); } // set roots for (int i = 0; i < rootOffsets.Count; i++) { HSDStruct str = offsetToStruct[rootOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; if (rootStrings[i].EndsWith("shapeanim_joint")) { var acc = new HSDAccessor(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("matanim_joint")) { var acc = new HSD_MatAnimJoint(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_joint")) { var jobj = new HSD_JOBJ(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_animjoint")) { var jobj = new HSD_AnimJoint(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_texanim")) { var jobj = new HSD_TexAnim(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_figatree")) { var jobj = new HSD_FigaTree(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_scene_models") || rootStrings[i].Equals("Stc_rarwmdls") || rootStrings[i].Equals("Stc_scemdls") || rootStrings[i].Equals("lupe") || rootStrings[i].Equals("tdsce")) { var jobj = new HSDNullPointerArrayAccessor <HSD_JOBJDesc>(); jobj._s = str; a = jobj; } else if (rootStrings[i].StartsWith("ftData")) { var acc = new SBM_PlayerData(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("MnSelectChrDataTable")) { var acc = new SBM_SelectChrDataTable(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("MnSelectStageDataTable")) { var acc = new SBM_MnSelectStageDataTable(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("coll_data")) { var acc = new SBM_Coll_Data(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("scene_data") || rootStrings[i].Equals("pnlsce") || rootStrings[i].Equals("flmsce") || (rootStrings[i].StartsWith("Sc") && str.Length == 0x10)) { var acc = new HSD_SOBJ(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("map_plit")) { var acc = new HSDNullPointerArrayAccessor <HSD_Light>(); acc._s = str; a = acc; } /*else * if (rootStrings[i].StartsWith("grGroundParam")) * { * var acc = new SBM_GroundParam(); * acc._s = str; * a = acc; * }*/ else if (rootStrings[i].StartsWith("map_head")) { var acc = new SBM_Map_Head(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grGroundParam")) { var acc = new SBM_GroundParam(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("vcDataStar")) { var acc = new KAR_vcDataStar(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("vcDataWheel")) { var acc = new KAR_vcDataWheel(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grModelMotion")) { var acc = new KAR_grModelMotion(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grModel")) { var acc = new KAR_grModel(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grData")) { var acc = new KAR_grData(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_texg")) { var acc = new HSD_TEXGraphicBank(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_ptcl")) { var acc = new HSD_ParticleGroup(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("eff")) { var acc = new SBM_EffectTable(); acc._s = str; a = acc; } Roots.Add(new HSDRootNode() { Name = rootStrings[i], Data = a }); } // set references for (int i = 0; i < refOffsets.Count; i++) { HSDStruct str = offsetToStruct[refOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; References.Add(new HSDRootNode() { Name = refStrings[i], Data = a }); } } }
/// <summary> /// /// </summary> /// <param name="table"></param> /// <param name="icons"></param> /// <returns></returns> private static MEX_mexSelectChr GenerateMexSelectChrSymbol(SBM_SelectChrDataTable table, MEX_CSSIcon[] cssIcons) { // create mexSelectChr struct MEX_mexSelectChr mex = new MEX_mexSelectChr(); // generate icon model var icon_joint = HSDAccessor.DeepClone <HSD_JOBJ>(table.MenuModel.Children[2].Child); icon_joint.TX = 0; icon_joint.TY = 0; icon_joint.TZ = 0; icon_joint.Next = null; var center = RegenerateIcon(icon_joint); // generate material_anim_joint var icon_matanim_joint = HSDAccessor.DeepClone <HSD_MatAnimJoint>(table.MenuMaterialAnimation.Children[2].Child); icon_matanim_joint.Next = null; // general base models HSD_JOBJ position_joint = new HSD_JOBJ(); position_joint.Flags = JOBJ_FLAG.CLASSICAL_SCALING | JOBJ_FLAG.ROOT_XLU; position_joint.SX = 1; position_joint.SY = 1; position_joint.SZ = 1; HSD_AnimJoint anim_joint = new HSD_AnimJoint(); HSD_MatAnimJoint matanim_joint = new HSD_MatAnimJoint(); // create icon data var joints = table.MenuModel.BreathFirstList; var matanims = table.MenuAnimation.BreathFirstList; foreach (var ico in cssIcons) { if (joints[ico.JointID].Dobj == null) { continue; } HSD_JOBJ joint = HSDAccessor.DeepClone <HSD_JOBJ>(icon_joint); joint.Dobj.Pobj.Attributes = icon_joint.Dobj.Pobj.Attributes; joint.Dobj.Next.Pobj.Attributes = icon_joint.Dobj.Pobj.Attributes; joint.Dobj.Next.Mobj.Textures = HSDAccessor.DeepClone <HSD_TOBJ>(joints[ico.JointID].Dobj.Next.Mobj.Textures); var worldPosition = new GXVector3(joints[ico.JointID].TX, joints[ico.JointID].TY, joints[ico.JointID].TZ); // get anim var anim = matanims[ico.JointID].AOBJ; // if it's a clone get parent location if (ico.JointID < 15) { worldPosition = new GXVector3(joints[ico.JointID - 1].TX, joints[ico.JointID - 1].TY, joints[ico.JointID - 1].TZ); anim = matanims[ico.JointID - 1].AOBJ; } // check animation for world position if (anim != null) { foreach (var v in anim.FObjDesc.List) { System.Diagnostics.Debug.WriteLine(v.JointTrackType); if (v.JointTrackType == JointTrackType.HSD_A_J_TRAX) { var keys = v.GetDecodedKeys(); worldPosition.X = keys[keys.Count - 1].Value; } } } joint.TX = worldPosition.X + center.X; joint.TY = worldPosition.Y + center.Y; joint.TZ = worldPosition.Z + center.Z; position_joint.AddChild(joint); anim_joint.AddChild(new HSD_AnimJoint()); matanim_joint.AddChild(HSDAccessor.DeepClone <HSD_MatAnimJoint>(icon_matanim_joint)); } mex.IconModel = position_joint; mex.IconAnimJoint = anim_joint; mex.IconMatAnimJoint = matanim_joint; mex.CSPMatAnim = HSDAccessor.DeepClone <HSD_MatAnim>(table.MenuMaterialAnimation.Children[6].Child.MaterialAnimation); var cspkeys = mex.CSPMatAnim.TextureAnimation.AnimationObject.FObjDesc.GetDecodedKeys(); foreach (var k in cspkeys) { if ((k.Frame % 30) >= 19) { k.Frame++; } } mex.CSPMatAnim.TextureAnimation.AnimationObject.FObjDesc.SetKeys(cspkeys, (byte)TexTrackType.HSD_A_T_TIMG); mex.CSPMatAnim.TextureAnimation.AnimationObject.FObjDesc.Next.SetKeys(cspkeys, (byte)TexTrackType.HSD_A_T_TCLT); mex.CSPStride = 30; return(mex); }
/// <summary> /// /// </summary> /// <param name="stage"></param> /// <returns></returns> public static MEX_mexMapData LoadIconDataFromVanilla(SBM_MnSelectStageDataTable stage) { List <HSD_TOBJ> nameTags = new List <HSD_TOBJ>(); List <HSD_TOBJ> iconTOBJs = new List <HSD_TOBJ>(); HSD_JOBJ root = new HSD_JOBJ() { SX = 1, SY = 1, SZ = 1, Flags = JOBJ_FLAG.CLASSICAL_SCALING }; HSD_AnimJoint animRoot = new HSD_AnimJoint(); var tex0 = stage.IconDoubleMatAnimJoint.Child.Next.MaterialAnimation.Next.TextureAnimation.ToTOBJs(); var tex0_extra = stage.IconDoubleMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation.ToTOBJs(); var tex1 = stage.IconLargeMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation.ToTOBJs(); var tex2 = stage.IconSpecialMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation.ToTOBJs(); var nameTOBJs = stage.StageNameMatAnimJoint.Child.Child.MaterialAnimation.TextureAnimation.ToTOBJs(); var nameTOBJsAnim = stage.StageNameMatAnimJoint.Child.Child.MaterialAnimation.TextureAnimation.AnimationObject.FObjDesc.GetDecodedKeys(); var positionAnimation = new List <HSD_AnimJoint>(); foreach (var c in stage.PositionAnimation.Children) { var pos = new HSD_AnimJoint(); pos.AOBJ = HSDAccessor.DeepClone <HSD_AOBJ>(c.AOBJ); positionAnimation.Add(pos); } var g1 = tex0.Length - 2; var g2 = tex0.Length - 2 + tex1.Length - 2; var g3 = tex0.Length - 2 + tex1.Length - 2 + tex2.Length - 2; for (int i = 0; i < stage.PositionModel.Children.Length; i++) { var childIndex = i; if (unswizzle.ContainsKey(i)) { childIndex = unswizzle[i]; } HSD_TOBJ icon = null; HSD_TOBJ name = null; var keys = positionAnimation[childIndex].AOBJ.FObjDesc.GetDecodedKeys(); var Y = stage.PositionModel.Children[childIndex].TY; var Z = stage.PositionModel.Children[childIndex].TZ; var SX = 1f; var SY = 1f; if (i >= g3) { //RandomIcon name = nameTOBJs[(int)nameTOBJsAnim[nameTOBJsAnim.Count - 1].Value]; } else if (i >= g2) { name = nameTOBJs[(int)nameTOBJsAnim[24 + (i - g2)].Value]; icon = tex2[i - g2 + 2]; SX = 0.8f; SY = 0.8f; } else if (i >= g1) { name = nameTOBJs[(int)nameTOBJsAnim[22 + texunswizzle[i - g1]].Value]; icon = tex1[i - g1 + 2]; SY = 1.1f; } else { icon = tex0[texunswizzle[i] + 2]; name = nameTOBJs[(int)nameTOBJsAnim[texunswizzle[i]].Value * 2]; root.AddChild(new HSD_JOBJ() { TX = keys[keys.Count - 1].Value, TY = Y, TZ = Z, SX = SX, SY = SY, SZ = 1, Flags = JOBJ_FLAG.CLASSICAL_SCALING }); iconTOBJs.Add(icon); nameTags.Add(name); animRoot.AddChild(HSDAccessor.DeepClone <HSD_AnimJoint>(positionAnimation[childIndex])); Y -= 5.6f; Z = 0; icon = tex0_extra[texunswizzle[i] + 2]; name = nameTOBJs[(int)nameTOBJsAnim[texunswizzle[i]].Value * 2 + 1]; } root.AddChild(new HSD_JOBJ() { TX = keys[keys.Count - 1].Value, TY = Y, TZ = Z, SX = SX, SY = SY, SZ = 1, Flags = JOBJ_FLAG.CLASSICAL_SCALING }); iconTOBJs.Add(icon); nameTags.Add(name); animRoot.AddChild(HSDAccessor.DeepClone <HSD_AnimJoint>(positionAnimation[childIndex])); } var extraIcons = stage.IconLargeMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation.ToTOBJs(); iconTOBJs.Insert(0, extraIcons[0]); iconTOBJs.Insert(0, extraIcons[1]); iconTOBJs.Add(extraIcons[0]); var iconJOBJ = HSDAccessor.DeepClone <HSD_JOBJ>(stage.IconDoubleModel); iconJOBJ.Child = iconJOBJ.Child.Next; var iconAnimJoint = HSDAccessor.DeepClone <HSD_AnimJoint>(stage.IconDoubleAnimJoint); iconAnimJoint.Child = iconAnimJoint.Child.Next; var iconMatAnimJoint = HSDAccessor.DeepClone <HSD_MatAnimJoint>(stage.IconDoubleMatAnimJoint); iconMatAnimJoint.Child = iconMatAnimJoint.Child.Next; iconMatAnimJoint.Child.MaterialAnimation.Next.TextureAnimation.FromTOBJs(iconTOBJs.ToArray(), true); var mapdata = new MEX_mexMapData(); mapdata.IconModel = iconJOBJ; mapdata.IconAnimJoint = iconAnimJoint; mapdata.IconMatAnimJoint = iconMatAnimJoint; mapdata.PositionModel = root; mapdata.PositionAnimJoint = animRoot; mapdata.StageNameMaterialAnimation = HSDAccessor.DeepClone <HSD_MatAnimJoint>(stage.StageNameMatAnimJoint); mapdata.StageNameMaterialAnimation.Child.Child.MaterialAnimation.TextureAnimation.FromTOBJs(nameTags, true); return(mapdata); }