From 364e99d849378546323d1d06307b6773e813b742 Mon Sep 17 00:00:00 2001 From: Treeki Date: Sun, 19 Feb 2012 06:28:18 +0100 Subject: added what is probably horribly broken support for reading animations --- ConsoleApp/ResFileCommands.cs | 2 +- NW4RTools/BrresReader.cs | 488 ++++++++++++++++++++++++++- NW4RTools/Models/Animation/CharacterAnim.cs | 96 ++++-- NW4RTools/Models/Animation/ColorAnim.cs | 34 ++ NW4RTools/Models/Animation/Shared.cs | 32 ++ NW4RTools/Models/Animation/TextureSRTAnim.cs | 18 + NW4RTools/NW4RTools.csproj | 4 +- 7 files changed, 637 insertions(+), 37 deletions(-) create mode 100644 NW4RTools/Models/Animation/Shared.cs diff --git a/ConsoleApp/ResFileCommands.cs b/ConsoleApp/ResFileCommands.cs index 83c28b2..84ba13a 100644 --- a/ConsoleApp/ResFileCommands.cs +++ b/ConsoleApp/ResFileCommands.cs @@ -25,7 +25,7 @@ namespace ConsoleApp { var data = System.IO.File.ReadAllBytes(args[0]); - TargetFile = BrresReader.LoadFile(data, false); + TargetFile = BrresReader.LoadFile(data, true); TargetPath = args[0]; OperateOnFile(newArgs); diff --git a/NW4RTools/BrresReader.cs b/NW4RTools/BrresReader.cs index 8b9fcb1..f120943 100644 --- a/NW4RTools/BrresReader.cs +++ b/NW4RTools/BrresReader.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using NW4RTools.Models; +using NW4RTools.Models.Animation; namespace NW4RTools { public class BrresReader { @@ -98,6 +99,9 @@ namespace NW4RTools { case "AnmTexSrt(NW4R)": File.Add(name, ReadAndConvertDict(ins, ConvertAnmTexSRTResource)); break; + case "External": + File.Add(name, ReadAndConvertDict(ins, ConvertExternalResource)); + break; default: Debug.Send("Not implemented"); return; @@ -106,6 +110,14 @@ namespace NW4RTools { } + private byte[] ConvertExternalResource(string name, InputStream ins) { + using (var c = Debug.Push(name)) { + OffsetMap.Add(ins.Position, "External: " + name); + return null; + } + } + + private Texture ConvertTextureResource(string name, InputStream ins) { using (var c = Debug.Push(name)) { @@ -161,12 +173,263 @@ namespace NW4RTools { OffsetMap.Add(startPos, "Character Animation: " + name); - // TODO - + byte[] magic = ins.ReadBytes(4); + UInt32 size = ins.ReadUInt32(); + UInt32 version = ins.ReadUInt32(); + + Debug.Send("Offset: 0x{0:X}; Size: 0x{1:X}; Version: {2}", startPos, size, version); + + CHR_ANIM_HACK = anim; + + Int32 resFileOffset = ins.ReadInt32(); + Int32 dataOffset = ins.ReadInt32(); + ins.Skip(4); // No idea + Int32 nameOffset = ins.ReadInt32(); + ins.Skip(4); // No idea + + anim.FrameCount = ins.ReadUInt16(); + UInt16 nodeCount = ins.ReadUInt16(); + + anim.Loop = (ins.ReadUInt32() > 0); + anim.ScaleMode = (Model.ScaleModeType)ins.ReadUInt32(); + + ins.Seek(startPos + dataOffset); + anim.Nodes = ReadAndConvertDict(ins, ConvertAnmChrNode); + + CHR_ANIM_HACK = null; + return anim; } } + // HACK HACK HACK + private CharacterAnim CHR_ANIM_HACK; + + private Models.Animation.CharacterAnim.Node ConvertAnmChrNode(string name, InputStream ins) { + using (var c = Debug.Push(name)) { + var node = new Models.Animation.CharacterAnim.Node(); + + int startPos = ins.Position; + OffsetMap.Add(startPos, "AnmChr Node: " + name); + + UInt32 nameOffset = ins.ReadUInt32(); + CharacterAnim.Flags flags = (CharacterAnim.Flags)ins.ReadUInt32(); + + Debug.Send("{0:X}", (UInt32)flags); + Debug.Send("{0}", flags); + node.ScaleFormat = (CharacterAnim.STFormatType)((UInt32)(flags & CharacterAnim.Flags.ScaleFormatMask) >> 25); + node.RotateFormat = (CharacterAnim.RotateFormatType)((UInt32)(flags & CharacterAnim.Flags.RotateFormatMask) >> 27); + node.TranslateFormat = (CharacterAnim.STFormatType)((UInt32)(flags & CharacterAnim.Flags.TranslateFormatMask) >> 30); + + node.Flags = flags & CharacterAnim.Flags.NonComputableFlags; + + // SCALES + bool needScaleYZ = true; + + if ((flags & CharacterAnim.Flags.ScaleXNotExist) == 0) { + node.ScaleX = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.ScaleXConstant, + (CharacterAnim.RotateFormatType)node.ScaleFormat); + + if ((flags & CharacterAnim.Flags.ScaleUniform) != 0) { + node.ScaleY = node.ScaleX; + node.ScaleZ = node.ScaleX; + needScaleYZ = false; + } + } else { + node.ScaleX = new KeyframeAnim(1.0f); + } + + if (needScaleYZ) { + if ((flags & CharacterAnim.Flags.ScaleYNotExist) == 0) + node.ScaleY = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.ScaleYConstant, + (CharacterAnim.RotateFormatType)node.ScaleFormat); + else + node.ScaleY = new KeyframeAnim(1.0f); + + if ((flags & CharacterAnim.Flags.ScaleZNotExist) == 0) + node.ScaleZ = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.ScaleZConstant, + (CharacterAnim.RotateFormatType)node.ScaleFormat); + else + node.ScaleZ = new KeyframeAnim(1.0f); + } + + // ROTATIONS + if ((flags & CharacterAnim.Flags.RotateXNotExist) == 0) { + node.RotateX = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.RotateXConstant, + node.RotateFormat); + } else { + node.RotateX = new KeyframeAnim(0.0f); + } + + if ((flags & CharacterAnim.Flags.RotateYNotExist) == 0) { + node.RotateY = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.RotateYConstant, + node.RotateFormat); + } else { + node.RotateY = new KeyframeAnim(0.0f); + } + + if ((flags & CharacterAnim.Flags.RotateZNotExist) == 0) { + node.RotateZ = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.RotateZConstant, + node.RotateFormat); + } else { + node.RotateZ = new KeyframeAnim(0.0f); + } + + // TRANSLATIIONS + + if ((flags & CharacterAnim.Flags.TranslateXNotExist) == 0) { + node.TranslateX = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.TranslateXConstant, + (CharacterAnim.RotateFormatType)node.TranslateFormat); + } else { + node.TranslateX = new KeyframeAnim(0.0f); + } + + if ((flags & CharacterAnim.Flags.TranslateYNotExist) == 0) { + node.TranslateY = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.TranslateYConstant, + (CharacterAnim.RotateFormatType)node.TranslateFormat); + } else { + node.TranslateY = new KeyframeAnim(0.0f); + } + + if ((flags & CharacterAnim.Flags.TranslateZNotExist) == 0) { + node.TranslateZ = ReadAnmChrElement( + ins, startPos, node, flags, + CharacterAnim.Flags.TranslateZConstant, + (CharacterAnim.RotateFormatType)node.TranslateFormat); + } else { + node.TranslateZ = new KeyframeAnim(0.0f); + } + + return node; + } + } + + private KeyframeAnim ReadAnmChrElement( + InputStream ins, int startPos, CharacterAnim.Node node, + CharacterAnim.Flags flags, CharacterAnim.Flags isConstF, CharacterAnim.RotateFormatType format) { + + var elem = new KeyframeAnim(); + + elem.IsConstant = (flags & isConstF) != 0; + OffsetMap.Add(ins.Position, String.Format("Element [{0}]", elem.IsConstant ? "Constant" : "Keyframes")); + + if (elem.IsConstant) { + elem.ConstValue = ins.ReadFloat(); + } else if ( + format == CharacterAnim.RotateFormatType.Data32 || + format == CharacterAnim.RotateFormatType.Data48 || + format == CharacterAnim.RotateFormatType.Data96) { + // KEYFRAME DATA + int savePos = ins.Position; + ins.Seek(startPos + ins.ReadInt32()); + int kfPos = ins.Position; + + UInt16 kfCount = ins.ReadUInt16(); + ins.Skip(2); + + OffsetMap[kfPos] = String.Format("Element Keyframe Data for {0:X} [{1} frames]", savePos, kfCount); + + float invKeyFrameRange = ins.ReadFloat(); + elem.Keyframes = new Keyframe[kfCount]; + + Debug.Send("{0}", format); + for (int i = 0; i < kfCount; i++) { + switch (format) { + case CharacterAnim.RotateFormatType.Data32: + UInt32 val = ins.ReadUInt32(); + + // Is this correct? + elem.Keyframes[i].Frame = val >> 24; + elem.Keyframes[i].Value = (val >> 12) & 0xFFF; + elem.Keyframes[i].Slope = ((float)(val & 0xFFF)) / 32.0f; + break; + + case CharacterAnim.RotateFormatType.Data48: + // Is this correct? + elem.Keyframes[i].Frame = ((float)ins.ReadInt16()) / 32.0f; + elem.Keyframes[i].Value = ((float)ins.ReadUInt16()) * (360.0f / 0x10000); + elem.Keyframes[i].Slope = ((float)ins.ReadInt16()) / 256.0f; + break; + + case CharacterAnim.RotateFormatType.Data96: + elem.Keyframes[i].Frame = ins.ReadFloat(); + elem.Keyframes[i].Value = ins.ReadFloat(); + elem.Keyframes[i].Slope = ins.ReadFloat(); + break; + + } + } + + ins.Seek(savePos + 4); + + } else if ( + format == CharacterAnim.RotateFormatType.DataUnk4 || + format == CharacterAnim.RotateFormatType.DataUnk5) { + // SOMETHING ELSE + int savePos = ins.Position; + ins.Seek(startPos + ins.ReadInt32()); + int kfPos = ins.Position; + + OffsetMap[kfPos] = String.Format("Element Multiplied Frame Data for {0:X}", savePos); + + elem.Multiplier = ins.ReadFloat(); + elem.BaseValue = ins.ReadFloat(); + elem.Values = new int[CHR_ANIM_HACK.FrameCount]; + + for (int i = 0; i < CHR_ANIM_HACK.FrameCount; i++) { + switch (format) { + case CharacterAnim.RotateFormatType.DataUnk4: + elem.Values[i] = ins.ReadByte(); + break; + case CharacterAnim.RotateFormatType.DataUnk5: + elem.Values[i] = ins.ReadUInt16(); + break; + } + } + + ins.Seek(savePos + 4); + + } else if ( + format == CharacterAnim.RotateFormatType.DataUnk6) { + // WHAT THE FUCK + int savePos = ins.Position; + ins.Seek(startPos + ins.ReadInt32()); + int kfPos = ins.Position; + + OffsetMap[kfPos] = String.Format("Element Type 6 Frame Data for {0:X}", savePos); + + elem.BaseValue = ins.ReadFloat(); + elem.FloatValues = new float[CHR_ANIM_HACK.FrameCount]; + + for (int i = 0; i < CHR_ANIM_HACK.FrameCount; i++) { + elem.FloatValues[i] = ins.ReadFloat(); + } + + ins.Seek(savePos + 4); + + } else { + Debug.Send("Unimplemented format {0} at {1:X}", format, ins.Position); + } + + return elem; + } + private Models.Animation.ColorAnim ConvertAnmClrResource(string name, InputStream ins) { @@ -176,13 +439,88 @@ namespace NW4RTools { int startPos = ins.Position; OffsetMap.Add(startPos, "Color Animation: " + name); - - // TODO - + + byte[] magic = ins.ReadBytes(4); + UInt32 size = ins.ReadUInt32(); + UInt32 version = ins.ReadUInt32(); + + Debug.Send("Offset: 0x{0:X}; Size: 0x{1:X}; Version: {2}", startPos, size, version); + + Int32 resFileOffset = ins.ReadInt32(); + Int32 dataOffset = ins.ReadInt32(); + ins.Skip(4); // No idea + Int32 nameOffset = ins.ReadInt32(); + ins.Skip(4); // No idea + + anim.FrameCount = ins.ReadUInt16(); + UInt16 nodeCount = ins.ReadUInt16(); + + anim.Loop = (ins.ReadUInt32() > 0); + + COLOR_ANIM_HACK = anim; + ins.Seek(startPos + dataOffset); + anim.Nodes = ReadAndConvertDict(ins, ConvertAnmClrNode); + COLOR_ANIM_HACK = null; + return anim; } } + // HACK HACK HACK + private ColorAnim COLOR_ANIM_HACK; + + private ColorAnim.Node ConvertAnmClrNode(string name, InputStream ins) { + using (var c = Debug.Push(name)) { + var node = new ColorAnim.Node(); + + int startPos = ins.Position; + OffsetMap[startPos] = "AnmClr Node: " + name; + + UInt32 nameOffset = ins.ReadUInt32(); + UInt32 flags = ins.ReadUInt32(); + + node.Elements = new ColorAnim.Element[(int)ColorAnim.TargetType.Count]; + + for (int i = 0; i < node.Elements.Length; i++) { + node.Elements[i] = ReadAnmClrElement(ins, startPos, flags); + flags >>= 2; + } + + return node; + } + } + + private ColorAnim.Element ReadAnmClrElement(InputStream ins, int startPos, UInt32 flags) { + var elem = new ColorAnim.Element(); + + elem.Exists = (flags & 1) != 0; + elem.IsConstant = (flags & 2) != 0; + + OffsetMap[ins.Position] = String.Format("Element [{0}]", elem.IsConstant ? "Constant" : "Colours"); + + elem.Mask = ins.ReadUInt32(); + + if (!elem.Exists) + return elem; + + if (elem.IsConstant) { + elem.ConstValue = ins.ReadColor(); + } else { + int savePos = ins.Position; + ins.Seek(startPos + ins.ReadInt32()); + + elem.Colors = new Color[COLOR_ANIM_HACK.FrameCount + 1]; + + for (int i = 0; i < elem.Colors.Length; i++) { + elem.Colors[i] = ins.ReadColor(); + } + + ins.Seek(savePos + 4); + } + + return elem; + } + private Models.Animation.TextureSRTAnim ConvertAnmTexSRTResource(string name, InputStream ins) { @@ -193,12 +531,148 @@ namespace NW4RTools { OffsetMap.Add(startPos, "Texture SRT Animation: " + name); - // TODO - + byte[] magic = ins.ReadBytes(4); + UInt32 size = ins.ReadUInt32(); + UInt32 version = ins.ReadUInt32(); + + Debug.Send("Offset: 0x{0:X}; Size: 0x{1:X}; Version: {2}", startPos, size, version); + + Int32 resFileOffset = ins.ReadInt32(); + Int32 dataOffset = ins.ReadInt32(); + ins.Skip(4); // No idea + Int32 nameOffset = ins.ReadInt32(); + ins.Skip(4); // No idea + + anim.FrameCount = ins.ReadUInt16(); + UInt16 nodeCount = ins.ReadUInt16(); + + anim.MatrixMode = (Model.TexMatrixModeType)ins.ReadUInt32(); + anim.Loop = (ins.ReadUInt32() > 0); + + ins.Seek(startPos + dataOffset); + anim.Nodes = ReadAndConvertDict(ins, ConvertAnmTexSRTNode); + return anim; } } + private TextureSRTAnim.Node ConvertAnmTexSRTNode(string name, InputStream ins) { + using (var c = Debug.Push(name)) { + var node = new TextureSRTAnim.Node(); + + int startPos = ins.Position; + OffsetMap.Add(startPos, "AnmTexSRT Node: " + name); + + UInt32 nameOffset = ins.ReadUInt32(); + UInt32 flags = ins.ReadUInt32(); + UInt32 indFlags = ins.ReadUInt32(); + Debug.Send("Flags: {0:X}, {1:X}", flags, indFlags); + + node.Textures = new TextureSRTAnim.Element[8]; + node.IndirectTextures = new TextureSRTAnim.Element[3]; + + for (int i = 0; i < 8; i++) { + Debug.Send("Texture {0}", i); + if ((flags & 1) == 0) + node.Textures[i].Exists = false; + else + node.Textures[i] = ReadAnmTexSRTElement(ins, startPos); + flags >>= 1; + } + + for (int i = 0; i < 3; i++) { + Debug.Send("Indirect Texture {0}", i); + if ((indFlags & 1) == 0) + node.IndirectTextures[i].Exists = false; + else + node.IndirectTextures[i] = ReadAnmTexSRTElement(ins, startPos); + indFlags >>= 1; + } + + return node; + } + } + + private TextureSRTAnim.Element ReadAnmTexSRTElement(InputStream ins, int startPos) { + var elem = new TextureSRTAnim.Element(); + + int savePos = ins.Position; + ins.Seek(startPos + ins.ReadInt32()); + + OffsetMap.Add(ins.Position, String.Format("Element")); + + Debug.Send("Offset: {0:X}", ins.Position); + UInt32 flags = ins.ReadUInt32(); + Debug.Send("Element Flags: {0:X}", flags); + + if ((flags & 2) != 0) { + Debug.Send("Scale 1"); + elem.ScaleS = new KeyframeAnim(1.0f); + elem.ScaleT = new KeyframeAnim(1.0f); + } else { + Debug.Send("Reading Scale S @ {0:X}", ins.Position); + elem.ScaleS = ReadKeyframeAnim(ins, (flags & 0x20) != 0); + if ((flags & 0x10) != 0) { + Debug.Send("Uniform Scale"); + elem.ScaleT = elem.ScaleS; + } else { + Debug.Send("Reading Scale T @ {0:X}", ins.Position); + elem.ScaleT = ReadKeyframeAnim(ins, (flags & 0x40) != 0); + } + } + + if ((flags & 4) != 0) { + Debug.Send("Rotate 0"); + elem.Rotate = new KeyframeAnim(0.0f); + } else { + Debug.Send("Reading Rotate @ {0:X}", ins.Position); + elem.Rotate = ReadKeyframeAnim(ins, (flags & 0x80) != 0); + } + + if ((flags & 8) != 0) { + Debug.Send("Trans 0"); + elem.TransS = new KeyframeAnim(0.0f); + elem.TransT = new KeyframeAnim(0.0f); + } else { + Debug.Send("Reading Trans S @ {0:X}", ins.Position); + elem.TransS = ReadKeyframeAnim(ins, (flags & 0x100) != 0); + Debug.Send("Reading Trans T @ {0:X}", ins.Position); + elem.TransT = ReadKeyframeAnim(ins, (flags & 0x200) != 0); + } + + ins.Seek(savePos + 4); + + return elem; + } + + + private KeyframeAnim ReadKeyframeAnim(InputStream ins, bool isConst) { + var output = new KeyframeAnim(); + + output.IsConstant = isConst; + if (isConst) { + output.ConstValue = ins.ReadFloat(); + } else { + int basePos = ins.Position; + int offset = ins.ReadInt32(); + ins.Seek(basePos + offset); + + UInt16 kfCount = ins.ReadUInt16(); + ins.Skip(2); + float invKeyFrameRange = ins.ReadFloat(); + + output.Keyframes = new Keyframe[kfCount]; + for (int i = 0; i < kfCount; i++) { + output.Keyframes[i].Frame = ins.ReadFloat(); + output.Keyframes[i].Value = ins.ReadFloat(); + output.Keyframes[i].Slope = ins.ReadFloat(); + } + + ins.Seek(basePos + 4); + } + + return output; + } private Model ConvertModelResource(string name, InputStream ins) { diff --git a/NW4RTools/Models/Animation/CharacterAnim.cs b/NW4RTools/Models/Animation/CharacterAnim.cs index 33c30ce..dd496f6 100644 --- a/NW4RTools/Models/Animation/CharacterAnim.cs +++ b/NW4RTools/Models/Animation/CharacterAnim.cs @@ -1,44 +1,86 @@ using System; + namespace NW4RTools.Models.Animation { public class CharacterAnim { [FlagsAttribute] public enum Flags : uint { - Unk0 = 1, - Unk1 = 2, - Unk2 = 4, - Unk3 = 8, - Unk4 = 0x10, + AlwaysSet = 1, + Identity = 2, + RtZero = 4, + ScaleOne = 8, + ScaleUniform = 0x10, RotateZero = 0x20, TranslateZero = 0x40, - Unk7 = 0x80, - Unk8 = 0x100, - Unk9 = 0x200, - Unk10 = 0x400, - Unk11 = 0x800, - Unk12 = 0x1000, - Unk13 = 0x2000, - Unk14 = 0x4000, - Unk15 = 0x8000, - Unk16 = 0x10000, - Unk17 = 0x20000, - Unk18 = 0x40000, - Unk19 = 0x80000, - Unk20 = 0x100000, - Unk21 = 0x200000, + ScaleUseModel = 0x80, + RotateUseModel = 0x100, + TranslateUseModel = 0x200, + ScaleCompensateApply = 0x400, + ScaleCompensateParent = 0x800, + ClassicScaleOff = 0x1000, + ScaleXConstant = 0x2000, + ScaleYConstant = 0x4000, + ScaleZConstant = 0x8000, + RotateXConstant = 0x10000, + RotateYConstant = 0x20000, + RotateZConstant = 0x40000, + TranslateXConstant = 0x80000, + TranslateYConstant = 0x100000, + TranslateZConstant = 0x200000, CalcScale = 0x400000, CalcRotate = 0x800000, CalcTranslate = 0x1000000, - Unk25 = 0x2000000, - Unk26 = 0x4000000, - Unk27 = 0x8000000, - Unk28 = 0x10000000, - Unk29 = 0x20000000, - Unk30 = 0x40000000, - Unk31 = 0x80000000, + ScaleFormatMask = 0x6000000, + RotateFormatMask = 0x38000000, + TranslateFormatMask = 0xC0000000, + + ScaleXNotExist = Identity | ScaleOne | ScaleUseModel, + ScaleYNotExist = Identity | ScaleOne | ScaleUniform | ScaleUseModel, + ScaleZNotExist = Identity | ScaleOne | ScaleUniform | ScaleUseModel, + RotateXNotExist = Identity | RtZero | RotateZero | RotateUseModel, + RotateYNotExist = Identity | RtZero | RotateZero | RotateUseModel, + RotateZNotExist = Identity | RtZero | RotateZero | RotateUseModel, + TranslateXNotExist = Identity | RtZero | TranslateZero | TranslateUseModel, + TranslateYNotExist = Identity | RtZero | TranslateZero | TranslateUseModel, + TranslateZNotExist = Identity | RtZero | TranslateZero | TranslateUseModel, + + NonComputableFlags = ScaleCompensateApply | ScaleCompensateParent | ClassicScaleOff, } + public enum STFormatType { + Constant = 0, + Data32 = 1, + Data48 = 2, + Data96 = 3, + } + + public enum RotateFormatType { + Constant = 0, + Data32 = 1, + Data48 = 2, + Data96 = 3, + DataUnk4 = 4, + DataUnk5 = 5, + DataUnk6 = 6, + Zero = 7, + } + + public Model.ScaleModeType ScaleMode; + public bool Loop; + + public UInt16 FrameCount; + + public ResDict Nodes; + public class Node { + public CharacterAnim.Flags Flags; + + public KeyframeAnim ScaleX, ScaleY, ScaleZ; + public KeyframeAnim RotateX, RotateY, RotateZ; + public KeyframeAnim TranslateX, TranslateY, TranslateZ; + public STFormatType ScaleFormat; + public STFormatType TranslateFormat; + public RotateFormatType RotateFormat; } public CharacterAnim() { diff --git a/NW4RTools/Models/Animation/ColorAnim.cs b/NW4RTools/Models/Animation/ColorAnim.cs index e1e14bc..de8fdbd 100644 --- a/NW4RTools/Models/Animation/ColorAnim.cs +++ b/NW4RTools/Models/Animation/ColorAnim.cs @@ -1,6 +1,40 @@ using System; namespace NW4RTools.Models.Animation { public class ColorAnim { + public bool Loop; + + public UInt16 FrameCount; + + public ResDict Nodes; + + public struct Element { + public UInt32 Mask; + + public bool Exists, IsConstant; + + public Color ConstValue; + public Color[] Colors; + } + + public enum TargetType { + Material0 = 0, + Material1 = 1, + Ambient0 = 2, + Ambient1 = 3, + Tev0 = 4, + Tev1 = 5, + Tev2 = 6, + TevConst0 = 7, + TevConst1 = 8, + TevConst2 = 9, + TevConst3 = 10, + Count = 11, + } + + public class Node { + public Element[] Elements; + } + public ColorAnim() { } } diff --git a/NW4RTools/Models/Animation/Shared.cs b/NW4RTools/Models/Animation/Shared.cs new file mode 100644 index 0000000..f87bea6 --- /dev/null +++ b/NW4RTools/Models/Animation/Shared.cs @@ -0,0 +1,32 @@ +using System; + +namespace NW4RTools.Models.Animation { + public struct Keyframe { + public float Frame, Value, Slope; + } + + public struct KeyframeAnim { + public bool IsConstant; + + public float ConstValue; + + public Keyframe[] Keyframes; + + // Only valid sometimes + // This sucks but I'm not sure how else to do it atm + public float BaseValue, Multiplier; + public int[] Values; + public float[] FloatValues; + + public KeyframeAnim(float cv) { + IsConstant = true; + ConstValue = cv; + + Keyframes = null; + + BaseValue = Multiplier = 0; + Values = null; + FloatValues = null; + } + } +} diff --git a/NW4RTools/Models/Animation/TextureSRTAnim.cs b/NW4RTools/Models/Animation/TextureSRTAnim.cs index edc3593..d033f5f 100644 --- a/NW4RTools/Models/Animation/TextureSRTAnim.cs +++ b/NW4RTools/Models/Animation/TextureSRTAnim.cs @@ -1,6 +1,24 @@ using System; namespace NW4RTools.Models.Animation { public class TextureSRTAnim { + public Model.TexMatrixModeType MatrixMode; + public bool Loop; + + public UInt16 FrameCount; + + public ResDict Nodes; + + public struct Element { + public bool Exists; + + public KeyframeAnim ScaleS, ScaleT, Rotate, TransS, TransT; + } + + public class Node { + public Element[] Textures; + public Element[] IndirectTextures; + } + public TextureSRTAnim() { } } diff --git a/NW4RTools/NW4RTools.csproj b/NW4RTools/NW4RTools.csproj index 593bafb..bcdc413 100644 --- a/NW4RTools/NW4RTools.csproj +++ b/NW4RTools/NW4RTools.csproj @@ -36,8 +36,7 @@ - - False + ..\ExternalLibs\OpenTK.dll @@ -78,6 +77,7 @@ + -- cgit v1.2.3