Error in KeyframeController

I think there's an error in KeyframeController, let me explain: when repeatType = RT_WRAP and curTime > getMaxTime(), wrapping is performed by resetting time to getMinTime()-1 in order to search next frame. I think this is incorrect because I expect wrapping to work in such a way that jumping over getMaxTime() takes me to curTime = getMinTime() + ( curTime - getMaxTime() ) which is a truly "circular" behavior.



The same applies to the case wher curTime < getMinTime(), which takes me to another problem: it is possible to have getMinTime() > getMaxTime()  (making all RT_WRAP tests to behave strangely) by calling setNewAnimationTimes with newBeginTime being greater than newEndTime, I don't know what this is allowed, but I think that in addition to set movingForward = false it is necessary to set maxTime and minTime with newBeginTime and newEndTime respectively. The attached code fixes both problems:



Note: I think that something similar applies when having repeatType = RT_CYCLE, but I have not the time to fix it right now.



[pre]

    /

    * Sets the new animation boundaries for this controller. This will start at

    * newBeginTime and proceed in the direction of newEndTime (either forwards

    * or backwards). If both are the same, then the animation is set to their

    * time and turned off, otherwise the animation is turned on to start the

    * animation acording to the repeat type. If either BeginTime or EndTime are

    * invalid times (less than 0 or greater than the maximum set keyframe time)

    * then a warning is set and nothing happens. <br>

    * It is suggested that this function be called if new animation boundaries

    * need to be set, instead of setMinTime and setMaxTime directly.

    *

    * @param newBeginTime

    *            The starting time

    * @param newEndTime

    *            The ending time

    */

    public void setNewAnimationTimes(float newBeginTime, float newEndTime) {

        if (isSmooth) return;

        if (newBeginTime < 0

                || newBeginTime > ((PointInTime) keyframes

                        .get(keyframes.size() - 1)).time) {

            LoggingSystem.getLogger().log(Level.WARNING,

                    "Attempt to set invalid begintime:" + newBeginTime);

            return;

        }

        if (newEndTime < 0

                || newEndTime > ((PointInTime) keyframes

                        .get(keyframes.size() - 1)).time) {

            LoggingSystem.getLogger().log(Level.WARNING,

                    "Attempt to set invalid endtime:" + newEndTime);

            return;

        }

        if ( newBeginTime > newEndTime ) {

            setMinTime(newEndTime);

            setMaxTime(newBeginTime);

            movingForward = false;

            curTime = newEndTime;

        } else {

            setMinTime(newBeginTime);

            setMaxTime(newEndTime);

            movingForward = true;

            curTime = newBeginTime;

        }

        if (newBeginTime == newEndTime) {

            update(0);

            setActive(false);

        } else

            setActive(true);

    }



    /


    * This is used by update(float). It calculates PointInTime

    * <code>before</code> and <code>after</code> as well as makes

    * adjustments on what to do when <code>curTime</code> is beyond the

    * MinTime and MaxTime bounds

    */

    private void findFrame() {

    // If we're in our special wrapping case then just ignore changing

    // frames. Once we get back into the actual series we'll revert back

    // to the normal process

    if ((curTime < getMinTime()) && (nextFrame < curFrame)) {

    return;

    }

   

    // Update the rest to maintain our new nextFrame marker as one infront

    // of the curFrame in all cases. The wrap case is where the real work

    // is done.

        if (curTime > this.getMaxTime()) {

            if (isSmooth) {

                swapKeyframeSets();

                isSmooth = false;

                curTime = tempNewBeginTime;

                curFrame = 0;

                nextFrame = 1;

                setNewAnimationTimes(tempNewBeginTime, tempNewEndTime);

                return;

            }

            if (this.getRepeatType() == Controller.RT_WRAP) {

                float delta = curTime - this.getMaxTime();

                curTime = this.getMinTime() + delta;

               

                for (curFrame = 0; curFrame < keyframes.size() - 1; curFrame++) {

                    if (curTime <= ((PointInTime) keyframes.get(curFrame)).time)

                            break;

                }

                curFrame–;

                return;

            } else if (this.getRepeatType() == Controller.RT_CLAMP) {

                return;

            } else { // Then assume it's RT_CYCLE

                movingForward = false;

                curTime = this.getMaxTime();

            }

        } else if (curTime < this.getMinTime()) {

            if (this.getRepeatType() == Controller.RT_WRAP) {

                float delta = this.getMinTime() - curTime;

                curTime = this.getMaxTime() - delta;

                curFrame = 0;

            } else if (this.getRepeatType() == Controller.RT_CLAMP) {

                return;

            } else { // Then assume it's RT_CYCLE

                movingForward = true;

                curTime = this.getMinTime();

            }

        }



    nextFrame = curFrame+1;

   

        if (curTime > ((PointInTime) keyframes.get(curFrame)).time) {

            if (curTime < ((PointInTime) keyframes.get(curFrame + 1)).time) {

            nextFrame = curFrame+1;

                return;

            }

            else {

                for (; curFrame < keyframes.size() - 1; curFrame++) {

                    if (curTime <= ((PointInTime) keyframes.get(curFrame + 1)).time) {

                    nextFrame = curFrame+1;

                            return;

                    }

                }

                // This -should- be unreachable because of the above

                curTime = this.getMinTime();

                curFrame = 0;

            nextFrame = curFrame+1;

                return;

            }

        } else {

            for (; curFrame >= 0; curFrame–) {

                if (curTime >= ((PointInTime) keyframes.get(curFrame)).time) {

                nextFrame = curFrame+1;

                return;

                }

            }

            // This should be unreachable because curTime>=0 and

            // keyframes[0].time=0;

            curFrame = 0;

        nextFrame = curFrame+1;

            return;

        }

    }



[/pre]

Should be fixed, use KeyframeController.setBlendTime(0)