skia2/gm/SkAnimTimer.h
Florin Malita 76a076bbdf Generic "directory" viewer slide
This is a generalization of "skottie-dir", based on SkSG and operating
at the Slide API level.

For now it is only instantiated for Json slides, but could be used for
other slide "directories" in the future.

TBR=
NOTRY=true
Change-Id: If12429084bddeb172b234344f23eabcdadedcceb
Reviewed-on: https://skia-review.googlesource.com/108002
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Florin Malita <fmalita@chromium.org>
2018-02-16 14:40:45 +00:00

166 lines
5.1 KiB
C++

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkScalar.h"
#include "SkTime.h"
#ifndef SkAnimTimer_DEFINED
#define SkAnimTimer_DEFINED
/**
* Class to track a "timer". It supports 3 states: stopped, paused, running.
*
* 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().
*/
class SkAnimTimer {
public:
enum State {
kStopped_State,
kPaused_State,
kRunning_State
};
/**
* Class begins in the "stopped" state.
*/
SkAnimTimer() : fBaseTimeNanos(0), fCurrTimeNanos(0), fState(kStopped_State) {}
SkAnimTimer(double base, double curr, State state)
: fBaseTimeNanos(base)
, fCurrTimeNanos(curr)
, fState(state) {}
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.
*/
void stop() {
this->setState(kStopped_State);
}
/**
* If the timer is paused or stopped, it will resume (or start if it was stopped).
*/
void run() {
this->setState(kRunning_State);
}
/**
* If the timer is stopped, this has no effect, else it toggles between paused and running.
*/
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) {
fCurrTimeNanos = SkTime::GetNSecs();
}
}
/**
* Return the time in milliseconds the timer has been in the running state.
* Returns 0 if the timer is stopped. Behavior is undefined if the timer
* has been running longer than SK_MSecMax.
*/
SkMSec msec() const {
const double msec = (fCurrTimeNanos - fBaseTimeNanos) * 1e-6;
SkASSERT(SK_MSecMax >= msec);
return static_cast<SkMSec>(msec);
}
/**
* Return the time in seconds the timer has been in the running state.
* Returns 0 if the timer is stopped.
*/
double secs() const { return (fCurrTimeNanos - fBaseTimeNanos) * 1e-9; }
/**
* 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);
}
/**
* 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);
}
/** Helper for computing a ping-pong value without a SkAnimTimer object. */
static SkScalar PingPong(double t, SkScalar period, SkScalar phase, SkScalar ends,
SkScalar mid) {
double value = ::fmod(t + phase, period);
double half = period / 2.0;
double diff = ::fabs(value - half);
return SkDoubleToScalar(ends + (1.0 - diff / half) * (mid - ends));
}
private:
double fBaseTimeNanos;
double fCurrTimeNanos;
State fState;
void setState(State newState) {
switch (newState) {
case kStopped_State:
fBaseTimeNanos = fCurrTimeNanos = 0;
fState = kStopped_State;
break;
case kPaused_State:
if (kRunning_State == fState) {
fState = kPaused_State;
} // else stay stopped or paused
break;
case kRunning_State:
switch (fState) {
case kStopped_State:
fBaseTimeNanos = fCurrTimeNanos = SkTime::GetNSecs();
break;
case kPaused_State: {// they want "resume"
double now = SkTime::GetNSecs();
fBaseTimeNanos += now - fCurrTimeNanos;
fCurrTimeNanos = now;
} break;
case kRunning_State:
break;
}
fState = kRunning_State;
break;
}
}
};
#endif