public static W3dMotionChannelTimeCodedData Parse(BinaryReader reader, ushort numTimeCodes, W3dAnimationChannelType channelType) { var keyframes = new ushort[numTimeCodes]; for (var i = 0; i < numTimeCodes; i++) { keyframes[i] = reader.ReadUInt16(); } if (numTimeCodes % 2 != 0) { // Align to 4-byte boundary. reader.ReadUInt16(); } var data = new W3dAnimationChannelDatum[numTimeCodes]; for (var i = 0; i < numTimeCodes; i++) { data[i] = W3dAnimationChannelDatum.Parse(reader, channelType); } return(new W3dMotionChannelTimeCodedData { TimeCodes = keyframes, Values = data }); }
internal static W3dAnimationChannel Parse(BinaryReader reader, W3dParseContext context) { return(ParseChunk(reader, context, header => { var startPosition = reader.BaseStream.Position; var result = new W3dAnimationChannel { FirstFrame = reader.ReadUInt16(), LastFrame = reader.ReadUInt16(), VectorLength = reader.ReadUInt16(), ChannelType = reader.ReadUInt16AsEnum <W3dAnimationChannelType>(), Pivot = reader.ReadUInt16(), Unknown = reader.ReadUInt16() }; ValidateChannelDataSize(result.ChannelType, result.VectorLength); var numElements = result.LastFrame - result.FirstFrame + 1; var data = new W3dAnimationChannelDatum[numElements]; for (var i = 0; i < numElements; i++) { data[i] = W3dAnimationChannelDatum.Parse(reader, result.ChannelType); } result.Data = data; result.NumPadBytes = (uint)(context.CurrentEndPosition - reader.BaseStream.Position); reader.BaseStream.Seek((int)result.NumPadBytes, SeekOrigin.Current); return result; })); }
public static W3dAnimationChannel Parse(BinaryReader reader, uint chunkSize) { var startPosition = reader.BaseStream.Position; var result = new W3dAnimationChannel { FirstFrame = reader.ReadUInt16(), LastFrame = reader.ReadUInt16(), VectorLength = reader.ReadUInt16(), ChannelType = reader.ReadUInt16AsEnum <W3dAnimationChannelType>(), Pivot = reader.ReadUInt16() }; reader.ReadUInt16(); // Pad ValidateChannelDataSize(result.ChannelType, result.VectorLength); var numElements = result.LastFrame - result.FirstFrame + 1; var data = new W3dAnimationChannelDatum[numElements]; for (var i = 0; i < numElements; i++) { data[i] = W3dAnimationChannelDatum.Parse(reader, result.ChannelType); } result.Data = data; // Pad var endPosition = startPosition + chunkSize; reader.ReadBytes((int)(endPosition - reader.BaseStream.Position)); return(result); }
public static W3dAnimationChannelDatum[] ReadAdaptiveDelta(BinaryReader reader, uint numFrames, W3dAnimationChannelType type, int vectorLen, float scale, int nBits) { float scaleFactor = 1.0f; switch (nBits) { //When deltas are 8 bits large we need to scale them to the range [-16;16] case 8: scaleFactor = 1 / 16.0f; break; //Do nothing for 4 bit deltas since they already map to [-16;16] case 4: break; default: throw new InvalidOperationException("Adaptive delta only supported 4 bit & 8 bit!"); } uint count = (numFrames + 15) >> 4; var data = new W3dAnimationChannelDatum[numFrames]; //First read all initial values for (int k = 0; k < vectorLen; ++k) { var initial = reader.ReadSingle(); UpdateDatum(ref data[0], initial, type, k); } //Then read the interleaved delta blocks for (int i = 0; i < count; ++i) { for (int k = 0; k < vectorLen; ++k) { var blockIndex = reader.ReadByte(); var blockScale = Table[blockIndex]; var deltaScale = blockScale * scale * scaleFactor; //read deltas for the next var deltas = ReadDeltaBlock(reader, nBits); for (int j = 0; j < deltas.Length; ++j) { int idx = i * 16 + j + 1; if (idx >= numFrames) { break; } var value = GetValue(data[idx - 1], type, k) + deltaScale * deltas[j]; UpdateDatum(ref data[idx], value, type, k); } } } return(data); }
public static W3dAnimationChannelDatum[] Decode( W3dAdaptiveDeltaData data, uint numFrames, float scale) { var scaleFactor = 1.0f; switch (data.BitCount) { // Do nothing for 4 bit deltas since they already map to [-16;16] case W3dAdaptiveDeltaBitCount.FourBits: break; // When deltas are 8 bits large we need to scale them to the range [-16;16] case W3dAdaptiveDeltaBitCount.EightBits: scaleFactor = 1 / 16.0f; break; default: throw new InvalidOperationException("Adaptive delta only supported 4 bit & 8 bit!"); } var result = new W3dAnimationChannelDatum[numFrames]; result[0] = data.InitialDatum; for (var i = 0; i < data.DeltaBlocks.Length; i++) { var deltaBlock = data.DeltaBlocks[i]; var blockIndex = deltaBlock.BlockIndex; var blockScale = Table[blockIndex]; var deltaScale = blockScale * scale * scaleFactor; var vectorIndex = deltaBlock.VectorIndex; var deltas = deltaBlock.GetDeltas(data.BitCount); for (var j = 0; j < deltas.Length; j++) { var idx = ((i / data.VectorLength) * 16) + j + 1; if (idx >= numFrames) { break; } var value = result[idx - 1].GetValue(vectorIndex) + deltaScale * deltas[j]; result[idx] = result[idx].WithValue(value, vectorIndex); idx++; } } return(result); }
internal static W3dTimeCodedDatum Parse(BinaryReader reader, W3dAnimationChannelType channelType) { var result = new W3dTimeCodedDatum(); result.TimeCode = reader.ReadUInt32(); // MSB is used to indicate a binary (non interpolated) movement if ((result.TimeCode >> 31) == 1) { result.NonInterpolatedMovement = true; // TODO: non-interpolated movement. result.TimeCode &= ~(1 << 31); } result.Value = W3dAnimationChannelDatum.Parse(reader, channelType); return(result); }
private static float GetValue(W3dAnimationChannelDatum datum, W3dAnimationChannelType type, int i = 0) { if (i > 0 && type != W3dAnimationChannelType.Quaternion) { throw new InvalidDataException(); } switch (type) { case W3dAnimationChannelType.TranslationX: case W3dAnimationChannelType.TranslationY: case W3dAnimationChannelType.TranslationZ: case W3dAnimationChannelType.XR: case W3dAnimationChannelType.YR: case W3dAnimationChannelType.ZR: case W3dAnimationChannelType.UnknownBfme: return(datum.FloatValue); case W3dAnimationChannelType.Quaternion: switch (i) { case 0: return(datum.Quaternion.X); case 1: return(datum.Quaternion.Y); case 2: return(datum.Quaternion.Z); case 3: return(datum.Quaternion.W); default: throw new InvalidOperationException(); } break; default: throw new NotImplementedException(); } }
private static void UpdateDatum(ref W3dAnimationChannelDatum datum, float value, W3dAnimationChannelType type, int i = 0) { if (i > 0 && type != W3dAnimationChannelType.Quaternion) { throw new InvalidDataException(); } switch (type) { case W3dAnimationChannelType.TranslationX: case W3dAnimationChannelType.TranslationY: case W3dAnimationChannelType.TranslationZ: case W3dAnimationChannelType.XR: case W3dAnimationChannelType.YR: case W3dAnimationChannelType.ZR: case W3dAnimationChannelType.UnknownBfme: datum.FloatValue = value; break; case W3dAnimationChannelType.Quaternion: switch (i) { case 0: datum.Quaternion.X = value; break; case 1: datum.Quaternion.Y = value; break; case 2: datum.Quaternion.Z = value; break; case 3: datum.Quaternion.W = value; break; } break; } }
public static W3dTimeCodedAnimationChannel Parse(BinaryReader reader) { var startPosition = reader.BaseStream.Position; var result = new W3dTimeCodedAnimationChannel { NumTimeCodes = reader.ReadUInt32(), Pivot = reader.ReadUInt16(), VectorLength = reader.ReadByte(), ChannelType = (W3dAnimationChannelType)reader.ReadByte() }; W3dAnimationChannel.ValidateChannelDataSize(result.ChannelType, result.VectorLength); var data = new W3dTimeCodedDatum[result.NumTimeCodes]; for (var i = 0; i < result.NumTimeCodes; i++) { var datum = new W3dTimeCodedDatum(); datum.TimeCode = reader.ReadUInt32(); // MSB is used to indicate a binary (non interpolated) movement if ((datum.TimeCode >> 31) == 1) { // TODO: non-interpolated movement. datum.TimeCode &= ~(1 << 31); } datum.Value = W3dAnimationChannelDatum.Parse(reader, result.ChannelType); data[i] = datum; } result.Data = data; return(result); }
internal static W3dAdaptiveDeltaData Parse( BinaryReader reader, uint numFrames, W3dAnimationChannelType type, int vectorLength, W3dAdaptiveDeltaBitCount bitCount) { var count = (numFrames + 15) >> 4; // First read all initial values var result = new W3dAdaptiveDeltaData { BitCount = bitCount, VectorLength = vectorLength, InitialDatum = W3dAnimationChannelDatum.Parse(reader, type) }; var numBits = (int)bitCount; // Then read the interleaved delta blocks var deltaBlocks = new W3dAdaptiveDeltaBlock[count * vectorLength]; for (var i = 0; i < count; i++) { for (var j = 0; j < vectorLength; j++) { deltaBlocks[(i * vectorLength) + j] = W3dAdaptiveDeltaBlock.Parse( reader, j, numBits); } } result.DeltaBlocks = deltaBlocks; return(result); }