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