} // AddAnimationNodes

        #endregion

        #region Process Root Animation

        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContent
        /// object to our runtime AnimationClip format.
        /// </summary>
        internal static RootAnimationClip ProcessRootAnimation(AnimationContent animation, string name)
        {
            List<RootKeyframe> keyframes = new List<RootKeyframe>();

            // The root animation is controlling the root of the bones
            AnimationChannel channel = animation.Channels[name];
            
            // Add the transformations on the root of the model
            foreach (AnimationKeyframe keyframe in channel)
            {
                keyframes.Add(new RootKeyframe((float)(keyframe.Time.TotalSeconds), keyframe.Transform));
            }            

            // Sort the merged keyframes by time.
            keyframes.Sort(CompareKeyframeTimes);

            #region Key Frame Reduction

            // We drop key frame data where the bone transformation is equal to the previous key frame.
            List<RootKeyframe> keyframesReduced = new List<RootKeyframe>();
            keyframesReduced.Add(keyframes[0]);
            for (int i = 1; i < keyframes.Count; i++)
            {
                if (keyframes[i - 1].Transform != keyframes[i].Transform)
                {
                    keyframesReduced.Add(keyframes[i]);
                }
            }
            keyframes = keyframesReduced;
            // Sort the merged keyframes by time.
            keyframes.Sort(CompareKeyframeTimes);

            #endregion

            if (keyframes.Count == 0)
                throw new InvalidContentException("Animation has no keyframes.");

            if (animation.Duration <= TimeSpan.Zero)
                throw new InvalidContentException("Animation has a zero duration.");

            RootKeyframe[] keyframesArray = new RootKeyframe[keyframes.Count];
            for (int i = 0; i < keyframes.Count; i++)
            {
                keyframesArray[i] = keyframes[i];
            }
            return new RootAnimationClip((float)(animation.Duration.TotalSeconds), keyframesArray);
        } // ProcessRootAnimation
        } // Play

        /// <summary>
        /// Starts playing a clip
        /// </summary>
        /// <param name="name">Animation name</param>
        /// <param name="playbackRate">Speed to playback</param>
        /// <param name="duration">Length of time to play in seconds (max is looping, 0 is once)</param>
        public void Play(string name, float playbackRate, float duration)
        {
            if (!rootAnimations.ContainsKey(name))
            {
                throw new ArgumentException("Root Animation Component: the animation name does not exist.");
            }

            // Store the clip and reset playing data
            currentAnimationClip = rootAnimations[name];
            currentKeyFrameIndex = 0;
            currentKeyFrame      = currentAnimationClip.Keyframes[0];
            CurrentTimeValue     = 0;
            elapsedPlaybackTime  = 0;
            paused = false;

            // Store the data about how we want to playback
            this.playbackRate = playbackRate;
            this.duration     = duration;

            previousAnimationTransform = ((GameObject3D)Owner).Transform.LocalMatrix;
        } // Play
        } // CompareKeyframeTimes

        /// <summary>
        /// Comparison function for sorting keyframes into ascending time order.
        /// </summary>
        static int CompareKeyframeTimes(RootKeyframe a, RootKeyframe b)
        {
            return a.Time.CompareTo(b.Time);
        } // CompareKeyframeTimes