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