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 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); }
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); }