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