CPAnimation: cubic bezier curves - the real, working equation

Conflicts:

	AppKit/CPAnimation.j
This commit is contained in:
Ross Boucher
2009-10-08 13:20:10 -07:00
parent 1fb9c973fe
commit 9b948dcac7
2 changed files with 41 additions and 7 deletions
+39 -5
View File
@@ -300,13 +300,47 @@ ACTUAL_FRAME_RATE = 0;
*/
- (float)currentValue
{
var t = [self currentProgress];
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
return [_delegate animation:self valueForProgress:_progress];
return [_delegate animation:self valueForProgress:t];
if (_animationCurve == CPAnimationLinear)
return _progress;
alert("IMPLEMENT ANIMATION CURVES!!!");
var c1 = [],
c2 = [];
[_timingFunction getControlPointAtIndex:1 values:c1];
[_timingFunction getControlPointAtIndex:2 values:c2];
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
}
@end
// currently used function to determine time
// 1:1 conversion to js from webkit source files
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
{
var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
// The epsilon value to pass given that the animation is going to run over |duration| seconds. The longer the animation, the more precision is needed in the timing function result to avoid ugly discontinuities.
function solveEpsilon(duration) {return 1.0/(200.0*duration);};
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
// Given an x value, find a parametric value it came from.
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
// First try a few iterations of Newton's method -- normally very fast.
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
// Fall back to the bisection method for reliability.
t0=0.0; t1=1.0; t2=x; if(t2<t0) {return t0;} if(t2>t1) {return t1;}
while(t0<t1) {x2=sampleCurveX(t2); if(fabs(x2-x)<epsilon) {return t2;} if(x>x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
return t2; // Failure.
};
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
// Convert from input time to parametric value in curve, then from that to output time.
return solve(t, solveEpsilon(duration));
};
+2 -2
View File
@@ -1787,7 +1787,7 @@ CPTexturedBackgroundWindowMask
[aSheet setFrame:startFrame];
_sheetContext["opened"] = YES;
[aSheet _setFrame:endFrame delegate:self duration:0.3 curve:CPAnimationEaseOut];
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
// Should run the main loop here until _isAnimating = FALSE
[aSheet becomeKeyWindow];
@@ -1808,7 +1808,7 @@ CPTexturedBackgroundWindowMask
[self _setUpMasksForView:sheetContent];
_sheetContext["opened"] = NO;
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationLinear];
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn];
}
/* @ignore */