public unsafe void Compute(CompressedTimeSpan newTime, AnimationClipResult result) { fixed(byte *structures = result.Data) { // Update factors for (int index = 0; index < Channels.Count; index++) { // For now, objects are not supported, so treat everything as a blittable struct. var channel = Channels.Items[index]; var structureStart = (float *)(structures + channel.Offset); // Write a float specifying channel factor (1 if exists, 0 if doesn't exist) *structureStart = channel.Factor; } if (curveEvaluatorOptimizedVector3 != null) { curveEvaluatorOptimizedVector3.Evaluate(newTime, (IntPtr)structures); } if (curveEvaluatorOptimizedQuaternion != null) { curveEvaluatorOptimizedQuaternion.Evaluate(newTime, (IntPtr)structures); } // Write interpolated data curveEvaluatorFloat.Evaluate(newTime, (IntPtr)structures); curveEvaluatorVector3.Evaluate(newTime, (IntPtr)structures); curveEvaluatorQuaternion.Evaluate(newTime, (IntPtr)structures); } }
internal void FreeIntermediateResult(AnimationClipResult result) { // Returns it to pool of available intermediate results lock (availableResultsPool) { result.Channels = null; availableResultsPool.Push(result); } }
public unsafe void AddCurveValues(CompressedTimeSpan newTime, AnimationClipResult result) { fixed(byte *structures = result.Data) { for (int index = 0; index < Channels.Count; index++) { var channel = Channels.Items[index]; // For now, objects are not supported, so treat everything as a blittable struct. channel.Curve.AddValue(newTime, (IntPtr)(structures + channel.Offset)); } } }
/// <summary> /// Computes the specified animation operations. /// </summary> /// <param name="animationOperations">The animation operations to perform.</param> /// <param name="result">The optional result (if not null, it expects the final stack to end up with this element).</param> public void Compute(FastList <AnimationOperation> animationOperations, ref AnimationClipResult result) { // Clear animation stack animationStack.Clear(); // Apply first operation (should be a push), directly into result (considered first item in the stack) var animationOperation0 = animationOperations.Items[0]; if (animationOperation0.Type != AnimationOperationType.Push) { throw new InvalidOperationException("First operation should be a push"); } // TODO: Either result is null (should have a Pop operation) or result is non null (stack end up being size 1) var hasResult = result != null; if (hasResult) { // Ensure there is enough size // TODO: Force result allocation to happen on user side? if (result.DataSize < structureSize) { result.DataSize = structureSize; result.Data = new byte[structureSize]; } result.Channels = channels; } else { result = AllocateIntermediateResult(); } animationOperation0.Evaluator.Compute((CompressedTimeSpan)animationOperation0.Time, result); animationStack.Push(result); for (int index = 1; index < animationOperations.Count; index++) { var animationOperation = animationOperations.Items[index]; ApplyAnimationOperation(ref animationOperation); } if (hasResult && (animationStack.Count != 1 || animationStack.Pop() != result)) { throw new InvalidOperationException("Stack should end up with result."); } }
public static unsafe void Blend(AnimationBlendOperation blendOperation, float blendFactor, AnimationClipResult sourceLeft, AnimationClipResult sourceRight, AnimationClipResult result) { fixed(byte *sourceLeftDataStart = sourceLeft.Data) fixed(byte *sourceRightDataStart = sourceRight.Data) fixed(byte *resultDataStart = result.Data) { foreach (var channel in sourceLeft.Channels) { int offset = channel.Offset; var sourceLeftData = (float *)(sourceLeftDataStart + offset); var sourceRightData = (float *)(sourceRightDataStart + offset); var resultData = (float *)(resultDataStart + offset); float factorLeft = *sourceLeftData++; float factorRight = *sourceRightData++; // Ignore this channel if (factorLeft == 0.0f && factorRight == 0.0f) { *resultData++ = 0.0f; continue; } // Use left value if (factorLeft > 0.0f && factorRight == 0.0f) { *resultData++ = 1.0f; Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); continue; } // Use right value if (factorRight > 0.0f && factorLeft == 0.0f) { *resultData++ = 1.0f; Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceRightData, channel.Size); continue; } // Blending *resultData++ = 1.0f; switch (blendOperation) { case AnimationBlendOperation.LinearBlend: // Perform linear blending // It will blend between left (0.0) and right (1.0) switch (channel.BlendType) { case BlendType.None: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2.Lerp(ref *(Vector2 *)sourceLeftData, ref *(Vector2 *)sourceRightData, blendFactor, out *(Vector2 *)resultData); break; case BlendType.Float3: Vector3.Lerp(ref *(Vector3 *)sourceLeftData, ref *(Vector3 *)sourceRightData, blendFactor, out *(Vector3 *)resultData); break; case BlendType.Quaternion: Quaternion.Slerp(ref *(Quaternion *)sourceLeftData, ref *(Quaternion *)sourceRightData, blendFactor, out *(Quaternion *)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; case AnimationBlendOperation.Add: // Perform additive blending // It will blend between left (0.0) and left + right (1.0). switch (channel.BlendType) { case BlendType.None: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2 rightValue2; Vector2.Add(ref *(Vector2 *)sourceLeftData, ref *(Vector2 *)sourceRightData, out rightValue2); Vector2.Lerp(ref *(Vector2 *)sourceLeftData, ref rightValue2, blendFactor, out *(Vector2 *)resultData); break; case BlendType.Float3: Vector3 rightValue3; Vector3.Add(ref *(Vector3 *)sourceLeftData, ref *(Vector3 *)sourceRightData, out rightValue3); Vector3.Lerp(ref *(Vector3 *)sourceLeftData, ref rightValue3, blendFactor, out *(Vector3 *)resultData); break; case BlendType.Quaternion: Quaternion rightValueQ; Quaternion.Multiply(ref *(Quaternion *)sourceLeftData, ref *(Quaternion *)sourceRightData, out rightValueQ); Quaternion.Normalize(ref rightValueQ, out rightValueQ); Quaternion.Slerp(ref *(Quaternion *)sourceLeftData, ref rightValueQ, blendFactor, out *(Quaternion *)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; case AnimationBlendOperation.Subtract: // Perform subtractive blending // It will blend between left (0.0) and left - right (1.0). switch (channel.BlendType) { case BlendType.None: Utilities.CopyMemory((IntPtr)resultData, (IntPtr)sourceLeftData, channel.Size); break; case BlendType.Float2: Vector2 rightValue2; Vector2.Subtract(ref *(Vector2 *)sourceLeftData, ref *(Vector2 *)sourceRightData, out rightValue2); Vector2.Lerp(ref *(Vector2 *)sourceLeftData, ref rightValue2, blendFactor, out *(Vector2 *)resultData); break; case BlendType.Float3: Vector3 rightValue3; Vector3.Subtract(ref *(Vector3 *)sourceLeftData, ref *(Vector3 *)sourceRightData, out rightValue3); Vector3.Lerp(ref *(Vector3 *)sourceLeftData, ref rightValue3, blendFactor, out *(Vector3 *)resultData); break; case BlendType.Quaternion: Quaternion rightValueQ; // blend between left (0.0) and left * conjugate(right) (1.0) Quaternion.Invert(ref *(Quaternion *)sourceRightData, out rightValueQ); Quaternion.Multiply(ref rightValueQ, ref *(Quaternion *)sourceLeftData, out rightValueQ); Quaternion.Normalize(ref rightValueQ, out rightValueQ); //throw new NotImplementedException(); Quaternion.Slerp(ref *(Quaternion *)sourceLeftData, ref rightValueQ, blendFactor, out *(Quaternion *)resultData); break; default: throw new ArgumentOutOfRangeException(); } break; default: throw new ArgumentOutOfRangeException("blendOperation"); } } } }