2015-02-02 20:55:02 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkScalar.h"
|
|
|
|
#include "include/core/SkTime.h"
|
2015-02-02 20:55:02 +00:00
|
|
|
|
2019-03-20 16:55:08 +00:00
|
|
|
#ifndef AnimTimer_DEFINED
|
|
|
|
#define AnimTimer_DEFINED
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
/**
|
2019-01-10 16:27:34 +00:00
|
|
|
* Class to track a "timer". It supports 3 states: stopped, paused, and running.
|
|
|
|
* Playback speed is variable.
|
2015-02-02 20:55:02 +00:00
|
|
|
*
|
|
|
|
* The caller must call updateTime() to resync with the clock (typically just before
|
|
|
|
* using the timer). Forcing the caller to do this ensures that the timer's return values
|
|
|
|
* are consistent if called repeatedly, as they only reflect the time since the last
|
|
|
|
* calle to updateTimer().
|
|
|
|
*/
|
2019-03-20 16:55:08 +00:00
|
|
|
class AnimTimer {
|
2015-02-02 20:55:02 +00:00
|
|
|
public:
|
2019-03-20 16:55:08 +00:00
|
|
|
enum State { kStopped_State, kPaused_State, kRunning_State };
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class begins in the "stopped" state.
|
|
|
|
*/
|
2019-03-20 16:55:08 +00:00
|
|
|
AnimTimer() : fPreviousNanos(0), fElapsedNanos(0), fSpeed(1), fState(kStopped_State) {}
|
2015-02-02 20:55:02 +00:00
|
|
|
|
2019-03-20 16:55:08 +00:00
|
|
|
AnimTimer(double elapsed)
|
|
|
|
: fPreviousNanos(0), fElapsedNanos(elapsed), fSpeed(1), fState(kRunning_State) {}
|
2018-02-15 23:40:48 +00:00
|
|
|
|
2015-02-02 20:55:02 +00:00
|
|
|
bool isStopped() const { return kStopped_State == fState; }
|
|
|
|
bool isRunning() const { return kRunning_State == fState; }
|
|
|
|
bool isPaused() const { return kPaused_State == fState; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stops the timer, and resets it, such that the next call to run or togglePauseResume
|
|
|
|
* will begin at time 0.
|
|
|
|
*/
|
2019-03-20 16:55:08 +00:00
|
|
|
void stop() { this->setState(kStopped_State); }
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* If the timer is paused or stopped, it will resume (or start if it was stopped).
|
|
|
|
*/
|
2019-03-20 16:55:08 +00:00
|
|
|
void run() { this->setState(kRunning_State); }
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
/**
|
2019-01-10 16:27:34 +00:00
|
|
|
* Control the rate at which time advances.
|
|
|
|
*/
|
|
|
|
float getSpeed() const { return fSpeed; }
|
2019-03-20 16:55:08 +00:00
|
|
|
void setSpeed(float speed) { fSpeed = speed; }
|
2019-01-10 16:27:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* If the timer is stopped, start running, else it toggles between paused and running.
|
2015-02-02 20:55:02 +00:00
|
|
|
*/
|
|
|
|
void togglePauseResume() {
|
|
|
|
if (kRunning_State == fState) {
|
|
|
|
this->setState(kPaused_State);
|
|
|
|
} else {
|
|
|
|
this->setState(kRunning_State);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Call this each time you want to sample the clock for the timer. This is NOT done
|
|
|
|
* automatically, so that repeated calls to msec() or secs() will always return the
|
|
|
|
* same value.
|
|
|
|
*
|
|
|
|
* This may safely be called with the timer in any state.
|
|
|
|
*/
|
|
|
|
void updateTime() {
|
|
|
|
if (kRunning_State == fState) {
|
2019-01-10 16:27:34 +00:00
|
|
|
double now = SkTime::GetNSecs();
|
|
|
|
fElapsedNanos += (now - fPreviousNanos) * fSpeed;
|
|
|
|
fPreviousNanos = now;
|
2015-02-02 20:55:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the time in milliseconds the timer has been in the running state.
|
Change SkTime::GetMSecs to double; ensure values stored in SkMSec do not overflow.
The following are currently unused in Android, Google3, Chromium, and Mozilla:
- SkEvent
- SkTime::GetMSecs
- SK_TIME_FACTOR (also unused in Skia)
- SkAutoTime
I left uses of SkMSec more-or-less intact for SkEvent, SkAnimator, and SkInterpolator. SkInterpolator is used in Chromium, so I did not want to change the API. The views/ and animator/ code is crufty, so it didn't seem worthwhile to refactor it. Instead, I added SkEvent::GetMSecsSinceStartup, which is likely to be adequate for use in SampleApp.
I also left SkMSec where it is used to measure a duration rather than a timestamp. With the exception of SkMovie, which is used in Android, all of the uses appear to measure the execution time of a piece of code, which I would hope does not exceed 2^31 milliseconds.
Added skiatest::Timer to support a common idiom in tests where we want to measure the wallclock time in integer milliseconds. (Not used in tests/PathOpsSkpClipTest.cpp because it redefines things in Test.h.)
Removed tabs in tests/StrokerTest.cpp.
BUG=skia:4632
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1811613004
Review URL: https://codereview.chromium.org/1811613004
2016-03-25 19:59:53 +00:00
|
|
|
* Returns 0 if the timer is stopped. Behavior is undefined if the timer
|
|
|
|
* has been running longer than SK_MSecMax.
|
2015-02-02 20:55:02 +00:00
|
|
|
*/
|
Change SkTime::GetMSecs to double; ensure values stored in SkMSec do not overflow.
The following are currently unused in Android, Google3, Chromium, and Mozilla:
- SkEvent
- SkTime::GetMSecs
- SK_TIME_FACTOR (also unused in Skia)
- SkAutoTime
I left uses of SkMSec more-or-less intact for SkEvent, SkAnimator, and SkInterpolator. SkInterpolator is used in Chromium, so I did not want to change the API. The views/ and animator/ code is crufty, so it didn't seem worthwhile to refactor it. Instead, I added SkEvent::GetMSecsSinceStartup, which is likely to be adequate for use in SampleApp.
I also left SkMSec where it is used to measure a duration rather than a timestamp. With the exception of SkMovie, which is used in Android, all of the uses appear to measure the execution time of a piece of code, which I would hope does not exceed 2^31 milliseconds.
Added skiatest::Timer to support a common idiom in tests where we want to measure the wallclock time in integer milliseconds. (Not used in tests/PathOpsSkpClipTest.cpp because it redefines things in Test.h.)
Removed tabs in tests/StrokerTest.cpp.
BUG=skia:4632
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1811613004
Review URL: https://codereview.chromium.org/1811613004
2016-03-25 19:59:53 +00:00
|
|
|
SkMSec msec() const {
|
2019-01-10 16:27:34 +00:00
|
|
|
const double msec = fElapsedNanos * 1e-6;
|
Change SkTime::GetMSecs to double; ensure values stored in SkMSec do not overflow.
The following are currently unused in Android, Google3, Chromium, and Mozilla:
- SkEvent
- SkTime::GetMSecs
- SK_TIME_FACTOR (also unused in Skia)
- SkAutoTime
I left uses of SkMSec more-or-less intact for SkEvent, SkAnimator, and SkInterpolator. SkInterpolator is used in Chromium, so I did not want to change the API. The views/ and animator/ code is crufty, so it didn't seem worthwhile to refactor it. Instead, I added SkEvent::GetMSecsSinceStartup, which is likely to be adequate for use in SampleApp.
I also left SkMSec where it is used to measure a duration rather than a timestamp. With the exception of SkMovie, which is used in Android, all of the uses appear to measure the execution time of a piece of code, which I would hope does not exceed 2^31 milliseconds.
Added skiatest::Timer to support a common idiom in tests where we want to measure the wallclock time in integer milliseconds. (Not used in tests/PathOpsSkpClipTest.cpp because it redefines things in Test.h.)
Removed tabs in tests/StrokerTest.cpp.
BUG=skia:4632
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1811613004
Review URL: https://codereview.chromium.org/1811613004
2016-03-25 19:59:53 +00:00
|
|
|
SkASSERT(SK_MSecMax >= msec);
|
|
|
|
return static_cast<SkMSec>(msec);
|
|
|
|
}
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the time in seconds the timer has been in the running state.
|
|
|
|
* Returns 0 if the timer is stopped.
|
|
|
|
*/
|
2019-01-10 16:27:34 +00:00
|
|
|
double secs() const { return fElapsedNanos * 1e-9; }
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the time in seconds the timer has been in the running state,
|
|
|
|
* scaled by "speed" and (if not zero) mod by period.
|
|
|
|
* Returns 0 if the timer is stopped.
|
|
|
|
*/
|
|
|
|
SkScalar scaled(SkScalar speed, SkScalar period = 0) const {
|
|
|
|
double value = this->secs() * speed;
|
|
|
|
if (period) {
|
|
|
|
value = ::fmod(value, SkScalarToDouble(period));
|
|
|
|
}
|
|
|
|
return SkDoubleToScalar(value);
|
|
|
|
}
|
|
|
|
|
2016-05-13 20:48:48 +00:00
|
|
|
/**
|
|
|
|
* Transitions from ends->mid->ends linearly over period seconds. The phase specifies a phase
|
|
|
|
* shift in seconds.
|
|
|
|
*/
|
|
|
|
SkScalar pingPong(SkScalar period, SkScalar phase, SkScalar ends, SkScalar mid) const {
|
|
|
|
return PingPong(this->secs(), period, phase, ends, mid);
|
|
|
|
}
|
|
|
|
|
2019-03-20 16:55:08 +00:00
|
|
|
/** Helper for computing a ping-pong value without a AnimTimer object. */
|
|
|
|
static SkScalar PingPong(double t,
|
|
|
|
SkScalar period,
|
|
|
|
SkScalar phase,
|
|
|
|
SkScalar ends,
|
2016-05-13 20:48:48 +00:00
|
|
|
SkScalar mid) {
|
|
|
|
double value = ::fmod(t + phase, period);
|
2019-03-20 16:55:08 +00:00
|
|
|
double half = period / 2.0;
|
|
|
|
double diff = ::fabs(value - half);
|
2016-05-13 20:48:48 +00:00
|
|
|
return SkDoubleToScalar(ends + (1.0 - diff / half) * (mid - ends));
|
|
|
|
}
|
|
|
|
|
2015-02-02 20:55:02 +00:00
|
|
|
private:
|
2019-01-10 16:27:34 +00:00
|
|
|
double fPreviousNanos;
|
|
|
|
double fElapsedNanos;
|
|
|
|
float fSpeed;
|
|
|
|
State fState;
|
2015-02-02 20:55:02 +00:00
|
|
|
|
|
|
|
void setState(State newState) {
|
|
|
|
switch (newState) {
|
|
|
|
case kStopped_State:
|
2019-01-10 16:27:34 +00:00
|
|
|
fPreviousNanos = fElapsedNanos = 0;
|
2019-03-20 16:55:08 +00:00
|
|
|
fState = kStopped_State;
|
2015-02-02 20:55:02 +00:00
|
|
|
break;
|
|
|
|
case kPaused_State:
|
|
|
|
if (kRunning_State == fState) {
|
|
|
|
fState = kPaused_State;
|
2019-03-20 16:55:08 +00:00
|
|
|
} // else stay stopped or paused
|
2015-02-02 20:55:02 +00:00
|
|
|
break;
|
|
|
|
case kRunning_State:
|
|
|
|
switch (fState) {
|
|
|
|
case kStopped_State:
|
2019-01-10 16:27:34 +00:00
|
|
|
fPreviousNanos = SkTime::GetNSecs();
|
2019-03-20 16:55:08 +00:00
|
|
|
fElapsedNanos = 0;
|
2019-01-10 16:27:34 +00:00
|
|
|
break;
|
|
|
|
case kPaused_State: // they want "resume"
|
|
|
|
fPreviousNanos = SkTime::GetNSecs();
|
2015-02-02 20:55:02 +00:00
|
|
|
break;
|
2019-03-20 16:55:08 +00:00
|
|
|
case kRunning_State: break;
|
2015-02-02 20:55:02 +00:00
|
|
|
}
|
|
|
|
fState = kRunning_State;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|