/** * Uses {@link #getTrackTime()} to compute the <code>animationTime</code>, which is between * {@link #getAnimationStart()} and {@link #getAnimationEnd()}. When the <code>trackTime</code> * is 0, the <code>animationTime</code> is equal to the <code>animationStart</code> time. */ public float getAnimationTime() { if (loop) { float duration = animationEnd - animationStart; if (duration == 0) return animationStart; return (trackTime % duration) + animationStart; } return Math.min(trackTime + animationStart, animationEnd); }
private void setCurrent(int index, TrackEntry current, boolean interrupt) { TrackEntry from = expandToIndex(index); tracks.set(index, current); if (from != null) { if (interrupt) queue.interrupt(from); current.mixingFrom = from; current.mixTime = 0; from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in. // If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero. if (from.mixingFrom != null && from.mixDuration > 0) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1); } queue.start(current); }
private void applyRotateTimeline( Timeline timeline, Skeleton skeleton, float time, float alpha, boolean setupPose, float[] timelinesRotation, int i, boolean firstFrame) { if (firstFrame) timelinesRotation[i] = 0; if (alpha == 1) { timeline.apply(skeleton, 0, time, null, 1, setupPose, false); return; } RotateTimeline rotateTimeline = (RotateTimeline) timeline; Bone bone = skeleton.bones.get(rotateTimeline.boneIndex); float[] frames = rotateTimeline.frames; if (time < frames[0]) { // Time is before first frame. if (setupPose) bone.rotation = bone.data.rotation; return; } float r2; if (time >= frames[frames.length - ENTRIES]) // Time is after last frame. r2 = bone.data.rotation + frames[frames.length + PREV_ROTATION]; else { // Interpolate between the previous frame and the current frame. int frame = Animation.binarySearch(frames, time, ENTRIES); float prevRotation = frames[frame + PREV_ROTATION]; float frameTime = frames[frame]; float percent = rotateTimeline.getCurvePercent( (frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); r2 = frames[frame + ROTATION] - prevRotation; r2 -= (16384 - (int) (16384.499999999996 - r2 / 360)) * 360; r2 = prevRotation + r2 * percent + bone.data.rotation; r2 -= (16384 - (int) (16384.499999999996 - r2 / 360)) * 360; } // Mix between rotations using the direction of the shortest route on the first frame while // detecting crosses. float r1 = setupPose ? bone.data.rotation : bone.rotation; float total, diff = r2 - r1; if (diff == 0) total = timelinesRotation[i]; else { diff -= (16384 - (int) (16384.499999999996 - diff / 360)) * 360; float lastTotal, lastDiff; if (firstFrame) { lastTotal = 0; lastDiff = diff; } else { lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops. lastDiff = timelinesRotation[i + 1]; // Difference between bones. } boolean current = diff > 0, dir = lastTotal >= 0; // Detect cross at 0 (not 180). if (Math.signum(lastDiff) != Math.signum(diff) && Math.abs(lastDiff) <= 90) { // A cross after a 360 rotation is a loop. if (Math.abs(lastTotal) > 180) lastTotal += 360 * Math.signum(lastTotal); dir = current; } total = diff + lastTotal - lastTotal % 360; // Store loops as part of lastTotal. if (dir != current) total += 360 * Math.signum(lastTotal); timelinesRotation[i] = total; } timelinesRotation[i + 1] = diff; r1 += total * alpha; bone.rotation = r1 - (16384 - (int) (16384.499999999996 - r1 / 360)) * 360; }