553 lines
21 KiB
C#
553 lines
21 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using Syroot.NintenTools.NSW.Bfres;
|
|||
|
using ResU = Syroot.NintenTools.Bfres;
|
|||
|
using System.Windows;
|
|||
|
using Syroot.Maths;
|
|||
|
using BrawlLib.SSBB.ResourceNodes;
|
|||
|
|
|||
|
namespace BrawlboxHelper
|
|||
|
{
|
|||
|
public class FSHUConverter
|
|||
|
{
|
|||
|
public static ResU.ShaderParamAnim Clr02Fshu(string FileName)
|
|||
|
{
|
|||
|
CLR0Node clr0 = NodeFactory.FromFile(null, FileName) as CLR0Node;
|
|||
|
|
|||
|
ResU.ShaderParamAnim fshu = new ResU.ShaderParamAnim();
|
|||
|
fshu.FrameCount = clr0.FrameCount;
|
|||
|
fshu.Name = clr0.Name;
|
|||
|
fshu.Path = clr0.OriginalPath;
|
|||
|
fshu.UserData = new ResU.ResDict<Syroot.NintenTools.Bfres.UserData>();
|
|||
|
|
|||
|
//Set flags
|
|||
|
if (clr0.Loop)
|
|||
|
fshu.Flags |= ResU.ShaderParamAnimFlags.Looping;
|
|||
|
|
|||
|
//Set mat anims and then calculate data after
|
|||
|
foreach (var entry in clr0.Children)
|
|||
|
fshu.ShaderParamMatAnims.Add(Clr0Entry2ShaderMatAnim(clr0, (CLR0MaterialNode)entry));
|
|||
|
|
|||
|
fshu.BakedSize = CalculateBakeSize(fshu);
|
|||
|
fshu.BindIndices = SetIndices(fshu);
|
|||
|
|
|||
|
return fshu;
|
|||
|
}
|
|||
|
|
|||
|
public static ResU.ShaderParamMatAnim Clr0Entry2ShaderMatAnim(CLR0Node clr0, CLR0MaterialNode clrMaterial)
|
|||
|
{
|
|||
|
ResU.ShaderParamMatAnim matAnim = new ResU.ShaderParamMatAnim();
|
|||
|
matAnim.Name = clrMaterial.Name;
|
|||
|
foreach (var entry in clrMaterial.Children)
|
|||
|
{
|
|||
|
ushort curveIndex = 0;
|
|||
|
ushort constantIndex = 0;
|
|||
|
|
|||
|
CLR0MaterialEntryNode ParamEntry = (CLR0MaterialEntryNode)entry;
|
|||
|
|
|||
|
//Add constants for RGBA if constant
|
|||
|
if (ParamEntry.Constant)
|
|||
|
{
|
|||
|
//Red
|
|||
|
matAnim.Constants.Add(new ResU.AnimConstant()
|
|||
|
{
|
|||
|
AnimDataOffset = 0,
|
|||
|
Value = (float)ParamEntry.Colors[0].R / 255f,
|
|||
|
});
|
|||
|
|
|||
|
//Green
|
|||
|
matAnim.Constants.Add(new ResU.AnimConstant()
|
|||
|
{
|
|||
|
AnimDataOffset = 4,
|
|||
|
Value = (float)ParamEntry.Colors[0].G / 255f,
|
|||
|
});
|
|||
|
|
|||
|
//Blue
|
|||
|
matAnim.Constants.Add(new ResU.AnimConstant()
|
|||
|
{
|
|||
|
AnimDataOffset = 8,
|
|||
|
Value = (float)ParamEntry.Colors[0].B / 255f,
|
|||
|
});
|
|||
|
|
|||
|
//Alpha
|
|||
|
matAnim.Constants.Add(new ResU.AnimConstant()
|
|||
|
{
|
|||
|
AnimDataOffset = 12,
|
|||
|
Value = (float)ParamEntry.Colors[0].A / 255f,
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
var RedCurve = GenerateCurve(0, clr0, ParamEntry);
|
|||
|
var GreenCurve = GenerateCurve(4, clr0, ParamEntry);
|
|||
|
var BlueCurve = GenerateCurve(8, clr0, ParamEntry);
|
|||
|
var AlphaCurve = GenerateCurve(12, clr0, ParamEntry);
|
|||
|
|
|||
|
if (RedCurve != null)
|
|||
|
matAnim.Curves.Add(RedCurve);
|
|||
|
if (GreenCurve != null)
|
|||
|
matAnim.Curves.Add(GreenCurve);
|
|||
|
if (BlueCurve != null)
|
|||
|
matAnim.Curves.Add(BlueCurve);
|
|||
|
if (AlphaCurve != null)
|
|||
|
matAnim.Curves.Add(AlphaCurve);
|
|||
|
|
|||
|
matAnim.ParamAnimInfos.Add(new ResU.ParamAnimInfo()
|
|||
|
{
|
|||
|
Name = entry.Name,
|
|||
|
BeginCurve = matAnim.Curves.Count > 0 ? curveIndex : ushort.MaxValue,
|
|||
|
FloatCurveCount = (ushort)matAnim.Curves.Count,
|
|||
|
SubBindIndex = ushort.MaxValue,
|
|||
|
ConstantCount = (ushort)matAnim.Constants.Count,
|
|||
|
BeginConstant = matAnim.Constants.Count > 0 ? constantIndex : ushort.MaxValue,
|
|||
|
});
|
|||
|
|
|||
|
constantIndex += (ushort)matAnim.Constants.Count;
|
|||
|
curveIndex += (ushort)matAnim.Curves.Count;
|
|||
|
}
|
|||
|
|
|||
|
return matAnim;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private static ResU.AnimCurve GenerateCurve(uint AnimOffset, CLR0Node anim, CLR0MaterialEntryNode entry)
|
|||
|
{
|
|||
|
ResU.AnimCurve curve = new ResU.AnimCurve();
|
|||
|
curve.AnimDataOffset = AnimOffset;
|
|||
|
curve.StartFrame = 0;
|
|||
|
curve.Offset = 0;
|
|||
|
curve.Scale = 1;
|
|||
|
curve.FrameType = ResU.AnimCurveFrameType.Single;
|
|||
|
curve.KeyType = ResU.AnimCurveKeyType.Single;
|
|||
|
curve.CurveType = ResU.AnimCurveType.Linear;
|
|||
|
|
|||
|
List<float> Frames = new List<float>();
|
|||
|
List<float> Keys = new List<float>();
|
|||
|
|
|||
|
for (int c = 0; c < entry.Colors.Count; c++)
|
|||
|
{
|
|||
|
Frames.Add(c);
|
|||
|
//Max of 4 values. Cubic using 4, linear using 2, and step using 1
|
|||
|
float[] KeyValues = new float[4];
|
|||
|
|
|||
|
switch (AnimOffset)
|
|||
|
{
|
|||
|
case 0: //Red
|
|||
|
Keys.Add((float)entry.Colors[c].R / 255f);
|
|||
|
break;
|
|||
|
case 4: //Green
|
|||
|
Keys.Add((float)entry.Colors[c].G / 255f);
|
|||
|
break;
|
|||
|
case 8: //Blue
|
|||
|
Keys.Add((float)entry.Colors[c].B / 255f);
|
|||
|
break;
|
|||
|
case 12: //Alpha
|
|||
|
Keys.Add((float)entry.Colors[c].A / 255f);
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new Exception("Invalid animation offset set!");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//Max value in frames is our end frame
|
|||
|
curve.EndFrame = Frames.Max();
|
|||
|
curve.Frames = Frames.ToArray();
|
|||
|
|
|||
|
//If a curve only has one frame we don't need to interpolate or add keys to a curve as it's constant
|
|||
|
if (curve.Frames.Length <= 1)
|
|||
|
return null;
|
|||
|
|
|||
|
switch (curve.CurveType)
|
|||
|
{
|
|||
|
case ResU.AnimCurveType.Cubic:
|
|||
|
curve.Keys = new float[Keys.Count, 4];
|
|||
|
for (int frame = 0; frame < Keys.Count; frame++)
|
|||
|
{
|
|||
|
float Delta = 0;
|
|||
|
|
|||
|
if (frame < Keys.Count - 1)
|
|||
|
Delta = Keys[frame + 1] - Keys[frame];
|
|||
|
|
|||
|
float value = Keys[frame];
|
|||
|
float Slope = 0;
|
|||
|
float Slope2 = 0;
|
|||
|
|
|||
|
curve.Keys[frame, 0] = value;
|
|||
|
curve.Keys[frame, 1] = Slope;
|
|||
|
curve.Keys[frame, 2] = Slope2;
|
|||
|
curve.Keys[frame, 3] = Delta;
|
|||
|
}
|
|||
|
break;
|
|||
|
case ResU.AnimCurveType.StepInt:
|
|||
|
//Step requires no interpolation
|
|||
|
curve.Keys = new float[Keys.Count, 1];
|
|||
|
for (int frame = 0; frame < Keys.Count; frame++)
|
|||
|
{
|
|||
|
curve.Keys[frame, 0] = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case ResU.AnimCurveType.Linear:
|
|||
|
curve.Keys = new float[Keys.Count, 2];
|
|||
|
for (int frame = 0; frame < Keys.Count; frame++)
|
|||
|
{
|
|||
|
//Delta for second value used in linear curves
|
|||
|
float time = curve.Frames[frame];
|
|||
|
float Delta = 0;
|
|||
|
|
|||
|
if (frame < Keys.Count - 1)
|
|||
|
Delta = Keys[frame + 1] - Keys[frame];
|
|||
|
|
|||
|
curve.Keys[frame, 0] = Keys[frame];
|
|||
|
curve.Keys[frame, 1] = Delta;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return curve;
|
|||
|
}
|
|||
|
|
|||
|
private static ushort[] SetIndices(ResU.ShaderParamAnim fshu)
|
|||
|
{
|
|||
|
List<ushort> indces = new List<ushort>();
|
|||
|
foreach (var matAnim in fshu.ShaderParamMatAnims)
|
|||
|
indces.Add(65535);
|
|||
|
|
|||
|
return indces.ToArray();
|
|||
|
}
|
|||
|
private static uint CalculateBakeSize(ResU.ShaderParamAnim fshu)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class FSKAConverter
|
|||
|
{
|
|||
|
static float Deg2Rad = (float)(Math.PI / 180f);
|
|||
|
|
|||
|
public static SkeletalAnim Chr02Fska(string FileName)
|
|||
|
{
|
|||
|
CHR0Node chr0 = CHR0Node.FromFile(FileName);
|
|||
|
|
|||
|
SkeletalAnim fska = new SkeletalAnim();
|
|||
|
fska.FrameCount = chr0.FrameCount;
|
|||
|
fska.Name = chr0.Name;
|
|||
|
fska.Path = chr0.OriginalPath;
|
|||
|
fska.UserDatas = new List<Syroot.NintenTools.NSW.Bfres.UserData>();
|
|||
|
fska.UserDataDict = new ResDict();
|
|||
|
|
|||
|
//Set flags
|
|||
|
if (chr0.Loop)
|
|||
|
fska.FlagsAnimSettings |= SkeletalAnimFlags.Looping;
|
|||
|
fska.FlagsRotate = SkeletalAnimFlagsRotate.EulerXYZ;
|
|||
|
fska.FlagsScale = SkeletalAnimFlagsScale.Maya;
|
|||
|
|
|||
|
//Set bone anims and then calculate data after
|
|||
|
foreach (var entry in chr0.Children)
|
|||
|
fska.BoneAnims.Add(Chr0Entry2BoneAnim((CHR0EntryNode)entry));
|
|||
|
|
|||
|
fska.BakedSize = CalculateBakeSize(fska);
|
|||
|
fska.BindIndices = SetIndices(fska);
|
|||
|
|
|||
|
return fska;
|
|||
|
}
|
|||
|
|
|||
|
private static BoneAnim Chr0Entry2BoneAnim(CHR0EntryNode entry)
|
|||
|
{
|
|||
|
BoneAnim boneAnim = new BoneAnim();
|
|||
|
boneAnim.Name = entry.Name;
|
|||
|
|
|||
|
if (entry.UseModelTranslate)
|
|||
|
boneAnim.FlagsBase |= BoneAnimFlagsBase.Translate;
|
|||
|
if (entry.UseModelRotate)
|
|||
|
boneAnim.FlagsBase |= BoneAnimFlagsBase.Rotate;
|
|||
|
if (entry.UseModelScale)
|
|||
|
boneAnim.FlagsBase |= BoneAnimFlagsBase.Scale;
|
|||
|
|
|||
|
var FirstFrame = entry.GetAnimFrame(0);
|
|||
|
|
|||
|
float xRadian = FirstFrame.Rotation._x * Deg2Rad;
|
|||
|
float yRadian = FirstFrame.Rotation._y * Deg2Rad;
|
|||
|
float zRadian = FirstFrame.Rotation._z * Deg2Rad;
|
|||
|
|
|||
|
var baseData = new BoneAnimData();
|
|||
|
baseData.Translate = new Vector3F(FirstFrame.Translation._x, FirstFrame.Translation._y, FirstFrame.Translation._z);
|
|||
|
baseData.Rotate = new Vector4F(xRadian, yRadian, zRadian, 1);
|
|||
|
baseData.Scale = new Vector3F(FirstFrame.Scale._x, FirstFrame.Scale._y, FirstFrame.Scale._z);
|
|||
|
baseData.Flags = 0;
|
|||
|
boneAnim.BaseData = baseData;
|
|||
|
|
|||
|
boneAnim.FlagsBase |= BoneAnimFlagsBase.Translate;
|
|||
|
boneAnim.FlagsBase |= BoneAnimFlagsBase.Scale;
|
|||
|
boneAnim.FlagsBase |= BoneAnimFlagsBase.Rotate;
|
|||
|
|
|||
|
if (baseData.Rotate == new Vector4F(0, 0, 0, 1))
|
|||
|
boneAnim.FlagsTransform |= BoneAnimFlagsTransform.RotateZero;
|
|||
|
if (baseData.Translate == new Vector3F(0, 0, 0))
|
|||
|
boneAnim.FlagsTransform |= BoneAnimFlagsTransform.TranslateZero;
|
|||
|
if (baseData.Scale == new Vector3F(1, 1, 1))
|
|||
|
boneAnim.FlagsTransform |= BoneAnimFlagsTransform.ScaleOne;
|
|||
|
if (IsUniform(baseData.Scale))
|
|||
|
boneAnim.FlagsTransform |= BoneAnimFlagsTransform.ScaleUniform;
|
|||
|
if (!IsRoot(boneAnim))
|
|||
|
boneAnim.FlagsTransform |= BoneAnimFlagsTransform.SegmentScaleCompensate;
|
|||
|
|
|||
|
boneAnim.BeginTranslate = 6;
|
|||
|
boneAnim.BeginRotate = 3;
|
|||
|
|
|||
|
if (FirstFrame.HasKeys)
|
|||
|
{
|
|||
|
var AnimFrame = entry.GetAnimFrame(0);
|
|||
|
if (AnimFrame.hasTx)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.TranslateX;
|
|||
|
var curve = GenerateCurve(0x10, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasTy)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.TranslateY;
|
|||
|
var curve = GenerateCurve(0x14, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasTz)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.TranslateZ;
|
|||
|
var curve = GenerateCurve(0x18, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasRx)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.RotateX;
|
|||
|
var curve = GenerateCurve(0x20, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasRy)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.RotateY;
|
|||
|
var curve = GenerateCurve(0x24, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasRz)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.RotateZ;
|
|||
|
var curve = GenerateCurve(0x28, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasSx)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.ScaleX;
|
|||
|
var curve = GenerateCurve(0x4, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasSy)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.ScaleY;
|
|||
|
var curve = GenerateCurve(0x8, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
if (AnimFrame.hasSz)
|
|||
|
{
|
|||
|
boneAnim.FlagsCurve |= BoneAnimFlagsCurve.ScaleZ;
|
|||
|
var curve = GenerateCurve(0xC, entry);
|
|||
|
if (curve != null)
|
|||
|
boneAnim.Curves.Add(curve);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return boneAnim;
|
|||
|
}
|
|||
|
|
|||
|
private static bool IsRoot(BoneAnim boneAnim)
|
|||
|
{
|
|||
|
if (boneAnim.Name.Contains("root") || boneAnim.Name.Contains("center"))
|
|||
|
return true;
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
private static bool IsUniform(Vector3F value)
|
|||
|
{
|
|||
|
return value.X == value.Y && value.X == value.Z;
|
|||
|
}
|
|||
|
|
|||
|
private static bool HasKeyFrames(CHR0EntryNode entry)
|
|||
|
{
|
|||
|
for (int frame = 0; frame < entry.FrameCount; frame++)
|
|||
|
{
|
|||
|
var AnimFrame = entry.GetAnimFrame(frame);
|
|||
|
if (frame > 0)
|
|||
|
{
|
|||
|
if (AnimFrame.hasTx) return true;
|
|||
|
if (AnimFrame.hasTy) return true;
|
|||
|
if (AnimFrame.hasTz) return true;
|
|||
|
if (AnimFrame.hasRx) return true;
|
|||
|
if (AnimFrame.hasRy) return true;
|
|||
|
if (AnimFrame.hasRz) return true;
|
|||
|
if (AnimFrame.hasSx) return true;
|
|||
|
if (AnimFrame.hasSy) return true;
|
|||
|
if (AnimFrame.hasSz) return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
private static AnimCurve GenerateCurve(uint AnimOffset, CHR0EntryNode entry)
|
|||
|
{
|
|||
|
AnimCurve curve = new AnimCurve();
|
|||
|
curve.AnimDataOffset = AnimOffset;
|
|||
|
curve.StartFrame = 0;
|
|||
|
curve.Offset = 0;
|
|||
|
curve.Scale = 1;
|
|||
|
curve.FrameType = AnimCurveFrameType.Single;
|
|||
|
curve.KeyType = AnimCurveKeyType.Single;
|
|||
|
curve.CurveType = AnimCurveType.Cubic;
|
|||
|
|
|||
|
List<float> Frames = new List<float>();
|
|||
|
List<float[]> Keys = new List<float[]>();
|
|||
|
|
|||
|
for (int frame = 0; frame < entry.FrameCount; frame++)
|
|||
|
{
|
|||
|
//Max of 4 values. Cubic using 4, linear using 2, and step using 1
|
|||
|
float[] KeyValues = new float[4];
|
|||
|
|
|||
|
//Set the main values to the curve based on offset for encoding later
|
|||
|
var AnimFrame = entry.GetAnimFrame(frame);
|
|||
|
if (AnimFrame.hasTx && AnimOffset == 0x10)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
KeyValues[0] = AnimFrame.Translation._x;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasTy && AnimOffset == 0x14)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
KeyValues[0] = AnimFrame.Translation._y;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasTz && AnimOffset == 0x18)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
KeyValues[0] = AnimFrame.Translation._z;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasRx && AnimOffset == 0x20)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
float xRadian = AnimFrame.Rotation._x * Deg2Rad;
|
|||
|
KeyValues[0] = xRadian;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasRy && AnimOffset == 0x24)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
float yRadian = AnimFrame.Rotation._y * Deg2Rad;
|
|||
|
KeyValues[0] = yRadian;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasRz && AnimOffset == 0x28)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
float zRadian = AnimFrame.Rotation._z * Deg2Rad;
|
|||
|
KeyValues[0] = zRadian;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasSx && AnimOffset == 0x04)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
KeyValues[0] = AnimFrame.Scale._x;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasSy && AnimOffset == 0x08)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
KeyValues[0] = AnimFrame.Scale._y;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
if (AnimFrame.hasSz && AnimOffset == 0x0C)
|
|||
|
{
|
|||
|
Frames.Add(frame);
|
|||
|
KeyValues[0] = AnimFrame.Scale._z;
|
|||
|
Keys.Add(KeyValues);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//Max value in frames is our end frame
|
|||
|
curve.EndFrame = Frames.Max();
|
|||
|
curve.Frames = Frames.ToArray();
|
|||
|
|
|||
|
//If a curve only has one frame we don't need to interpolate or add keys to a curve as it's constant
|
|||
|
if (curve.Frames.Length <= 1)
|
|||
|
return null;
|
|||
|
|
|||
|
switch (curve.CurveType)
|
|||
|
{
|
|||
|
case AnimCurveType.Cubic:
|
|||
|
curve.Keys = new float[Keys.Count, 4];
|
|||
|
for (int frame = 0; frame < Keys.Count; frame++)
|
|||
|
{
|
|||
|
float Delta = 0;
|
|||
|
|
|||
|
if (frame < Keys.Count - 1)
|
|||
|
Delta = Keys[frame + 1][0] - Keys[frame][0];
|
|||
|
|
|||
|
float value = Keys[frame][0];
|
|||
|
float Slope = Keys[frame][1];
|
|||
|
float Slope2 = Keys[frame][2];
|
|||
|
|
|||
|
curve.Keys[frame, 0] = value;
|
|||
|
curve.Keys[frame, 1] = Slope;
|
|||
|
curve.Keys[frame, 2] = Slope2;
|
|||
|
curve.Keys[frame, 3] = Delta;
|
|||
|
}
|
|||
|
break;
|
|||
|
case AnimCurveType.StepInt:
|
|||
|
//Step requires no interpolation
|
|||
|
curve.Keys = new float[Keys.Count, 1];
|
|||
|
for (int frame = 0; frame < Keys.Count; frame++)
|
|||
|
{
|
|||
|
curve.Keys[frame, 0] = Keys[frame][0];
|
|||
|
}
|
|||
|
break;
|
|||
|
case AnimCurveType.Linear:
|
|||
|
curve.Keys = new float[Keys.Count, 2];
|
|||
|
for (int frame = 0; frame < Keys.Count; frame++)
|
|||
|
{
|
|||
|
//Delta for second value used in linear curves
|
|||
|
float time = curve.Frames[frame];
|
|||
|
float Delta = 0;
|
|||
|
|
|||
|
if (frame < Keys.Count - 1)
|
|||
|
Delta = Keys[frame + 1][0] - Keys[frame][0];
|
|||
|
|
|||
|
curve.Keys[frame, 0] = Keys[frame][0];
|
|||
|
curve.Keys[frame, 1] = Delta;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return curve;
|
|||
|
}
|
|||
|
|
|||
|
private static ushort[] SetIndices(SkeletalAnim fska)
|
|||
|
{
|
|||
|
List<ushort> indces = new List<ushort>();
|
|||
|
foreach (var boneAnim in fska.BoneAnims)
|
|||
|
indces.Add(65535);
|
|||
|
|
|||
|
return indces.ToArray();
|
|||
|
}
|
|||
|
private static uint CalculateBakeSize(SkeletalAnim fska)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|