/// <summary>
        /// Advance all attached animations by a given amount of time.
        /// </summary>
        /// <param name="dt">How much to advance animations by.</param>
        public void Advance(float dt)
        {
            dirty_ = true;
            try
            {
                unchecked
                {
                    //  update transitions
                    for (int ti = 0, tn = transitions_.Count; ti != tn; ++ti)
                    {
                        if (transitions_[ti].Update(dt))
                        {
                            transitions_.RemoveAt(ti);
                            --ti;
                            --tn;
                        }
                    }

                    inAdvance_ = true;
                    //  update blends
                    float runningWeight = 0;
                    for (int bi = 0, bn = blendedAnimations_.Count; bi != bn; ++bi)
                    {
                        BlendedAnimation ba = blendedAnimations_[bi];
                        ba.Instance.Advance(dt);
                        float wt = ba.Weight;
                        if (wt == 0)
                        {
                            continue;
                        }
                        Keyframe[] kfs = ba.Instance.CurrentPose;
                        if (runningWeight == 0)
                        {
                            runningWeight = Math.Abs(wt);
                            for (int i = 0, n = Math.Min(kfs.Length, keyframes_.Length); i != n; ++i)
                            {
                                Keyframe k = kfs[i];
                                if (k != null)
                                {
                                    keyframes_[i].CopyFrom(k);
                                }
                            }
                        }
                        else
                        {
                            runningWeight += Math.Abs(wt);
                            float t = wt / runningWeight;
                            for (int i = 0, n = Math.Min(kfs.Length, keyframes_.Length); i != n; ++i)
                            {
                                Keyframe k = kfs[i];
                                Keyframe d = keyframes_[i];
                                if (k != null)
                                {
                                    Keyframe.Interpolate(d, k, wt, d);
                                }
                            }
                        }
                    }

                    //  update composes
                    //  TODO: sort from smallest to biggest weight?
                    for (int ci = 0, cn = composedAnimations_.Count; ci != cn; ++ci)
                    {
                        BlendedAnimation ca = composedAnimations_[ci];
                        ca.Instance.Advance(dt);
                        float w = ca.Weight;
                        if (w == 0)
                        {
                            continue;
                        }
                        Keyframe[] kfs = ca.Instance.CurrentPose;
                        for (int i = 0, n = Math.Min(kfs.Length, keyframes_.Length); i != n; ++i)
                        {
                            Keyframe k = kfs[i];
                            Keyframe d = keyframes_[i];
                            if (k != null)
                            {
                                Keyframe.Compose(d, k, w, workItem_);
                                d.CopyFrom(workItem_);
                            }
                        }
                    }
                }
            }
            finally
            {
                inAdvance_ = false;
            }
        }
        //  Internally, calculate all the keyframe values for a given time value.
        void CalculateKeyframes()
        {
            appliedTime_ = time_;
            float fracOrig;
            int   frame;

            //  figure out which keyframe index it should be
            FrameFromTime(time_, out frame, out fracOrig);
            unchecked
            {
                for (int i = 0, n = tracks_.Length; i != n; ++i)
                {
                    Keyframe kf = keyframes_[i];
                    if (kf != null)
                    {
                        //  if I'm animating this bone
                        Keyframe[] kfs = tracks_[i].Keyframes;
                        //  now, find the matching begin/end frames
                        int f1    = frame;
                        int f2    = frame + 1;
                        int nprev = 0;
                        int npost = 0;
                        //  wrap onto the available frames (the last frame may not be at the end?)
                        if (f1 >= kfs.Length)
                        {
                            nprev = (f1 - kfs.Length + 1);
                            f1    = kfs.Length - 1;
                        }
                        if (f2 >= kfs.Length)
                        {
                            npost = f2 - kfs.Length;
                            f2    = 0;
                        }
                        //  find the bracketing keyframes, because frame data is sparse
                        while (kfs[f1] == null)
                        {
                            //  first and last slots always have keyframes
                            System.Diagnostics.Debug.Assert(f1 > 0 && f1 != kfs.Length - 1);
                            --f1;
                            ++nprev;
                        }
                        //  If I'm not looping, I don't want to blend with the 0 frame
                        if (!looping_ && f2 == 0)
                        {
                            f2 = kfs.Length - 1;
                        }
                        while (kfs[f2] == null)
                        {
                            //  first and last slots always have keyframes
                            System.Diagnostics.Debug.Assert(f2 < kfs.Length - 1 && f2 != 0);
                            ++f2;
                            ++npost;
                        }
                        //  adjust "frac" to be interpolation between f1 and f2 frames
                        float frac = fracOrig;
                        if (nprev != 0 || npost != 0)
                        {
                            frac = (nprev + frac) / (nprev + npost + 1);
                        }
                        //  actually extract the appropriate animation value
                        Keyframe.Interpolate(kfs[f1], kfs[f2], frac, keyframes_[i]);
                    }
                }
            }
        }