/// <summary> /// Gets the rounded up frame relative to the given Key Frame. /// </summary> /// <param name="keyFrames">List with the Key Frames</param> /// <param name="frame">The frame number used as reference</param> /// <returns></returns> public static RenderBase.OAnimationKeyFrame getRightFrame(List <RenderBase.OAnimationKeyFrame> keyFrames, float frame) { if (keyFrames == null || keyFrames.Count == 0) { return(null); } RenderBase.OAnimationKeyFrame value = keyFrames[keyFrames.Count - 1]; foreach (RenderBase.OAnimationKeyFrame key in keyFrames) { if (key.frame <= value.frame && key.frame >= frame) { value = key; } } return(value); }
/// <summary> /// Interpolates a point between two Key Frames on a given Frame using Hermite Interpolation. /// </summary> /// <param name="keyFrames">The list with all available Key Frames (Hermite format)</param> /// <param name="frame">The frame number that should be interpolated</param> /// <returns>The interpolated frame value</returns> public static float interpolateHermite(List <RenderBase.OAnimationKeyFrame> keyFrames, float frame) { RenderBase.OAnimationKeyFrame a = getLeftFrame(keyFrames, frame); RenderBase.OAnimationKeyFrame b = getRightFrame(keyFrames, frame); if (a.frame == b.frame) { return(a.value); } float outSlope = a.outSlope; float inSlope = b.inSlope; float distance = frame - a.frame; float invDuration = 1f / (b.frame - a.frame); float t = distance * invDuration; float t1 = t - 1f; return((a.value + ((((a.value - b.value) * ((2f * t) - 3f)) * t) * t)) + ((distance * t1) * ((t1 * outSlope) + (t * inSlope)))); }
private static void addFrame( RenderBase.OSkeletalAnimationBone bone, bool mul2, int axis, float val, float frame = 0, float slope = 0) { RenderBase.OAnimationKeyFrame frm = new RenderBase.OAnimationKeyFrame(); if (mul2) { val *= 2; } frm.frame = frame; frm.inSlope = slope; frm.outSlope = slope; frm.value = val; switch (axis) { case 0: bone.scaleX.keyFrames.Add(frm); break; case 1: bone.scaleY.keyFrames.Add(frm); break; case 2: bone.scaleZ.keyFrames.Add(frm); break; case 3: bone.rotationX.keyFrames.Add(frm); break; case 4: bone.rotationY.keyFrames.Add(frm); break; case 5: bone.rotationZ.keyFrames.Add(frm); break; case 6: bone.translationX.keyFrames.Add(frm); break; case 7: bone.translationY.keyFrames.Add(frm); break; case 8: bone.translationZ.keyFrames.Add(frm); break; } }
/// <summary> /// Gets an Animation Key frame from the CGFX file. /// The Reader position must be set to the beggining of the Key Frame Data. /// </summary> /// <param name="input">The CGFX file Reader</param> /// <param name="header">The CGFX file header</param> /// <returns></returns> private static void getAnimationKeyFrame(BinaryReader input, RenderBase.OAnimationKeyFrameGroup frame) { float startFrame = input.ReadSingle(); float endFrame = input.ReadSingle(); input.BaseStream.Seek(0x10, SeekOrigin.Current); frame.startFrame = input.ReadSingle(); frame.endFrame = input.ReadSingle(); uint segmentFlags = input.ReadUInt32(); switch (segmentFlags & 0xf) { case 0: frame.interpolation = RenderBase.OInterpolationMode.step; break; case 4: frame.interpolation = RenderBase.OInterpolationMode.linear; break; case 8: frame.interpolation = RenderBase.OInterpolationMode.hermite; break; } RenderBase.OSegmentQuantization quantization = (RenderBase.OSegmentQuantization)(segmentFlags >> 5); uint entries = input.ReadUInt32(); float invDuration = input.ReadSingle(); float valueScale = 1; float valueOffset = 0; float frameScale = 1; if (quantization != RenderBase.OSegmentQuantization.hermite128 && quantization != RenderBase.OSegmentQuantization.unifiedHermite96 && quantization != RenderBase.OSegmentQuantization.stepLinear64) { valueScale = input.ReadSingle(); valueOffset = input.ReadSingle(); frameScale = input.ReadSingle(); } for (int key = 0; key < entries; key++) { RenderBase.OAnimationKeyFrame keyFrame = new RenderBase.OAnimationKeyFrame(); switch (quantization) { case RenderBase.OSegmentQuantization.hermite128: keyFrame.frame = input.ReadSingle(); keyFrame.value = input.ReadSingle(); keyFrame.inSlope = input.ReadSingle(); keyFrame.outSlope = input.ReadSingle(); break; case RenderBase.OSegmentQuantization.hermite64: uint h64Value = input.ReadUInt32(); keyFrame.frame = h64Value & 0xfff; keyFrame.value = h64Value >> 12; keyFrame.inSlope = input.ReadInt16() / 256f; keyFrame.outSlope = input.ReadInt16() / 256f; break; case RenderBase.OSegmentQuantization.hermite48: keyFrame.frame = input.ReadByte(); keyFrame.value = input.ReadUInt16(); byte slope0 = input.ReadByte(); byte slope1 = input.ReadByte(); byte slope2 = input.ReadByte(); keyFrame.inSlope = IOUtils.signExtend(slope0 | ((slope1 & 0xf) << 8), 12) / 32f; keyFrame.outSlope = IOUtils.signExtend((slope1 >> 4) | (slope2 << 4), 12) / 32f; break; case RenderBase.OSegmentQuantization.unifiedHermite96: keyFrame.frame = input.ReadSingle(); keyFrame.value = input.ReadSingle(); keyFrame.inSlope = input.ReadSingle(); keyFrame.outSlope = keyFrame.inSlope; break; case RenderBase.OSegmentQuantization.unifiedHermite48: keyFrame.frame = input.ReadUInt16() / 32f; keyFrame.value = input.ReadUInt16(); keyFrame.inSlope = input.ReadInt16() / 256f; keyFrame.outSlope = keyFrame.inSlope; break; case RenderBase.OSegmentQuantization.unifiedHermite32: keyFrame.frame = input.ReadByte(); ushort uH32Value = input.ReadUInt16(); keyFrame.value = uH32Value & 0xfff; keyFrame.inSlope = IOUtils.signExtend((uH32Value >> 12) | (input.ReadByte() << 4), 12) / 32f; keyFrame.outSlope = keyFrame.inSlope; break; case RenderBase.OSegmentQuantization.stepLinear64: keyFrame.frame = input.ReadSingle(); keyFrame.value = input.ReadSingle(); break; case RenderBase.OSegmentQuantization.stepLinear32: uint sL32Value = input.ReadUInt32(); keyFrame.frame = sL32Value & 0xfff; keyFrame.value = sL32Value >> 12; break; } keyFrame.frame = (keyFrame.frame * frameScale) + startFrame; keyFrame.value = (keyFrame.value * valueScale) + valueOffset; frame.keyFrames.Add(keyFrame); } }
/// <summary> /// Gets an Animation Key frame from the BCH file. /// The Reader position must be set to the beggining of the Key Frame Data. /// </summary> /// <param name="input">The BCH file Reader</param> /// <param name="header">The BCH file header</param> /// <returns></returns> private static void getAnimationKeyFrame(BinaryReader input, RenderBase.OAnimationKeyFrameGroup frame) { frame.startFrame = input.ReadSingle(); frame.endFrame = input.ReadSingle(); uint frameFlags = input.ReadUInt32(); frame.preRepeat = (RenderBase.ORepeatMethod)(frameFlags & 0xf); frame.postRepeat = (RenderBase.ORepeatMethod)((frameFlags >> 8) & 0xf); uint segmentFlags = input.ReadUInt32(); frame.interpolation = (RenderBase.OInterpolationMode)(segmentFlags & 0xf); RenderBase.OSegmentQuantization quantization = (RenderBase.OSegmentQuantization)((segmentFlags >> 8) & 0xff); uint entries = segmentFlags >> 16; float valueScale = input.ReadSingle(); float valueOffset = input.ReadSingle(); float frameScale = input.ReadSingle(); float frameOffset = input.ReadSingle(); uint offset = input.ReadUInt32(); if (offset < input.BaseStream.Length) input.BaseStream.Seek(offset, SeekOrigin.Begin); for (int key = 0; key < entries; key++) { RenderBase.OAnimationKeyFrame keyFrame = new RenderBase.OAnimationKeyFrame(); switch (quantization) { case RenderBase.OSegmentQuantization.hermite128: keyFrame.frame = input.ReadSingle(); keyFrame.value = input.ReadSingle(); keyFrame.inSlope = input.ReadSingle(); keyFrame.outSlope = input.ReadSingle(); break; case RenderBase.OSegmentQuantization.hermite64: uint h64Value = input.ReadUInt32(); keyFrame.frame = h64Value & 0xfff; keyFrame.value = h64Value >> 12; keyFrame.inSlope = input.ReadInt16() / 256f; keyFrame.outSlope = input.ReadInt16() / 256f; break; case RenderBase.OSegmentQuantization.hermite48: keyFrame.frame = input.ReadByte(); keyFrame.value = input.ReadUInt16(); byte slope0 = input.ReadByte(); byte slope1 = input.ReadByte(); byte slope2 = input.ReadByte(); keyFrame.inSlope = IOUtils.signExtend(slope0 | ((slope1 & 0xf) << 8), 12) / 32f; keyFrame.outSlope = IOUtils.signExtend((slope1 >> 4) | (slope2 << 4), 12) / 32f; break; case RenderBase.OSegmentQuantization.unifiedHermite96: keyFrame.frame = input.ReadSingle(); keyFrame.value = input.ReadSingle(); keyFrame.inSlope = input.ReadSingle(); keyFrame.outSlope = keyFrame.inSlope; break; case RenderBase.OSegmentQuantization.unifiedHermite48: keyFrame.frame = input.ReadUInt16() / 32f; keyFrame.value = input.ReadUInt16(); keyFrame.inSlope = input.ReadInt16() / 256f; keyFrame.outSlope = keyFrame.inSlope; break; case RenderBase.OSegmentQuantization.unifiedHermite32: keyFrame.frame = input.ReadByte(); ushort uH32Value = input.ReadUInt16(); keyFrame.value = uH32Value & 0xfff; keyFrame.inSlope = IOUtils.signExtend((uH32Value >> 12) | (input.ReadByte() << 4), 12) / 32f; keyFrame.outSlope = keyFrame.inSlope; break; case RenderBase.OSegmentQuantization.stepLinear64: keyFrame.frame = input.ReadSingle(); keyFrame.value = input.ReadSingle(); break; case RenderBase.OSegmentQuantization.stepLinear32: uint sL32Value = input.ReadUInt32(); keyFrame.frame = sL32Value & 0xfff; keyFrame.value = sL32Value >> 12; break; } keyFrame.frame = (keyFrame.frame * frameScale) + frameOffset; keyFrame.value = (keyFrame.value * valueScale) + valueOffset; frame.keyFrames.Add(keyFrame); } }