michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project 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: #ifndef SkInterpolator_DEFINED michael@0: #define SkInterpolator_DEFINED michael@0: michael@0: #include "SkScalar.h" michael@0: michael@0: class SkInterpolatorBase : SkNoncopyable { michael@0: public: michael@0: enum Result { michael@0: kNormal_Result, michael@0: kFreezeStart_Result, michael@0: kFreezeEnd_Result michael@0: }; michael@0: protected: michael@0: SkInterpolatorBase(); michael@0: ~SkInterpolatorBase(); michael@0: public: michael@0: void reset(int elemCount, int frameCount); michael@0: michael@0: /** Return the start and end time for this interpolator. michael@0: If there are no key frames, return false. michael@0: @param startTime If not null, returns the time (in milliseconds) of the michael@0: first keyframe. If there are no keyframes, this param michael@0: is ignored (left unchanged). michael@0: @param endTime If not null, returns the time (in milliseconds) of the michael@0: last keyframe. If there are no keyframes, this parameter michael@0: is ignored (left unchanged). michael@0: @return True if there are key frames, or false if there are none. michael@0: */ michael@0: bool getDuration(SkMSec* startTime, SkMSec* endTime) const; michael@0: michael@0: michael@0: /** Set the whether the repeat is mirrored. michael@0: @param mirror If true, the odd repeats interpolate from the last key michael@0: frame and the first. michael@0: */ michael@0: void setMirror(bool mirror) { michael@0: fFlags = SkToU8((fFlags & ~kMirror) | (int)mirror); michael@0: } michael@0: michael@0: /** Set the repeat count. The repeat count may be fractional. michael@0: @param repeatCount Multiplies the total time by this scalar. michael@0: */ michael@0: void setRepeatCount(SkScalar repeatCount) { fRepeat = repeatCount; } michael@0: michael@0: /** Set the whether the repeat is mirrored. michael@0: @param reset If true, the odd repeats interpolate from the last key michael@0: frame and the first. michael@0: */ michael@0: void setReset(bool reset) { michael@0: fFlags = SkToU8((fFlags & ~kReset) | (int)reset); michael@0: } michael@0: michael@0: Result timeToT(SkMSec time, SkScalar* T, int* index, SkBool* exact) const; michael@0: michael@0: protected: michael@0: enum Flags { michael@0: kMirror = 1, michael@0: kReset = 2, michael@0: kHasBlend = 4 michael@0: }; michael@0: static SkScalar ComputeRelativeT(SkMSec time, SkMSec prevTime, michael@0: SkMSec nextTime, const SkScalar blend[4] = NULL); michael@0: int16_t fFrameCount; michael@0: uint8_t fElemCount; michael@0: uint8_t fFlags; michael@0: SkScalar fRepeat; michael@0: struct SkTimeCode { michael@0: SkMSec fTime; michael@0: SkScalar fBlend[4]; michael@0: }; michael@0: SkTimeCode* fTimes; // pointer into fStorage michael@0: void* fStorage; michael@0: #ifdef SK_DEBUG michael@0: SkTimeCode(* fTimesArray)[10]; michael@0: #endif michael@0: }; michael@0: michael@0: class SkInterpolator : public SkInterpolatorBase { michael@0: public: michael@0: SkInterpolator(); michael@0: SkInterpolator(int elemCount, int frameCount); michael@0: void reset(int elemCount, int frameCount); michael@0: michael@0: /** Add or replace a key frame, copying the values[] data into the michael@0: interpolator. michael@0: @param index The index of this frame (frames must be ordered by time) michael@0: @param time The millisecond time for this frame michael@0: @param values The array of values [elemCount] for this frame. The data michael@0: is copied into the interpolator. michael@0: @param blend A positive scalar specifying how to blend between this michael@0: and the next key frame. [0...1) is a cubic lag/log/lag michael@0: blend (slow to change at the beginning and end) michael@0: 1 is a linear blend (default) michael@0: */ michael@0: bool setKeyFrame(int index, SkMSec time, const SkScalar values[], michael@0: const SkScalar blend[4] = NULL); michael@0: michael@0: /** Return the computed values given the specified time. Return whether michael@0: those values are the result of pinning to either the first michael@0: (kFreezeStart) or last (kFreezeEnd), or from interpolated the two michael@0: nearest key values (kNormal). michael@0: @param time The time to sample (in milliseconds) michael@0: @param (may be null) where to write the computed values. michael@0: */ michael@0: Result timeToValues(SkMSec time, SkScalar values[] = NULL) const; michael@0: michael@0: SkDEBUGCODE(static void UnitTest();) michael@0: private: michael@0: SkScalar* fValues; // pointer into fStorage michael@0: #ifdef SK_DEBUG michael@0: SkScalar(* fScalarsArray)[10]; michael@0: #endif michael@0: typedef SkInterpolatorBase INHERITED; michael@0: }; michael@0: michael@0: /** Given all the parameters are [0...1], apply the cubic specified by (0,0) michael@0: (bx,by) (cx,cy) (1,1) to value, returning the answer, also [0...1]. michael@0: */ michael@0: SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by, michael@0: SkScalar cx, SkScalar cy); michael@0: michael@0: #endif