• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 
8 #ifndef SkCurve_DEFINED
9 #define SkCurve_DEFINED
10 
11 #include "SkColor.h"
12 #include "SkParticleData.h"
13 #include "SkScalar.h"
14 #include "SkTArray.h"
15 
16 class SkFieldVisitor;
17 
18 /**
19  * SkCurve implements a keyframed 1D function, useful for animating values over time. This pattern
20  * is common in digital content creation tools. An SkCurve might represent rotation, scale, opacity,
21  * or any other scalar quantity.
22  *
23  * An SkCurve has a logical domain of [0, 1], and is made of one or more SkCurveSegments.
24  * Each segment describes the behavior of the curve in some sub-domain. For an SkCurve with N
25  * segments, there are (N - 1) intermediate x-values that subdivide the domain. The first and last
26  * x-values are implicitly 0 and 1:
27  *
28  * 0    ...    x[0]    ...    x[1]   ...      ...    1
29  *   Segment_0      Segment_1     ...     Segment_N-1
30  *
31  * Each segment describes a function over [0, 1] - x-values are re-normalized to the segment's
32  * domain when being evaluated. The segments are cubic polynomials, defined by four values (fMin).
33  * These are the values at x=0 and x=1, as well as control points at x=1/3 and x=2/3.
34  *
35  * For segments with fConstant == true, only the first value is used (fMin[0]).
36  *
37  * Each segment has two additional features for creating interesting (and varied) animation:
38  *   - A segment can be ranged. Ranged segments have two sets of coefficients, and a random value
39  *     taken from the particle's SkRandom is used to lerp betwen them. Typically, the SkRandom is
40  *     in the same state at each call, so this value is stable. That causes a ranged SkCurve to
41  *     produce a single smooth cubic function somewhere within the range defined by fMin and fMax.
42  *   - A segment can be bidirectional. In that case, after a value is computed, it will be negated
43  *     50% of the time.
44  */
45 
46 enum SkCurveSegmentType {
47     kConstant_SegmentType,
48     kLinear_SegmentType,
49     kCubic_SegmentType,
50 };
51 
52 struct SkCurveSegment {
53     SkScalar eval(SkScalar x, SkScalar t, bool negate) const;
54     void visitFields(SkFieldVisitor* v);
55 
setConstantSkCurveSegment56     void setConstant(SkScalar c) {
57         fType   = kConstant_SegmentType;
58         fRanged = false;
59         fMin[0] = c;
60     }
61 
62     SkScalar fMin[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
63     SkScalar fMax[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
64 
65     int  fType          = kConstant_SegmentType;
66     bool fRanged        = false;
67     bool fBidirectional = false;
68 };
69 
70 struct SkCurve {
71     SkCurve(SkScalar c = 0.0f) {
72         fSegments.push_back().setConstant(c);
73     }
74 
75     SkScalar eval(const SkParticleUpdateParams& params, SkParticleState& ps) const;
76     void visitFields(SkFieldVisitor* v);
77 
78     // Parameters that determine our x-value during evaluation
79     SkParticleValue                fInput;
80 
81     // It should always be true that (fXValues.count() + 1) == fSegments.count()
82     SkTArray<SkScalar, true>       fXValues;
83     SkTArray<SkCurveSegment, true> fSegments;
84 };
85 
86 /**
87  * SkColorCurve is similar to SkCurve, but keyframes 4D values - specifically colors. Because
88  * negative colors rarely make sense, SkColorCurves do not support bidirectional segments, but
89  * support all other features (including cubic interpolation).
90  */
91 
92 struct SkColorCurveSegment {
SkColorCurveSegmentSkColorCurveSegment93     SkColorCurveSegment() {
94         for (int i = 0; i < 4; ++i) {
95             fMin[i] = { 1.0f, 1.0f, 1.0f, 1.0f };
96             fMax[i] = { 1.0f, 1.0f, 1.0f, 1.0f };
97         }
98     }
99 
100     SkColor4f eval(SkScalar x, SkScalar t) const;
101     void visitFields(SkFieldVisitor* v);
102 
setConstantSkColorCurveSegment103     void setConstant(SkColor4f c) {
104         fType   = kConstant_SegmentType;
105         fRanged = false;
106         fMin[0] = c;
107     }
108 
109     SkColor4f fMin[4];
110     SkColor4f fMax[4];
111 
112     int  fType   = kConstant_SegmentType;
113     bool fRanged = false;
114 };
115 
116 struct SkColorCurve {
117     SkColorCurve(SkColor4f c = { 1.0f, 1.0f, 1.0f, 1.0f }) {
118         fSegments.push_back().setConstant(c);
119     }
120 
121     SkColor4f eval(const SkParticleUpdateParams& params, SkParticleState& ps) const;
122     void visitFields(SkFieldVisitor* v);
123 
124     SkParticleValue                     fInput;
125     SkTArray<SkScalar, true>            fXValues;
126     SkTArray<SkColorCurveSegment, true> fSegments;
127 };
128 
129 #endif // SkCurve_DEFINED
130