summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ConsoleApp/ResFileCommands.cs2
-rw-r--r--NW4RTools/BrresReader.cs488
-rw-r--r--NW4RTools/Models/Animation/CharacterAnim.cs96
-rw-r--r--NW4RTools/Models/Animation/ColorAnim.cs34
-rw-r--r--NW4RTools/Models/Animation/Shared.cs32
-rw-r--r--NW4RTools/Models/Animation/TextureSRTAnim.cs18
-rw-r--r--NW4RTools/NW4RTools.csproj4
7 files changed, 637 insertions, 37 deletions
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<Models.Animation.TextureSRTAnim>(ins, ConvertAnmTexSRTResource));
break;
+ case "External":
+ File.Add(name, ReadAndConvertDict<byte[]>(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<Models.Animation.CharacterAnim.Node>(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<ColorAnim.Node>(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<TextureSRTAnim.Node>(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<Node> 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<Node> 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<Node> 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 @@
<Reference Include="System.Xml" />
<Reference Include="System.Drawing" />
<Reference Include="System.Core" />
- <Reference Include="OpenTK, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="OpenTK">
<HintPath>..\ExternalLibs\OpenTK.dll</HintPath>
</Reference>
</ItemGroup>
@@ -78,6 +77,7 @@
<Compile Include="ObjExporter.cs" />
<Compile Include="ObjImporter.cs" />
<Compile Include="DisplayListWriter.cs" />
+ <Compile Include="Models\Animation\Shared.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>