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);
            }
        }
Exemple #2
0
 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));
                }
            }
        }
Exemple #4
0
        /// <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 unsafe void Update(ModelViewHierarchyUpdater hierarchy, AnimationClipResult result)
        {
            // Check if we need to regenerate "update channels" (i.e. how to copy data from result to hierarchy)
            if (updateChannels == null // First time?...
                || currentSourceChannels != result.Channels // ... or changed?
                || currentSourceChannels.Count != currentSourceChannelCount) // .. or modified? (could only append channel)
            {
                RegenerateUpdateChannels(hierarchy, result.Channels);
                currentSourceChannels = result.Channels;
                currentSourceChannelCount = currentSourceChannels.Count;
            }

            // Copy results to node hierarchy
            fixed (byte* structures = result.Data)
            {
                foreach (var updateChannel in updateChannels)
                {
                    var structureData = (float*)(structures + updateChannel.Offset);
                    var factor = *structureData++;
                    if (factor == 0.0f)
                        continue;

                    switch (updateChannel.Type)
                    {
                        case ChannelType.Translation:
                            Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Translation);
                            break;
                        case ChannelType.Rotation:
                            Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Rotation);
                            break;
                        case ChannelType.Scaling:
                            Utilities.Read((IntPtr)structureData, ref hierarchy.NodeTransformations[updateChannel.Index].Transform.Scaling);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
            }
        }
Exemple #6
0
        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");
                    }
                }
            }
        }
        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 (curveEvaluatorOptimizedFloat != null)
                {
                    curveEvaluatorOptimizedFloat.Evaluate(newTime, (IntPtr)structures);
                }
                
                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);
            }
        }
        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));
                }
            }
        }
 internal void FreeIntermediateResult(AnimationClipResult result)
 {
     // Returns it to pool of available intermediate results
     lock (availableResultsPool)
     {
         result.Channels = null;
         availableResultsPool.Push(result);
     }
 }
        /// <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");
                    }
                }
            }
        }