Switch-Toolbox/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FSKA.cs
KillzXGaming 716d1c4520 More clean up and additions
- Starting to make all texture classes use STGenericTexture. This will make all functions usable between each one and converting through other classes much easier.
- Many bug fixes to the texture importer like duped texture importing, dds opening the window, index out of range issues, etc.
- Start on titlebar information.
- Start on ASTC texture format support.
- Support TGA images.
- Support FTEX importing and saving properly.
- Export models properly along with textures (with generic classes). Todo, support rigs and bones.
2018-12-10 18:48:51 -05:00

478 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using Syroot.NintenTools.NSW.Bfres;
using System.Windows.Forms;
using Switch_Toolbox.Library;
using ResU = Syroot.NintenTools.Bfres;
using FirstPlugin;
using OpenTK;
namespace Bfres.Structs
{
public class FskaFolder : AnimationGroupNode
{
public FskaFolder()
{
Text = "Skeleton Animations";
Name = "FSKA";
ContextMenu = new ContextMenu();
MenuItem import = new MenuItem("Import");
ContextMenu.MenuItems.Add(import);
import.Click += Import;
MenuItem exportAll = new MenuItem("Export All");
ContextMenu.MenuItems.Add(exportAll);
exportAll.Click += ExportAll;
MenuItem clear = new MenuItem("Clear");
ContextMenu.MenuItems.Add(clear);
clear.Click += Clear;
}
public void Import(object sender, EventArgs args)
{
}
public void ExportAll(object sender, EventArgs args)
{
FolderSelectDialog sfd = new FolderSelectDialog();
if (sfd.ShowDialog() == DialogResult.OK)
{
string folderPath = sfd.SelectedPath;
foreach (BfresSkeletonAnim fska in Nodes)
{
string FileName = folderPath + '\\' + fska.Text + ".bfska";
((BfresSkeletonAnim)fska).SkeletalAnim.Export(FileName, fska.GetResFile());
}
}
}
private void Clear(object sender, EventArgs args)
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to remove all skeletal animations? This cannot be undone!", "", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
Nodes.Clear();
}
}
}
public class BfresSkeletonAnim : Animation
{
public enum TrackType
{
XSCA = 0x4,
YSCA = 0x8,
ZSCA = 0xC,
XPOS = 0x10,
YPOS = 0x14,
ZPOS = 0x18,
XROT = 0x20,
YROT = 0x24,
ZROT = 0x28,
}
public SkeletalAnim SkeletalAnim;
public ResU.SkeletalAnim SkeletalAnimU;
public BfresSkeletonAnim()
{
ImageKey = "skeletonAnimation";
SelectedImageKey = "skeletonAnimation";
ContextMenu = new ContextMenu();
MenuItem export = new MenuItem("Export");
ContextMenu.MenuItems.Add(export);
export.Click += Export;
MenuItem replace = new MenuItem("Replace");
ContextMenu.MenuItems.Add(replace);
replace.Click += Replace;
}
public BfresSkeletonAnim(string name)
{
Text = name;
ImageKey = "skeletonAnimation";
SelectedImageKey = "skeletonAnimation";
ContextMenu = new ContextMenu();
MenuItem export = new MenuItem("Export");
ContextMenu.MenuItems.Add(export);
export.Click += Export;
MenuItem replace = new MenuItem("Replace");
ContextMenu.MenuItems.Add(replace);
replace.Click += Replace;
}
public ResFile GetResFile()
{
//ResourceFile -> FMDL -> Material Folder -> this
return ((BFRES)Parent.Parent).resFile;
}
public ResU.ResFile GetResFileU()
{
//ResourceFile -> FMDL -> Material Folder -> this
return ((BFRES)Parent.Parent).resFileU;
}
private void Export(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Supported Formats|*.bfska;";
sfd.FileName = Text;
sfd.DefaultExt = ".bfska";
if (sfd.ShowDialog() == DialogResult.OK)
{
if (GetResFileU() != null)
{
throw new Exception("Wii U unsupported!");
}
else
{
SkeletalAnim.Export(sfd.FileName, GetResFile());
}
}
}
private void Replace(object sender, EventArgs args)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Supported Formats|*.bfska;";
if (ofd.ShowDialog() == DialogResult.OK)
{
if (GetResFileU() != null)
{
throw new Exception("Wii U unsupported!");
}
else
{
SkeletalAnim.Import(ofd.FileName);
}
}
SkeletalAnim.Name = Text;
}
public static List<Animation> SkeletonAnimations = new List<Animation>();
public void Read(ResU.SkeletalAnim ska, ResU.ResFile b)
{
FrameCount = ska.FrameCount;
SkeletalAnimU = ska;
foreach (ResU.BoneAnim bn in ska.BoneAnims)
{
FSKANode bonean = new FSKANode(bn);
Animation.KeyNode bone = new Animation.KeyNode("");
Bones.Add(bone);
if (ska.FlagsRotate == ResU.SkeletalAnimFlagsRotate.EulerXYZ)
bone.RotType = Animation.RotationType.EULER;
else
bone.RotType = Animation.RotationType.QUATERNION;
bone.Text = bonean.Text;
for (int Frame = 0; Frame < ska.FrameCount; Frame++)
{
if (Frame == 0)
{
if (bn.FlagsBase.HasFlag(ResU.BoneAnimFlagsBase.Scale))
{
bone.XSCA.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.sca.X });
bone.YSCA.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.sca.Y });
bone.ZSCA.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.sca.Z });
}
if (bn.FlagsBase.HasFlag(ResU.BoneAnimFlagsBase.Rotate))
{
bone.XROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.X });
bone.YROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.Y });
bone.ZROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.Z });
bone.WROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.W });
}
if (bn.FlagsBase.HasFlag(ResU.BoneAnimFlagsBase.Translate))
{
bone.XPOS.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.pos.X });
bone.YPOS.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.pos.Y });
bone.ZPOS.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.pos.Z });
}
}
foreach (FSKATrack track in bonean.tracks)
{
KeyFrame frame = new KeyFrame();
frame.InterType = Animation.InterpolationType.HERMITE;
frame.Frame = Frame;
FSKAKey left = track.GetLeft(Frame);
FSKAKey right = track.GetRight(Frame);
float value;
value = Animation.Hermite(Frame, left.frame, right.frame, 0, 0, left.unk1, right.unk1);
// interpolate the value and apply
switch (track.flag)
{
case (int)TrackType.XPOS: frame.Value = value; bone.XPOS.Keys.Add(frame); break;
case (int)TrackType.YPOS: frame.Value = value; bone.YPOS.Keys.Add(frame); break;
case (int)TrackType.ZPOS: frame.Value = value; bone.ZPOS.Keys.Add(frame); break;
case (int)TrackType.XROT: frame.Value = value; bone.XROT.Keys.Add(frame); break;
case (int)TrackType.YROT: frame.Value = value; bone.YROT.Keys.Add(frame); break;
case (int)TrackType.ZROT: frame.Value = value; bone.ZROT.Keys.Add(frame); break;
case (int)TrackType.XSCA: frame.Value = value; bone.XSCA.Keys.Add(frame); break;
case (int)TrackType.YSCA: frame.Value = value; bone.YSCA.Keys.Add(frame); break;
case (int)TrackType.ZSCA: frame.Value = value; bone.ZSCA.Keys.Add(frame); break;
}
}
}
}
}
public void Read(SkeletalAnim ska, ResFile b)
{
FrameCount = ska.FrameCount;
SkeletalAnim = ska;
foreach (BoneAnim bn in ska.BoneAnims)
{
FSKANode bonean = new FSKANode(bn);
Animation.KeyNode bone = new Animation.KeyNode("");
Bones.Add(bone);
if (ska.FlagsRotate == SkeletalAnimFlagsRotate.EulerXYZ)
bone.RotType = Animation.RotationType.EULER;
else
bone.RotType = Animation.RotationType.QUATERNION;
bone.Text = bonean.Text;
for (int Frame = 0; Frame < ska.FrameCount; Frame++)
{
if (Frame == 0)
{
if (bn.FlagsBase.HasFlag(BoneAnimFlagsBase.Scale))
{
bone.XSCA.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.sca.X });
bone.YSCA.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.sca.Y });
bone.ZSCA.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.sca.Z });
}
if (bn.FlagsBase.HasFlag(BoneAnimFlagsBase.Rotate))
{
bone.XROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.X });
bone.YROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.Y });
bone.ZROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.Z });
bone.WROT.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.rot.W });
}
if (bn.FlagsBase.HasFlag(BoneAnimFlagsBase.Translate))
{
bone.XPOS.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.pos.X });
bone.YPOS.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.pos.Y });
bone.ZPOS.Keys.Add(new KeyFrame() { Frame = 0, Value = bonean.pos.Z });
}
}
foreach (FSKATrack track in bonean.tracks)
{
KeyFrame frame = new KeyFrame();
frame.InterType = Animation.InterpolationType.HERMITE;
frame.Frame = Frame;
FSKAKey left = track.GetLeft(Frame);
FSKAKey right = track.GetRight(Frame);
float value;
value = Animation.Hermite(Frame, left.frame, right.frame, 0, 0, left.unk1, right.unk1);
// interpolate the value and apply
switch (track.flag)
{
case (int)TrackType.XPOS: frame.Value = value; bone.XPOS.Keys.Add(frame); break;
case (int)TrackType.YPOS: frame.Value = value; bone.YPOS.Keys.Add(frame); break;
case (int)TrackType.ZPOS: frame.Value = value; bone.ZPOS.Keys.Add(frame); break;
case (int)TrackType.XROT: frame.Value = value; bone.XROT.Keys.Add(frame); break;
case (int)TrackType.YROT: frame.Value = value; bone.YROT.Keys.Add(frame); break;
case (int)TrackType.ZROT: frame.Value = value; bone.ZROT.Keys.Add(frame); break;
case (int)TrackType.XSCA: frame.Value = value; bone.XSCA.Keys.Add(frame); break;
case (int)TrackType.YSCA: frame.Value = value; bone.YSCA.Keys.Add(frame); break;
case (int)TrackType.ZSCA: frame.Value = value; bone.ZSCA.Keys.Add(frame); break;
}
}
}
}
}
public class FSKANode
{
public int flags;
public int flags2;
public int stride;
public int BeginRotate;
public int BeginTranslate;
public long offBase;
public int trackCount;
public int trackFlag;
public long offTrack;
public string Text;
public Vector3 sca, pos;
public Vector4 rot;
public List<FSKATrack> tracks = new List<FSKATrack>();
public FSKANode(ResU.BoneAnim b)
{
return;
Text = b.Name;
sca = new Vector3(b.BaseData.Scale.X, b.BaseData.Scale.Y, b.BaseData.Scale.Z);
rot = new Vector4(b.BaseData.Rotate.X, b.BaseData.Rotate.Y, b.BaseData.Rotate.Z, b.BaseData.Rotate.W);
pos = new Vector3(b.BaseData.Translate.X, b.BaseData.Translate.Y, b.BaseData.Translate.Z);
foreach (ResU.AnimCurve tr in b.Curves)
{
FSKATrack t = new FSKATrack();
t.flag = (int)tr.AnimDataOffset;
tracks.Add(t);
float tanscale = tr.Delta;
if (tanscale == 0)
tanscale = 1;
for (int i = 0; i < (ushort)tr.Frames.Length; i++)
{
if (tr.CurveType == ResU.AnimCurveType.Cubic)
{
int framedata = (int)tr.Frames[i];
float keydata = tr.Offset + ((tr.Keys[i, 0] * tr.Scale));
float keydata2 = tr.Offset + ((tr.Keys[i, 1] * tr.Scale));
float keydata3 = tr.Offset + ((tr.Keys[i, 2] * tr.Scale));
float keydata4 = tr.Offset + ((tr.Keys[i, 3] * tr.Scale));
}
if (tr.KeyType == ResU.AnimCurveKeyType.Int16)
{
}
else if (tr.KeyType == ResU.AnimCurveKeyType.Single)
{
}
else if (tr.KeyType == ResU.AnimCurveKeyType.SByte)
{
}
t.keys.Add(new FSKAKey()
{
frame = (int)tr.Frames[i],
unk1 = tr.Offset + ((tr.Keys[i, 0] * tr.Scale)),
unk2 = tr.Offset + ((tr.Keys[i, 1] * tr.Scale)),
unk3 = tr.Offset + ((tr.Keys[i, 2] * tr.Scale)),
unk4 = tr.Offset + ((tr.Keys[i, 3] * tr.Scale)),
});
}
}
}
public FSKANode(BoneAnim b)
{
Text = b.Name;
sca = new Vector3(b.BaseData.Scale.X, b.BaseData.Scale.Y, b.BaseData.Scale.Z);
rot = new Vector4(b.BaseData.Rotate.X, b.BaseData.Rotate.Y, b.BaseData.Rotate.Z, b.BaseData.Rotate.W);
pos = new Vector3(b.BaseData.Translate.X, b.BaseData.Translate.Y, b.BaseData.Translate.Z);
foreach (AnimCurve tr in b.Curves)
{
FSKATrack t = new FSKATrack();
t.flag = (int)tr.AnimDataOffset;
tracks.Add(t);
float tanscale = tr.Delta;
if (tanscale == 0)
tanscale = 1;
for (int i = 0; i < (ushort)tr.Frames.Length; i++)
{
if (tr.CurveType == AnimCurveType.Cubic)
{
int framedata = (int)tr.Frames[i];
float keydata = tr.Offset + ((tr.Keys[i, 0] * tr.Scale));
float keydata2 = tr.Offset + ((tr.Keys[i, 1] * tr.Scale));
float keydata3 = tr.Offset + ((tr.Keys[i, 2] * tr.Scale));
float keydata4 = tr.Offset + ((tr.Keys[i, 3] * tr.Scale));
}
if (tr.KeyType == AnimCurveKeyType.Int16)
{
}
else if (tr.KeyType == AnimCurveKeyType.Single)
{
}
else if (tr.KeyType == AnimCurveKeyType.SByte)
{
}
t.keys.Add(new FSKAKey()
{
frame = (int)tr.Frames[i],
unk1 = tr.Offset + ((tr.Keys[i, 0] * tr.Scale)),
unk2 = tr.Offset + ((tr.Keys[i, 1] * tr.Scale)),
unk3 = tr.Offset + ((tr.Keys[i, 2] * tr.Scale)),
unk4 = tr.Offset + ((tr.Keys[i, 3] * tr.Scale)),
});
}
}
}
}
public class FSKATrack
{
public short type;
public short keyCount;
public int flag;
public int unk2;
public int padding1;
public int padding2;
public int padding3;
public float frameCount;
public float scale, init, unkf3;
public long offtolastKeys, offtolastData;
public List<FSKAKey> keys = new List<FSKAKey>();
public int offset;
public FSKAKey GetLeft(int frame)
{
FSKAKey prev = keys[0];
for (int i = 0; i < keys.Count - 1; i++)
{
FSKAKey key = keys[i];
if (key.frame > frame && prev.frame <= frame)
break;
prev = key;
}
return prev;
}
public FSKAKey GetRight(int frame)
{
FSKAKey cur = keys[0];
FSKAKey prev = keys[0];
for (int i = 1; i < keys.Count; i++)
{
FSKAKey key = keys[i];
cur = key;
if (key.frame > frame && prev.frame <= frame)
break;
prev = key;
}
return cur;
}
}
public class FSKAKey
{
public int frame;
public float unk1, unk2, unk3, unk4;
public int offset;
}
}
}