michael@0: michael@0: /* michael@0: * Copyright 2010 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: michael@0: #include "FlingState.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkTime.h" michael@0: michael@0: #define DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER true michael@0: michael@0: static const float MAX_FLING_SPEED = 1500; michael@0: michael@0: static float pin_max_fling(float speed) { michael@0: if (speed > MAX_FLING_SPEED) { michael@0: speed = MAX_FLING_SPEED; michael@0: } michael@0: return speed; michael@0: } michael@0: michael@0: static double getseconds() { michael@0: return SkTime::GetMSecs() * 0.001; michael@0: } michael@0: michael@0: // returns +1 or -1, depending on the sign of x michael@0: // returns +1 if x is zero michael@0: static SkScalar SkScalarSign(SkScalar x) { michael@0: SkScalar sign = SK_Scalar1; michael@0: if (x < 0) { michael@0: sign = -sign; michael@0: } michael@0: return sign; michael@0: } michael@0: michael@0: static void unit_axis_align(SkVector* unit) { michael@0: const SkScalar TOLERANCE = SkDoubleToScalar(0.15); michael@0: if (SkScalarAbs(unit->fX) < TOLERANCE) { michael@0: unit->fX = 0; michael@0: unit->fY = SkScalarSign(unit->fY); michael@0: } else if (SkScalarAbs(unit->fY) < TOLERANCE) { michael@0: unit->fX = SkScalarSign(unit->fX); michael@0: unit->fY = 0; michael@0: } michael@0: } michael@0: michael@0: void FlingState::reset(float sx, float sy) { michael@0: fActive = true; michael@0: fDirection.set(sx, sy); michael@0: fSpeed0 = SkPoint::Normalize(&fDirection); michael@0: fSpeed0 = pin_max_fling(fSpeed0); michael@0: fTime0 = getseconds(); michael@0: michael@0: unit_axis_align(&fDirection); michael@0: // printf("---- speed %g dir %g %g\n", fSpeed0, fDirection.fX, fDirection.fY); michael@0: } michael@0: michael@0: bool FlingState::evaluateMatrix(SkMatrix* matrix) { michael@0: if (!fActive) { michael@0: return false; michael@0: } michael@0: michael@0: const float t = getseconds() - fTime0; michael@0: const float MIN_SPEED = 2; michael@0: const float K0 = 5.0; michael@0: const float K1 = 0.02; michael@0: const float speed = fSpeed0 * (sk_float_exp(- K0 * t) - K1); michael@0: if (speed <= MIN_SPEED) { michael@0: fActive = false; michael@0: return false; michael@0: } michael@0: float dist = (fSpeed0 - speed) / K0; michael@0: michael@0: // printf("---- time %g speed %g dist %g\n", t, speed, dist); michael@0: float tx = fDirection.fX * dist; michael@0: float ty = fDirection.fY * dist; michael@0: if (DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER) { michael@0: tx = sk_float_round2int(tx); michael@0: ty = sk_float_round2int(ty); michael@0: } michael@0: matrix->setTranslate(tx, ty); michael@0: // printf("---- evaluate (%g %g)\n", tx, ty); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: //////////////////////////////////////// michael@0: michael@0: GrAnimateFloat::GrAnimateFloat() : fTime0(0) {} michael@0: michael@0: void GrAnimateFloat::start(float v0, float v1, float duration) { michael@0: fValue0 = v0; michael@0: fValue1 = v1; michael@0: fDuration = duration; michael@0: if (duration > 0) { michael@0: fTime0 = SkTime::GetMSecs(); michael@0: if (!fTime0) { michael@0: fTime0 = 1; // time0 is our sentinel michael@0: } michael@0: } else { michael@0: fTime0 = 0; michael@0: } michael@0: } michael@0: michael@0: float GrAnimateFloat::evaluate() { michael@0: if (!fTime0) { michael@0: return fValue1; michael@0: } michael@0: michael@0: double elapsed = (SkTime::GetMSecs() - fTime0) * 0.001; michael@0: if (elapsed >= fDuration) { michael@0: fTime0 = 0; michael@0: return fValue1; michael@0: } michael@0: michael@0: double t = elapsed / fDuration; michael@0: if (true) { michael@0: t = (3 - 2 * t) * t * t; michael@0: } michael@0: return fValue0 + t * (fValue1 - fValue0); michael@0: }