/// <summary> /// Decompresses values in a track /// </summary> /// <param name="parser"></param> /// <param name="dataOffset"></param> /// <param name="header"></param> /// <param name="valueCount"></param> /// <returns></returns> private List <float[]> DecompressValues(SSBHParser parser, uint dataOffset, SSBHAnimCompressedHeader header, int valueCount) { List <float[]> transforms = new List <float[]>(header.FrameCount); // PreProcess SSBHAnimCompressedItem[] items = parser.ByteToType <SSBHAnimCompressedItem>(valueCount); parser.Seek(dataOffset + header.DefaultDataOffset); float[] defaultValues = GetDefaultValues(parser, valueCount); parser.Seek(dataOffset + header.CompressedDataOffset); for (int frameIndex = 0; frameIndex < header.FrameCount; frameIndex++) { // Copy default values. float[] values = new float[valueCount]; for (int i = 0; i < valueCount; i++) { values[i] = defaultValues[i]; } for (int itemIndex = 0; itemIndex < items.Length; itemIndex++) { var item = items[itemIndex]; // Decompress int valueBitCount = (int)item.Count; if (valueBitCount == 0) { continue; } int value = parser.ReadBits(valueBitCount); int scale = 0; for (int k = 0; k < valueBitCount; k++) { scale |= 0x1 << k; } float frameValue = Lerp(item.Start, item.End, 0, 1, value / (float)scale); if (float.IsNaN(frameValue)) { frameValue = 0; } values[itemIndex] = frameValue; } transforms.Add(values); } return(transforms); }
/// <summary> /// Reads the data out of the given track. /// </summary> /// <param name="track"></param> /// <returns></returns> public object[] ReadTrack(AnimTrack track) { //Console.WriteLine(Track.Name + " " + Track.Flags.ToString("X") + " " + Track.FrameCount + " " + Track.DataOffset.ToString("X")); List <object> output = new List <object>(); using (SSBHParser parser = new SSBHParser(new MemoryStream(animFile.Buffer))) { parser.Seek(track.DataOffset); if (CheckFlag(track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant)) { output.Add(ReadDirect(parser, track.Flags)); } if (CheckFlag(track.Flags, 0xFF00, ANIM_TRACKFLAGS.ConstTransform)) { // TODO: investigate more output.Add(ReadDirect(parser, track.Flags)); } if (CheckFlag(track.Flags, 0xFF00, ANIM_TRACKFLAGS.Direct)) { for (int i = 0; i < track.FrameCount; i++) { output.Add(ReadDirect(parser, track.Flags)); } } if (CheckFlag(track.Flags, 0xFF00, ANIM_TRACKFLAGS.Compressed)) { output.AddRange(ReadCompressed(parser, track.Flags)); } } return(output.ToArray()); }
private static void ReadBooleans(SSBHParser reader, List <object> output, uint dataOffset, SSBHAnimCompressedHeader header) { reader.Seek((int)dataOffset + header.CompressedDataOffset); // note: there is a section for "default" and "compressed items" but they seem to always be 0-ed out for (int i = 0; i < header.FrameCount; i++) { output.Add(reader.ReadBits(header.BitsPerEntry) == 1); } }
public override void PostProcess(SSBHParser R) { R.Seek(OffsetToData); if (DataType == MatlEnums.ParamDataType.Float) { DataObject = R.ReadSingle(); } else if (DataType == MatlEnums.ParamDataType.Boolean) { DataObject = R.ReadUInt32() == 1; } else if (DataType == MatlEnums.ParamDataType.Vector4) { DataObject = R.Parse <MatlVector4>(); } else if (DataType == MatlEnums.ParamDataType.String) { DataObject = R.Parse <MtalString>(); } else if (DataType == MatlEnums.ParamDataType.Sampler) { DataObject = R.Parse <MtalSampler>(); } else if (DataType == MatlEnums.ParamDataType.UvTransform) { DataObject = R.Parse <MTAL_UVTransform>(); } else if (DataType == MatlEnums.ParamDataType.BlendState) { DataObject = R.Parse <MatlBlendState>(); } else if (DataType == MatlEnums.ParamDataType.RasterizerState) { DataObject = R.Parse <MatlRasterizerState>(); } }
/// <summary> /// decompresses transform values from a track /// </summary> /// <param name="parser"></param> /// <param name="dataOffset"></param> /// <param name="header"></param> /// <returns></returns> private AnimTrackTransform[] DecompressTransform(SSBHParser parser, uint dataOffset, SSBHAnimCompressedHeader header) { AnimTrackTransform[] transforms = new AnimTrackTransform[header.FrameCount]; // PreProcess SSBHAnimCompressedItem[] items = parser.ByteToType <SSBHAnimCompressedItem>(9); parser.Seek(dataOffset + header.DefaultDataOffset); float XSCA = parser.ReadSingle(); float YSCA = parser.ReadSingle(); float ZSCA = parser.ReadSingle(); float XROT = parser.ReadSingle(); float YROT = parser.ReadSingle(); float ZROT = parser.ReadSingle(); float WROT = parser.ReadSingle(); float XPOS = parser.ReadSingle(); float YPOS = parser.ReadSingle(); float ZPOS = parser.ReadSingle(); float CSCA = parser.ReadSingle(); parser.Seek(dataOffset + header.CompressedDataOffset); for (int frame = 0; frame < header.FrameCount; frame++) { AnimTrackTransform transform = new AnimTrackTransform() { X = XPOS, Y = YPOS, Z = ZPOS, RX = XROT, RY = YROT, RZ = ZROT, RW = WROT, SX = XSCA, SY = YSCA, SZ = ZSCA, CompensateScale = CSCA }; for (int itemIndex = 0; itemIndex < items.Length; itemIndex++) { // First check if this track should be parsed // TODO: Don't hard code these flags. if (!((itemIndex == 0 && (header.Flags & 0x3) == 0x3) || //isotropic scale (itemIndex >= 0 && itemIndex <= 2 && (header.Flags & 0x3) == 0x1) || //normal scale (itemIndex > 2 && itemIndex <= 5 && (header.Flags & 0x4) > 0) || (itemIndex > 5 && itemIndex <= 8 && (header.Flags & 0x8) > 0))) { continue; } var item = items[itemIndex]; // Decompress int valueBitCount = (int)item.Count; if (valueBitCount == 0) { continue; } int value = parser.ReadBits(valueBitCount); int scale = 0; for (int k = 0; k < valueBitCount; k++) { scale |= 0x1 << k; } float frameValue = Lerp(item.Start, item.End, 0, 1, value / (float)scale); if (float.IsNaN(frameValue)) { frameValue = 0; } // the Transform type relies a lot on flags if ((header.Flags & 0x3) == 0x3) { //Scale Compensate if (itemIndex == 0) { transform.CompensateScale = frameValue; } } if ((header.Flags & 0x3) == 0x1) { //Scale normal switch (itemIndex) { case 0: transform.SX = frameValue; break; case 1: transform.SY = frameValue; break; case 2: transform.SZ = frameValue; break; } } //Rotation and Position switch (itemIndex) { case 3: transform.RX = frameValue; break; case 4: transform.RY = frameValue; break; case 5: transform.RZ = frameValue; break; case 6: transform.X = frameValue; break; case 7: transform.Y = frameValue; break; case 8: transform.Z = frameValue; break; } } // Rotations have an extra bit at the end if ((header.Flags & 0x4) > 0) { bool wFlip = parser.ReadBits(1) == 1; // W is calculated transform.RW = (float)Math.Sqrt(Math.Abs(1 - (transform.RX * transform.RX + transform.RY * transform.RY + transform.RZ * transform.RZ))); if (wFlip) { transform.RW = -transform.RW; } } transforms[frame] = transform; } return(transforms); }
public object[] ReadTrack(AnimTrack Track) { Console.WriteLine(Track.Name + " " + Track.Flags.ToString() + " " + Track.FrameCount + " " + Track.DataOffset.ToString("X")); List <object> output = new List <object>(); using (SSBHParser parser = new SSBHParser(new MemoryStream(AnimFile.Buffer))) { parser.Seek(Track.DataOffset); if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Boolean)) { if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated)) { int Unk_4 = parser.ReadInt16(); int TrackFlag = parser.ReadInt16(); int Unk1 = parser.ReadInt16(); int Unk2 = parser.ReadInt16(); int DataStart = parser.ReadInt32(); int FrameCount = parser.ReadInt32(); parser.Seek((int)Track.DataOffset + DataStart); for (int i = 0; i < FrameCount; i++) { output.Add(new AnimTrackBool(parser.ReadBits(1) == 1)); } } else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant)) { output.Add(new AnimTrackBool(parser.ReadBits(1) == 1)); } } if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Vector4)) { if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated)) { int Unk_4 = parser.ReadInt16(); int TrackFlag = parser.ReadInt16(); int Unk1 = parser.ReadInt16(); int Unk2 = parser.ReadInt16(); int DataStart = parser.ReadInt32(); int FrameCount = parser.ReadInt32(); int[] ByteCounts = new int[9]; int[] BitCounts = new int[9]; float[] Start = new float[9]; float[] End = new float[9]; for (int i = 0; i < 4; i++) { Start[i] = parser.ReadSingle(); End[i] = parser.ReadSingle(); long Count = parser.ReadInt64(); long bytes = (Count >> 3); int bits = ((int)Count & 0x7); if ((i >= 0 && i <= 0 && (TrackFlag & 0x3) == 0x3) || //isotrophic scale (i >= 0 && i <= 2 && (TrackFlag & 0x3) == 0x1) || //normal scale (i > 2 && i <= 5 && (TrackFlag & 0x4) > 0) || (i > 5 && i <= 8 && (TrackFlag & 0x8) > 0)) { //reads { BitCounts[i] = bits; ByteCounts[i] = (int)bytes; } } } float X = parser.ReadSingle(); float Y = parser.ReadSingle(); float Z = parser.ReadSingle(); float W = parser.ReadSingle(); parser.Seek((int)Track.DataOffset + DataStart); for (int i = 0; i < FrameCount; i++) { AnimTrackCustomVector4 Vector = new AnimTrackCustomVector4(); for (int j = 0; j < 4; j++) { int ValueBitCount = ByteCounts[j] * 8 + BitCounts[j]; int Value = parser.ReadBits(ValueBitCount); int scale = 0; for (int k = 0; k < ValueBitCount; k++) { scale |= 0x1 << k; } float FrameValue = Lerp(Start[j], End[j], 0, 1, Value / (float)scale); if (float.IsNaN(FrameValue)) { FrameValue = 0; } switch (j) { case 0: if (ValueBitCount > 0) { Vector.X = FrameValue; } else { Vector.X = X; } break; case 1: if (ValueBitCount > 0) { Vector.Y = FrameValue; } else { Vector.Y = Y; } break; case 2: if (ValueBitCount > 0) { Vector.Z = FrameValue; } else { Vector.Z = Z; } break; case 3: if (ValueBitCount > 0) { Vector.W = FrameValue; } else { Vector.W = W; } break; } } output.Add(Vector); } } else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant)) { output.Add(new AnimTrackCustomVector4() { X = parser.ReadSingle(), Y = parser.ReadSingle(), Z = parser.ReadSingle(), W = parser.ReadSingle() }); } } if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Transform)) { if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated)) { int Unk_4 = parser.ReadInt16(); int TrackFlag = parser.ReadInt16(); int Unk1 = parser.ReadInt16(); int Unk2 = parser.ReadInt16(); int DataStart = parser.ReadInt32(); int FrameCount = parser.ReadInt32(); int[] ByteCounts = new int[9]; int[] BitCounts = new int[9]; float[] Start = new float[9]; float[] End = new float[9]; for (int i = 0; i < 9; i++) { Start[i] = parser.ReadSingle(); End[i] = parser.ReadSingle(); long Count = parser.ReadInt64(); long bytes = (Count >> 3); int bits = ((int)Count & 0x7); if ((i >= 0 && i <= 0 && (TrackFlag & 0x3) == 0x3) || //isotrophic scale (i >= 0 && i <= 2 && (TrackFlag & 0x3) == 0x1) || //normal scale (i > 2 && i <= 5 && (TrackFlag & 0x4) > 0) || (i > 5 && i <= 8 && (TrackFlag & 0x8) > 0)) { //reads { BitCounts[i] = bits; ByteCounts[i] = (int)bytes; } } } float XSCA = parser.ReadSingle(); float YSCA = parser.ReadSingle(); float ZSCA = parser.ReadSingle(); float XROT = parser.ReadSingle(); float YROT = parser.ReadSingle(); float ZROT = parser.ReadSingle(); float WROT = parser.ReadSingle(); float XPOS = parser.ReadSingle(); float YPOS = parser.ReadSingle(); float ZPOS = parser.ReadSingle(); parser.ReadInt32(); // ???? parser.Seek((int)Track.DataOffset + DataStart); for (int i = 0; i < FrameCount; i++) { AnimTrackTransform Transform = new AnimTrackTransform(); for (int j = 0; j < 9; j++) { int ValueBitCount = ByteCounts[j] * 8 + BitCounts[j]; int Value = parser.ReadBits(ValueBitCount); int scale = 0; for (int k = 0; k < ValueBitCount; k++) { scale |= 0x1 << k; } float FrameValue = Lerp(Start[j], End[j], 0, 1, Value / (float)scale); if (float.IsNaN(FrameValue)) { FrameValue = 0; } if ((TrackFlag & 0x3) == 0x3) { //Scale Isotropic if (j == 0) { Transform.SX = FrameValue; Transform.SY = FrameValue; Transform.SZ = FrameValue; } } else if ((TrackFlag & 0x3) == 0x1) { //Scale normal switch (j) { case 0: if (ValueBitCount > 0) { Transform.SX = FrameValue; } else { Transform.SX = XSCA; } break; case 1: if (ValueBitCount > 0) { Transform.SY = FrameValue; } else { Transform.SY = YSCA; } break; case 2: if (ValueBitCount > 0) { Transform.SZ = FrameValue; } else { Transform.SZ = ZSCA; } break; } } else { Transform.SX = XSCA; Transform.SY = YSCA; Transform.SZ = ZSCA; } //Rotation if ((TrackFlag & 0x4) > 0) { switch (j) { case 3: if (ValueBitCount > 0) { Transform.RX = FrameValue; } else { Transform.RX = XROT; } break; case 4: if (ValueBitCount > 0) { Transform.RY = FrameValue; } else { Transform.RY = YROT; } break; case 5: if (ValueBitCount > 0) { Transform.RZ = FrameValue; } else { Transform.RZ = ZROT; } break; } } else { Transform.RX = XROT; Transform.RY = YROT; Transform.RZ = ZROT; Transform.RW = WROT; } // Position if ((TrackFlag & 0x8) > 0) { switch (j) { case 6: if (ValueBitCount > 0) { Transform.X = FrameValue; } else { Transform.X = XPOS; } break; case 7: if (ValueBitCount > 0) { Transform.Y = FrameValue; } else { Transform.Y = YPOS; } break; case 8: if (ValueBitCount > 0) { Transform.Z = FrameValue; } else { Transform.Z = ZPOS; } break; } } else { Transform.X = XPOS; Transform.Y = YPOS; Transform.Z = ZPOS; } } if ((TrackFlag & 0x4) > 0) { // Rotation w bool Wflip = parser.ReadBits(1) == 1;// (TrackFlag & 0x1) == 0 ? parser.ReadBits(1) == 1 : true; Transform.RW = (float)Math.Sqrt(Math.Abs(1 - (Transform.RX * Transform.RX + Transform.RY * Transform.RY + Transform.RZ * Transform.RZ))); if (Wflip) { Transform.RW = -Transform.RW; } } output.Add(Transform); } } else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.ConstTransform)) { output.Add(new AnimTrackTransform() { SX = parser.ReadSingle(), SY = parser.ReadSingle(), SZ = parser.ReadSingle(), RX = parser.ReadSingle(), RY = parser.ReadSingle(), RZ = parser.ReadSingle(), RW = parser.ReadSingle(), X = parser.ReadSingle(), Y = parser.ReadSingle(), Z = parser.ReadSingle(), }); parser.ReadInt32(); // ???? } } } return(output.ToArray()); }