/// <summary> /// Reads the data from a compressed track /// </summary> /// <param name="reader"></param> /// <param name="flags"></param> /// <returns></returns> private object[] ReadCompressed(SsbhParser reader, uint flags) { List <object> output = new List <object>(); uint dataOffset = (uint)reader.BaseStream.Position; SsbhAnimCompressedHeader header = reader.ByteToType <SsbhAnimCompressedHeader>(); if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Boolean)) { ReadBooleans(reader, output, dataOffset, header); } if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Texture)) { // TODO: What type is this } if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Float)) { //TODO: What type is this } if (CheckFlag(flags, 0x00FF, AnimTrackFlags.PatternIndex)) { //TODO: What type is this } if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Vector4)) { ReadVector4(reader, output, dataOffset, header); } if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Transform)) { ReadTransform(reader, output, dataOffset, header); } return(output.ToArray()); }
/// <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> /// 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); }