private static void EulerFilter(JointAnimManager anim) { foreach (var n in anim.Nodes) { foreach (var t in n.Tracks) { if (t.JointTrackType == JointTrackType.HSD_A_J_ROTX || t.JointTrackType == JointTrackType.HSD_A_J_ROTY || t.JointTrackType == JointTrackType.HSD_A_J_ROTZ) { // filter for (int i = 1; i < t.Keys.Count; i++) { var prevKey = t.Keys[i - 1]; var key = t.Keys[i]; if (Math.Abs(prevKey.Value - key.Value) > Math.PI) { if (prevKey.Value < key.Value) { key.Value -= (float)(2 * Math.PI); } else { key.Value += (float)(2 * Math.PI); } } } } } } }
/// <summary> /// /// </summary> public void SetJoint(HSD_JOBJ jobj, JointAnimManager animManager) { jointTree.BeginUpdate(); jointTree.Nodes.Clear(); var jobjs = jobj.BreathFirstList; Dictionary <HSD_JOBJ, JointNode> childToParent = new Dictionary <HSD_JOBJ, JointNode>(); for (int i = 0; i < Math.Min(animManager.NodeCount, jobjs.Count); i++) { var node = new JointNode() { JOBJ = jobjs[i], AnimNode = animManager.Nodes[i], Text = $"JOINT_{i}" }; foreach (var c in jobjs[i].Children) { childToParent.Add(c, node); } if (childToParent.ContainsKey(jobjs[i])) { childToParent[jobjs[i]].Nodes.Add(node); } else { jointTree.Nodes.Add(node); } } jointTree.ExpandAll(); jointTree.EndUpdate(); }
/* * * 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> private void UpdateAnimationWithFSMs() { // load backup animation var tempanim = new JointAnimManager(); tempanim.FromFigaTree(BackupAnim.ToFigaTree()); var backup = BackupAnim; // apply fsms to backup animation tempanim.ApplyFSMs(FrameSpeedModifiers); // load edited anim LoadFigaTree(SelectedAction.Symbol, tempanim.ToFigaTree()); BackupAnim = backup; // refresh fsm display tips UpdateFrameTips(); }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void compressAllAnimationsToolStripMenuItem_Click(object sender, EventArgs e) { if (AJManager == null) { return; } HashSet <string> edited = new HashSet <string>(); int oldSize = 0; int newSize = 0; foreach (var a in AllActions) { if (string.IsNullOrEmpty(a.Symbol) || edited.Contains(a.Symbol)) { continue; } var anim = AJManager.GetAnimationData(a.Symbol); if (anim != null) { JointAnimManager ja = new JointAnimManager(); var animfile = new HSDRawFile(anim); ja.FromFigaTree(animfile.Roots[0].Data as HSD_FigaTree); //ja.Optimize(JointManager.GetJOBJ(0), 0.01f); animfile.Roots[0].Data = ja.ToFigaTree(0.01f); using (MemoryStream s = new MemoryStream()) { animfile.Save(s); var newfile = s.ToArray(); oldSize += anim.Length; newSize += newfile.Length; AJManager.SetAnimation(a.Symbol, newfile); } } edited.Add(a.Symbol); } Console.WriteLine($"{oldSize.ToString("X")} => {newSize.ToString("X")}"); Console.WriteLine($"Saved {(oldSize - newSize).ToString("X")} bytes"); }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="target"></param> /// <param name="animation"></param> /// <param name="sourceMap"></param> /// <param name="targetMap"></param> /// <returns></returns> public static JointAnimManager Port(JointAnimManager animation, JointMap sourceMap, JointMap targetMap) { JointAnimManager newAnim = new JointAnimManager(); newAnim.FrameCount = animation.FrameCount; for (int i = 0; i < targetMap.Count; i++) { var bone = targetMap[i]; var index = sourceMap.IndexOf(bone); if (index != -1 && index < animation.Nodes.Count) { newAnim.Nodes.Add(animation.Nodes[index]); } else { newAnim.Nodes.Add(new AnimNode()); } } return(newAnim); }
/// <summary> /// /// </summary> /// <param name="filePath"></param> public static JointAnimManager ImportFromMayaAnim(string filePath) { var mayaFile = new MayaAnim(); mayaFile.Open(filePath); JointAnimManager animation = new JointAnimManager(); animation.FrameCount = mayaFile.header.endTime - mayaFile.header.startTime; // process and encode FOBJ keys foreach (var mNode in mayaFile.Nodes) { AnimNode node = new AnimNode(); //Debug.WriteLine(mNode.name); foreach (var mTrack in mNode.atts) { FOBJ_Player t = new FOBJ_Player(); t.Keys = new List <FOBJKey>(); t.JointTrackType = jointTrackToMayaTrack.FirstOrDefault(e => e.Value == mTrack.type).Key; //Debug.WriteLine("\t" + mTrack.type); var degrees = mayaFile.header.angularUnit == "deg"; var trackUnit = (mTrack.IsAngular() && degrees); for (int i = 0; i < mTrack.keys.Count; i++) { var mKey = mTrack.keys[i]; var mKeyNext = i + 1 < mTrack.keys.Count ? mTrack.keys[i + 1] : mTrack.keys[i]; var k = new FOBJKey(); k.Frame = mKey.input - mayaFile.header.startTime; k.Value = trackUnit ? MathHelper.DegreesToRadians(mKey.output) : mKey.output; switch (mKey.outtan) { case "auto": case "linear": k.InterpolationType = GXInterpolationType.HSD_A_OP_LIN; t.Keys.Add(k); break; case "step": if (mTrack.keys.Count == 1) { k.InterpolationType = GXInterpolationType.HSD_A_OP_KEY; } else { k.InterpolationType = GXInterpolationType.HSD_A_OP_CON; } t.Keys.Add(k); break; case "fixed": case "spline": k.InterpolationType = GXInterpolationType.HSD_A_OP_SPL; k.Tan = AngleToTan(mKey.t1, degrees); if ((mKeyNext.input - mKey.input) <= 1) // optimization { //k.InterpolationType = GXInterpolationType.HSD_A_OP_LIN; t.Keys.Add(k); } else if (mKey.t2 == 0) { k.InterpolationType = GXInterpolationType.HSD_A_OP_SPL0; t.Keys.Add(k); } else if (mKey.t1 != mKey.t2) { t.Keys.Add(k); var slp = new FOBJKey(); slp.Frame = mKeyNext.input - 1; slp.InterpolationType = GXInterpolationType.HSD_A_OP_SLP; slp.Tan = AngleToTan(mKey.t2, degrees); t.Keys.Add(slp); } else { t.Keys.Add(k); } break; default: Console.WriteLine(mKey.outtan + " not supported!"); break; } if (mTrack.keys.Count == 1) { k.InterpolationType = GXInterpolationType.HSD_A_OP_KEY; } //foreach (var key in t.Keys) // Debug.WriteLine($"\t\t{key.Frame} {key.Value}"); } node.Tracks.Add(t); } animation.Nodes.Add(node); } return(animation); }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <param name="nodes"></param> public static void ExportToMayaAnim(string filePath, JointAnimManager animation, Dictionary <int, string> boneLabelMap) { using (PropertyDialog d = new PropertyDialog("Maya Settings", MayaSettings)) { if (d.ShowDialog() != DialogResult.OK) { return; } } MayaAnim a = new MayaAnim(); if (!MayaSettings.UseRadians) { a.header.angularUnit = "deg"; } int nodeIndex = 0; int frameCount = 0; foreach (var n in animation.Nodes) { MayaAnim.MayaNode mnode = new MayaAnim.MayaNode(); mnode.name = boneLabelMap.ContainsKey(nodeIndex) ? boneLabelMap[nodeIndex] : "JOBJ_" + nodeIndex; a.Nodes.Add(mnode); foreach (var t in n.Tracks) { if (!jointTrackToMayaTrack.ContainsKey(t.JointTrackType)) { continue; } MayaAnim.MayaTrack mtrack = new MayaAnim.MayaTrack(); mnode.atts.Add(mtrack); mtrack.type = jointTrackToMayaTrack[t.JointTrackType]; if (mtrack.IsAngular()) { mtrack.output = MayaAnim.OutputType.angular; } FOBJAnimState prevState = null; for (int i = 0; i < t.Keys.Count; i++) { // get maximum frame to use as framecount frameCount = (int)Math.Max(frameCount, t.Keys[i].Frame); // get current state at this key frame var state = t.GetState(t.Keys[i].Frame); bool nextSlope = i + 1 < t.Keys.Count && t.Keys[i + 1].InterpolationType == GXInterpolationType.HSD_A_OP_SLP; if (t.Keys[i].InterpolationType == GXInterpolationType.HSD_A_OP_SLP) { continue; } // assuming last frame // if last frame shift frame information over if (t.Keys[i].Frame == state.t1) { state.t0 = state.t1; state.p0 = state.p1; state.d0 = state.d1; //state.op_intrp = state.op; } // generate key with time and value var animkey = new MayaAnim.AnimKey() { input = state.t0, output = state.p0, }; // nothing to do for linear //if (op_intrp == GXInterpolationType.HSD_A_OP_LIN) // set step type for constant and key if (state.op_intrp == GXInterpolationType.HSD_A_OP_CON || state.op_intrp == GXInterpolationType.HSD_A_OP_KEY) { animkey.intan = "auto"; animkey.outtan = "step"; } // set tangents for weighted slopes if (state.op_intrp == GXInterpolationType.HSD_A_OP_SLP || state.op_intrp == GXInterpolationType.HSD_A_OP_SPL0 || state.op_intrp == GXInterpolationType.HSD_A_OP_SPL) { animkey.t1 = state.d0; animkey.t2 = state.d0; if (nextSlope && prevState != null) { animkey.t1 = prevState.d1; } animkey.intan = "spline"; animkey.outtan = "spline"; } prevState = state; animkey.t1 = (float)MathHelper.RadiansToDegrees(Math.Atan(animkey.t1)); animkey.t2 = (float)MathHelper.RadiansToDegrees(Math.Atan(animkey.t2)); if (mtrack.IsAngular() && !MayaSettings.UseRadians) { animkey.output = MathHelper.RadiansToDegrees(animkey.output); animkey.t1 = MathHelper.RadiansToDegrees(animkey.t1); animkey.t2 = MathHelper.RadiansToDegrees(animkey.t2); } // add final key mtrack.keys.Add(animkey); } } nodeIndex++; } // set framecount a.header.endTime = animation.FrameCount; a.header.startTime = 0; // save to file a.Save(filePath); }
/// <summary> /// /// </summary> /// <param name="cam"></param> /// <param name="frame"></param> public void Render(Camera cam, float frame) { if (frame == -1 && entryAnimation.Count > 0) { entryAnimation.Clear(); } if (frame == 0) { entryAnimation.Clear(); // Load Animation foreach (var i in Icons) { if (i.AnimJoint == null) { continue; } var a = new JointAnimManager(); a.FromAnimJoint(i.AnimJoint); entryAnimation.Add(i, a); } } for (int i = 0; i < Icons.Length; i++) { var ico = Icons[i]; if (ico.Joint == null) { continue; } var transform = Matrix4.Identity; if (entryAnimation.ContainsKey(ico)) { transform = entryAnimation[ico].GetAnimatedMatrix(frame, 0, ico.Joint); } else { transform = Matrix4.CreateScale(ico.Joint.SX, ico.Joint.SY, ico.Joint.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(ico.Joint.RZ, ico.Joint.RY, ico.Joint.RX)) * Matrix4.CreateTranslation(ico.Joint.TX, ico.Joint.TY, ico.Joint.TZ); } if (IconJOBJManager.JointCount > 0) { IconJOBJManager.SetWorldTransform(0, transform); ico.IconTOBJ.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE; IconJOBJManager.GetJOBJ(0).Child.Dobj.Next.Mobj.Textures = ico.IconTOBJ; IconJOBJManager.Render(cam, false); } if (sssEditor.SelectedIndices.Contains(i)) { if (sssEditor.SelectedIndices.Count == 1 && StageNameJOBJManager.JointCount > 0) { ico.NameTOBJ.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE; StageNameJOBJManager.GetJOBJ(0).Child.Child.Dobj.Mobj.Textures = ico.NameTOBJ; } var rect = ico.ToRectangle(); DrawShape.DrawRectangle(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height, ico.Joint.TZ, 2, MEX_CSSIconEntry.SelectedIconColor); if (Dragging) { DrawShape.Line(new Vector3(-100, rect.Y, 0), new Vector3(100, rect.Y, 0), SnapColor, 1); DrawShape.Line(new Vector3(rect.X, -100, 0), new Vector3(rect.X, 100, 0), SnapColor, 1); DrawShape.Line(new Vector3(-100, rect.Y + rect.Height, 0), new Vector3(100, rect.Y + rect.Height, 0), SnapColor, 1); DrawShape.Line(new Vector3(rect.X + rect.Width, -100, 0), new Vector3(rect.X + rect.Width, 100, 0), SnapColor, 1); } } } StageNameJOBJManager.Render(cam); }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static JointAnimManager LoadCHR0(string filePath, JointMap jointMap) { JointAnimManager anim = new JointAnimManager(); for (int i = 0; i < jointMap.Count; i++) { anim.Nodes.Add(new AnimNode()); } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; if (r.BaseStream.Length < 4 || new string(r.ReadChars(4)) != "CHR0") { throw new InvalidDataException("CHR0 file is not valid"); } r.Skip(4); int versionNum = r.ReadInt32(); if (versionNum != 4) { throw new InvalidDataException($"CHR0 version {versionNum} not supported"); } r.Seek(0x10); var indexGroupOffset = r.ReadUInt32(); var animName = r.ReadString(r.ReadInt32(), -1); r.Skip(4); anim.FrameCount = r.ReadUInt16() - 1; int animDataCount = r.ReadUInt16(); r.Skip(8); r.Seek(indexGroupOffset); var sectionOffset = r.ReadUInt32() + indexGroupOffset; int sectionCount = r.ReadInt32(); for (uint i = 0; i < sectionCount; i++) { r.Seek(indexGroupOffset + 8 + 16 * i); r.Skip(4); // id and unknown r.Skip(2); // let r.Skip(2); // right var boneName = r.ReadString(r.ReadInt32() + (int)indexGroupOffset, -1); var dataOffset = r.ReadUInt32() + indexGroupOffset; if (dataOffset == indexGroupOffset) { sectionCount += 1; continue; } if (jointMap.IndexOf(boneName) == -1) { continue; } r.Seek(dataOffset); var nameOff = r.Position + r.ReadUInt32(); var flags = r.ReadInt32(); //Console.WriteLine(boneName + " " + flags.ToString("X")); //r.PrintPosition(); //01BFE019 int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; AnimNode node = new AnimNode(); FOBJ_Player trackX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX }; FOBJ_Player trackY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY }; FOBJ_Player trackZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ }; FOBJ_Player trackRX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX }; FOBJ_Player trackRY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY }; FOBJ_Player trackRZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ }; FOBJ_Player trackSX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX }; FOBJ_Player trackSY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY }; FOBJ_Player trackSZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ }; if (hasS == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackSX, trackSY, trackSZ, Siso == 1, SXfixed == 1, SYfixed == 1, SZfixed == 1, s_type, dataOffset); } if (hasR == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackRX, trackRY, trackRZ, Riso == 1, RXfixed == 1, RYfixed == 1, RZfixed == 1, r_type, dataOffset); } if (hasT == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackX, trackY, trackZ, Tiso == 1, Xfixed == 1, Yfixed == 1, Zfixed == 1, t_type, dataOffset); } if (trackX.Keys.Count > 0) { node.Tracks.Add(trackX); } if (trackY.Keys.Count > 0) { node.Tracks.Add(trackY); } if (trackZ.Keys.Count > 0) { node.Tracks.Add(trackZ); } if (trackRX.Keys.Count > 0) { node.Tracks.Add(trackRX); } if (trackRY.Keys.Count > 0) { node.Tracks.Add(trackRY); } if (trackRZ.Keys.Count > 0) { node.Tracks.Add(trackRZ); } if (trackSX.Keys.Count > 0) { node.Tracks.Add(trackSX); } if (trackSY.Keys.Count > 0) { node.Tracks.Add(trackSY); } if (trackSZ.Keys.Count > 0) { node.Tracks.Add(trackSZ); } foreach (var k in trackRX.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } foreach (var k in trackRY.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } foreach (var k in trackRZ.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } // make sure all tracks start at frame 0 foreach (var track in node.Tracks) { if (track.Keys.Count > 0 && track.Keys[0].Frame != 0) { track.Keys.Insert(0, new FOBJKey() { Frame = 0, Value = track.Keys[0].Value, InterpolationType = GXInterpolationType.HSD_A_OP_CON, }); } } //Console.WriteLine(boneName + " Tracks:" + node.Tracks.Count + " " + flags.ToString("X")); //Console.WriteLine($"{trackX.Keys.Count} {trackY.Keys.Count} {trackZ.Keys.Count}"); //Console.WriteLine($"{trackRX.Keys.Count} {trackRY.Keys.Count} {trackRZ.Keys.Count}"); //Console.WriteLine($"{trackSX.Keys.Count} {trackSY.Keys.Count} {trackSZ.Keys.Count}"); anim.Nodes[jointMap.IndexOf(boneName)] = node; } } return(anim); }
/// <summary> /// /// </summary> /// <param name="node"></param> /// <param name="frame"></param> /// <param name="value"></param> /// <param name="track"></param> /// <param name="manager"></param> private static void AddKey(int node, int frame, float value, JointTrackType tracktype, JointAnimManager manager) { var track = manager.Nodes[node].Tracks.Find(e => e.JointTrackType == tracktype); if (track == null) { track = new FOBJ_Player() { JointTrackType = tracktype }; manager.Nodes[node].Tracks.Add(track); } track.Keys.Add(new FOBJKey() { Frame = frame, Value = value, InterpolationType = frame == 0 ? GXInterpolationType.HSD_A_OP_KEY : GXInterpolationType.HSD_A_OP_CON }); }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="target"></param> /// <param name="animation"></param> /// <param name="sourceMap"></param> /// <param name="targetMap"></param> /// <returns></returns> public static JointAnimManager SmartPort(HSD_JOBJ source, HSD_JOBJ target, JointAnimManager animation, JointMap sourceMap = null, JointMap targetMap = null) { var sourceManager = new JOBJManager(); sourceManager.SetJOBJ(source); var sourceInverseWorldTransforms = new List <Matrix4>(); for (int i = 0; i < sourceManager.JointCount; i++) { sourceInverseWorldTransforms.Add(sourceManager.GetWorldTransform(i).Inverted()); } sourceManager.Animation = animation; var targetManager = new JOBJManager(); targetManager.SetJOBJ(target); JointAnimManager newAnim = new JointAnimManager(); newAnim.FrameCount = sourceManager.Animation.FrameCount; newAnim.Nodes.Clear(); for (int i = 0; i < targetManager.JointCount; i++) { newAnim.Nodes.Add(new AnimNode()); } for (int i = 0; i < sourceManager.JointCount; i++) { int targetIndex = i; int sourceIndex = i; Console.WriteLine(sourceMap[i]); // remap bone if joint maps are present if (sourceMap != null && targetMap != null && !string.IsNullOrEmpty(sourceMap[i])) { targetIndex = targetMap.IndexOf(sourceMap[i]); } if (targetIndex == -1) { continue; } var sourceJoint = sourceManager.GetJOBJ(sourceIndex); var targetJoint = targetManager.GetJOBJ(targetIndex); Console.WriteLine($"\t {sourceJoint.RX} {sourceJoint.RY} {sourceJoint.RZ}"); Console.WriteLine($"\t {targetJoint.RX} {targetJoint.RY} {targetJoint.RZ}"); /*if(sourceMap[i] == "RLegJ") * { * var track = animation.Nodes[sourceIndex].Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTX); * * if (track != null) * foreach (var k in track.Keys) * k.Value += (float)Math.PI / 2; * * track = animation.Nodes[sourceIndex].Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTZ); * * if (track != null) * foreach (var k in track.Keys) * k.Value += (float)Math.PI / 2; * }*/ newAnim.Nodes[targetIndex].Tracks = animation.Nodes[sourceIndex].Tracks;; } return(newAnim); }
/// <summary> /// /// </summary> private void LoadFigaTree(string treeSymbol, HSD_FigaTree tree) { // clear animation JointManager.SetFigaTree(null); ThrowDummyManager.SetFigaTree(null); // create new action var name = new Action() { Symbol = treeSymbol }.ToString(); // load figatree to manager and anim editor JointManager.SetFigaTree(tree); _animEditor.SetJoint(JointManager.GetJOBJ(0), JointManager.Animation); // set backup anim BackupAnim = new JointAnimManager(); BackupAnim.FromFigaTree(tree); // set frame viewport.MaxFrame = tree.FrameCount; // enable shield display if (FighterData != null && name.Equals("Guard")) { DisplayShieldSize = FighterData.Attributes.ShieldSize / 2; } // load throw dummy for thrown animations if (name.Contains("Throw") && !name.Contains("Taro")) { // find thrown anim Action throwAction = null; foreach (Action a in actionList.Items) { if (a.Symbol != null && a.Symbol.Contains("Taro") && a.Symbol.Contains(name) && !a.Symbol.Equals(treeSymbol)) { throwAction = a; break; } } // if throw animation is found if (throwAction != null && throwAction.Symbol != null) { var throwData = AJManager.GetAnimationData(throwAction.Symbol); if (throwData != null) { // load throw animation var tanim = new HSDRawFile(throwData); if (tanim.Roots[0].Data is HSD_FigaTree tree2) { ThrowDummyManager.SetFigaTree(tree2); if (ThrowDummyLookupTable.Count > 0) { ThrowDummyManager.Animation.EnableBoneLookup = true; ThrowDummyManager.Animation.BoneLookup = ThrowDummyLookupTable; } } } } } }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static JointAnimManager LoadCHR0(string filePath, Dictionary <int, string> BoneLabelMap) { JointAnimManager anim = new JointAnimManager(); Dictionary <string, int> nameToIndex = new Dictionary <string, int>(); foreach (var v in BoneLabelMap) { nameToIndex.Add(v.Value, v.Key); anim.Nodes.Add(new AnimNode()); } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; if (r.BaseStream.Length < 4 || new string(r.ReadChars(4)) != "CHR0") { throw new InvalidDataException("CHR0 file is not valid"); } r.Skip(4); int versionNum = r.ReadInt32(); if (versionNum != 4) { throw new InvalidDataException($"CHR0 version {versionNum} not supported"); } System.Console.WriteLine("Reading Track "); r.Seek(0x10); var indexGroupOffset = r.ReadUInt32(); var animName = r.ReadString(r.ReadInt32(), -1); r.Skip(4); anim.FrameCount = r.ReadUInt16(); int animDataCount = r.ReadUInt16(); r.Skip(8); r.Seek(indexGroupOffset); var sectionOffset = r.ReadUInt32() + indexGroupOffset; int sectionCount = r.ReadInt32(); for (uint i = 0; i < sectionCount; i++) { r.Seek(indexGroupOffset + 8 + 16 * i); r.Skip(4); // id and unknown r.Skip(2); // let r.Skip(2); // right var boneName = r.ReadString(r.ReadInt32() + (int)indexGroupOffset, -1); var dataOffset = r.ReadUInt32() + indexGroupOffset; if (dataOffset == indexGroupOffset) { sectionCount += 1; continue; } if (!nameToIndex.ContainsKey(boneName)) { continue; } r.Seek(dataOffset); var nameOff = r.Position + r.ReadUInt32(); var flags = r.ReadInt32(); int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; AnimNode node = new AnimNode(); FOBJ_Player trackX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX }; FOBJ_Player trackY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY }; FOBJ_Player trackZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ }; FOBJ_Player trackRX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX }; FOBJ_Player trackRY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY }; FOBJ_Player trackRZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ }; FOBJ_Player trackSX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX }; FOBJ_Player trackSY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY }; FOBJ_Player trackSZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ }; if (hasS == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackSX, trackSY, trackSZ, Siso == 1, SXfixed == 1, SYfixed == 1, SZfixed == 1, s_type, dataOffset); } if (hasR == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackRX, trackRY, trackRZ, Riso == 1, RXfixed == 1, RYfixed == 1, RZfixed == 1, r_type, dataOffset); } if (hasT == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackX, trackY, trackZ, Tiso == 1, Xfixed == 1, Yfixed == 1, Zfixed == 1, t_type, dataOffset); } if (trackX.Keys.Count > 1) { node.Tracks.Add(trackX); } if (trackY.Keys.Count > 1) { node.Tracks.Add(trackY); } if (trackZ.Keys.Count > 1) { node.Tracks.Add(trackZ); } if (trackRX.Keys.Count > 1) { node.Tracks.Add(trackRX); } if (trackRY.Keys.Count > 1) { node.Tracks.Add(trackRY); } if (trackRZ.Keys.Count > 1) { node.Tracks.Add(trackRZ); } if (trackSX.Keys.Count > 1) { node.Tracks.Add(trackSX); } if (trackSY.Keys.Count > 1) { node.Tracks.Add(trackSY); } if (trackSZ.Keys.Count > 1) { node.Tracks.Add(trackSZ); } foreach (var k in trackRX.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Value); } foreach (var k in trackRY.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Value); } foreach (var k in trackRZ.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Value); } Console.WriteLine(boneName + " Tracks:" + node.Tracks.Count); Console.WriteLine($"{trackX.Keys.Count} {trackY.Keys.Count} {trackZ.Keys.Count}"); Console.WriteLine($"{trackRX.Keys.Count} {trackRY.Keys.Count} {trackRZ.Keys.Count}"); Console.WriteLine($"{trackSX.Keys.Count} {trackSY.Keys.Count} {trackSZ.Keys.Count}"); anim.Nodes[nameToIndex[boneName]] = node; } } return(anim); }
/// <summary> /// Opens editor for currently selected node if editor exists /// </summary> public void OpenEditor() { if (SelectedDataNode == null) { return; } var edit = PluginManager.GetEditorFromType(SelectedDataNode.Accessor.GetType()); // Special animation override if (SelectedDataNode.Accessor is HSD_AnimJoint || SelectedDataNode.Accessor is HSD_FigaTree || SelectedDataNode.Accessor is HSD_MatAnimJoint || SelectedDataNode.Accessor is HSD_ShapeAnimJoint || SelectedDataNode.Accessor is HSD_FogDesc || SelectedDataNode.Accessor is HSD_Camera || SelectedDataNode.Accessor is SBM_ModelPart) { //foreach (var v in dockPanel.Contents) { if (LastActiveContent is JobjEditorDock jedit && jedit.Visible) { if (SelectedDataNode.Accessor is HSD_MatAnimJoint matjoint) { jedit.LoadAnimation(matjoint); } if (SelectedDataNode.Accessor is HSD_ShapeAnimJoint shapeJoint) { jedit.LoadAnimation(shapeJoint); } if (SelectedDataNode.Accessor is HSD_AnimJoint joint) { jedit.LoadAnimation(new JointAnimManager(joint)); } if (SelectedDataNode.Accessor is HSD_FigaTree tree) { jedit.LoadAnimation(new JointAnimManager(tree)); } if (SelectedDataNode.Accessor is HSD_FogDesc fog) { jedit.Editor.SetFog(fog); } if (SelectedDataNode.Accessor is HSD_Camera camera) { jedit.Editor.SetCamera(camera); } if (SelectedDataNode.Accessor is SBM_ModelPart modelPart && modelPart.Anims.Length > 0) { if (prev_selected_part == modelPart) { part_select_index++; } else { part_select_index = 0; } prev_selected_part = modelPart; if (part_select_index > modelPart.Anims.Length) { part_select_index = 0; } JointAnimManager manager = new JointAnimManager(); for (int i = 0; i < modelPart.StartingBone; i++) { manager.Nodes.Add(new AnimNode()); } manager.Nodes.AddRange(new JointAnimManager(modelPart.Anims[part_select_index]).Nodes); jedit.LoadAnimation(manager); } } } } if (IsOpened(SelectedDataNode)) { var editor = GetEditors(SelectedDataNode); editor[0].BringToFront(); } else if (!IsChildOpened(SelectedDataNode.Accessor._s) && edit != null && edit is DockContent dc) { //Editors.Add(edit); SelectedDataNode.Collapse(); edit.Node = SelectedDataNode; dc.Show(dockPanel); dc.Text = SelectedDataNode.Text; dc.TabText = SelectedDataNode.Text; //if (dc is EditorBase b) // dc.DockState = b.DefaultDockState; } }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="target"></param> /// <param name="animation"></param> /// <returns></returns> public static JointAnimManager Retarget(HSD_JOBJ source, HSD_JOBJ target, JointAnimManager animation, JointMap sourceMap = null, JointMap targetMap = null) { var sourceManager = new JOBJManager(); sourceManager.SetJOBJ(source); var sourceInverseWorldTransforms = new List <Matrix4>(); for (int i = 0; i < sourceManager.JointCount; i++) { sourceInverseWorldTransforms.Add(sourceManager.GetWorldTransform(i).Inverted()); } sourceManager.Animation = animation; var targetManager = new JOBJManager(); targetManager.SetJOBJ(target); JointAnimManager newAnim = new JointAnimManager(); newAnim.FrameCount = sourceManager.Animation.FrameCount; var targetWorldTransforms = new List <Matrix4>(); for (int i = 0; i < targetManager.JointCount; i++) { targetWorldTransforms.Add(targetManager.GetWorldTransform(i)); newAnim.Nodes.Add(new AnimNode()); } targetManager.Animation = newAnim; for (int f = 0; f <= sourceManager.Animation.FrameCount; f++) { sourceManager.Frame = f - 1; sourceManager.UpdateNoRender(); targetManager.Frame = f; targetManager.UpdateNoRender(); // bake animation on target skeleton for (int i = 0; i < sourceManager.JointCount; i++) { int targetIndex = i; int sourceIndex = i; // remap bone if joint maps are present if (sourceMap != null && targetMap != null && !string.IsNullOrEmpty(sourceMap[i])) { targetIndex = targetMap.IndexOf(sourceMap[i]); } if (targetIndex == -1) { continue; } int targetParentIndex = targetManager.ParentIndex(targetManager.GetJOBJ(targetIndex)); var inverseSourceWorldRotation = sourceInverseWorldTransforms[sourceIndex]; var sourceAnimatedWorldRotation = sourceManager.GetWorldTransform(sourceIndex); var targetWorldRotation = targetWorldTransforms[targetIndex]; var rel = targetWorldRotation * inverseSourceWorldRotation * sourceAnimatedWorldRotation; if (targetParentIndex != -1) { rel *= targetManager.GetWorldTransform(targetParentIndex).Inverted(); } var rot = Math3D.ToEulerAngles(rel.ExtractRotation().Inverted()); var targetJOBJ = targetManager.GetJOBJ(targetIndex); var sourceJOBJ = sourceManager.GetJOBJ(sourceIndex); sourceManager.Animation.GetAnimatedState(f - 1, sourceIndex, sourceJOBJ, out float TX, out float TY, out float TZ, out float RX, out float RY, out float RZ, out float SX, out float SY, out float SZ); var relTranslate = new Vector3(sourceJOBJ.TX - TX, sourceJOBJ.TY - TY, sourceJOBJ.TZ - TZ); //relTranslate = Vector3.TransformNormal(relTranslate, Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(sourceJOBJ.RZ, sourceJOBJ.RY, sourceJOBJ.RX).Inverted())); //relTranslate = Vector3.TransformNormal(relTranslate, Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(targetJOBJ.RZ, targetJOBJ.RY, targetJOBJ.RX))); var relScale = new Vector3(sourceJOBJ.SX - SX, sourceJOBJ.SY - SY, sourceJOBJ.SZ - SZ); //relScale = Vector3.TransformNormal(relScale, inverseSourceWorldRotation); //relScale = Vector3.TransformNormal(relScale, targetWorldRotation); AddKey(targetIndex, f, targetJOBJ.TX - relTranslate.X, JointTrackType.HSD_A_J_TRAX, newAnim); AddKey(targetIndex, f, targetJOBJ.TY - relTranslate.Y, JointTrackType.HSD_A_J_TRAY, newAnim); AddKey(targetIndex, f, targetJOBJ.TZ - relTranslate.Z, JointTrackType.HSD_A_J_TRAZ, newAnim); AddKey(targetIndex, f, rot.X, JointTrackType.HSD_A_J_ROTX, newAnim); AddKey(targetIndex, f, rot.Y, JointTrackType.HSD_A_J_ROTY, newAnim); AddKey(targetIndex, f, rot.Z, JointTrackType.HSD_A_J_ROTZ, newAnim); AddKey(targetIndex, f, targetJOBJ.SX - relScale.X, JointTrackType.HSD_A_J_SCAX, newAnim); AddKey(targetIndex, f, targetJOBJ.SY - relScale.Y, JointTrackType.HSD_A_J_SCAY, newAnim); AddKey(targetIndex, f, targetJOBJ.SZ - relScale.Z, JointTrackType.HSD_A_J_SCAZ, newAnim); targetManager.UpdateNoRender(); } } EulerFilter(newAnim); var targetAnim = newAnim.ToAnimJoint(target, AOBJ_Flags.ANIM_LOOP); AnimationCompressor.AdaptiveCompressAnimation(targetAnim, targetMap); RemoveUnusedTracks(target, targetAnim); newAnim.FromAnimJoint(targetAnim); // apply additional single frame filter check for (int i = 0; i < sourceManager.JointCount; i++) { int targetIndex = i; int sourceIndex = i; // remap bone if joint maps are present if (sourceMap != null && targetMap != null && !string.IsNullOrEmpty(sourceMap[i])) { targetIndex = targetMap.IndexOf(sourceMap[i]); } if (targetIndex == -1) { continue; } var sourceNode = animation.Nodes[sourceIndex]; var targetNode = newAnim.Nodes[targetIndex]; FOBJ_Player sourceXRot = null; FOBJ_Player sourceYRot = null; FOBJ_Player sourceZRot = null; foreach (var t in sourceNode.Tracks) { if (t.JointTrackType == JointTrackType.HSD_A_J_ROTX) { sourceXRot = t; } if (t.JointTrackType == JointTrackType.HSD_A_J_ROTY) { sourceYRot = t; } if (t.JointTrackType == JointTrackType.HSD_A_J_ROTZ) { sourceZRot = t; } } if (sourceXRot != null && sourceYRot != null && sourceZRot != null && sourceXRot.Keys.Count == 1 && sourceYRot.Keys.Count == 1 && sourceZRot.Keys.Count == 1) { foreach (var t in targetNode.Tracks) { if (t.JointTrackType == JointTrackType.HSD_A_J_ROTX || t.JointTrackType == JointTrackType.HSD_A_J_ROTY || t.JointTrackType == JointTrackType.HSD_A_J_ROTZ) { t.Keys.RemoveAll(e => e.Frame > 0); t.Keys[0].InterpolationType = GXInterpolationType.HSD_A_OP_KEY; } } } } return(newAnim); }
public static JointAnimManager ToJointAnim(string filePath, JointMap jm) { var bke = BKE.Open(filePath); JointAnimManager anim = new JointAnimManager(); anim.FrameCount = bke.CountFrames(); for (int i = 0; i < bke.Nodes.Count; i++) { var node = new AnimNode(); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ, Keys = new List <FOBJKey>() }); anim.Nodes.Add(node); } foreach (var n in bke.Nodes) { if (jm.IndexOf(n.Name) == -1) { break; } var node = anim.Nodes[jm.IndexOf(n.Name)]; Console.WriteLine(n.Name + " " + n.Parent?.Name); for (int f = 0; f < anim.FrameCount; f++) { var matrix = n.GetLocal(f); var tra = matrix.ExtractTranslation(); var sca = matrix.ExtractScale(); var rot = Math3D.ToEulerAngles(matrix.ExtractRotation().Inverted()); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_TRAX).Keys.Add(new FOBJKey() { Frame = f, Value = tra.X, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_TRAY).Keys.Add(new FOBJKey() { Frame = f, Value = tra.Y, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_TRAZ).Keys.Add(new FOBJKey() { Frame = f, Value = tra.Z, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTX).Keys.Add(new FOBJKey() { Frame = f, Value = rot.X, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTY).Keys.Add(new FOBJKey() { Frame = f, Value = rot.Y, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTZ).Keys.Add(new FOBJKey() { Frame = f, Value = rot.Z, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_SCAX).Keys.Add(new FOBJKey() { Frame = f, Value = sca.X, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_SCAY).Keys.Add(new FOBJKey() { Frame = f, Value = sca.Y, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_SCAZ).Keys.Add(new FOBJKey() { Frame = f, Value = sca.Z, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); } } return(anim); }