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 #include "SkCurve.h"
9
10 #include "SkParticleData.h"
11 #include "SkRandom.h"
12 #include "SkReflected.h"
13
14 constexpr SkFieldVisitor::EnumStringMapping gCurveSegmentTypeMapping[] = {
15 { kConstant_SegmentType, "Constant" },
16 { kLinear_SegmentType, "Linear" },
17 { kCubic_SegmentType, "Cubic" },
18 };
19
operator +(SkColor4f c1,SkColor4f c2)20 static SkColor4f operator+(SkColor4f c1, SkColor4f c2) {
21 return { c1.fR + c2.fR, c1.fG + c2.fG, c1.fB + c2.fB, c1.fA + c2.fA };
22 }
23
operator -(SkColor4f c1,SkColor4f c2)24 static SkColor4f operator-(SkColor4f c1, SkColor4f c2) {
25 return { c1.fR - c2.fR, c1.fG - c2.fG, c1.fB - c2.fB, c1.fA - c2.fA };
26 }
27
28 template <typename T>
eval_cubic(const T * pts,SkScalar x)29 static T eval_cubic(const T* pts, SkScalar x) {
30 SkScalar ix = (1 - x);
31 return pts[0]*(ix*ix*ix) + pts[1]*(3*ix*ix*x) + pts[2]*(3*ix*x*x) + pts[3]*(x*x*x);
32 }
33
34 template <typename T>
eval_segment(const T * pts,SkScalar x,int type)35 static T eval_segment(const T* pts, SkScalar x, int type) {
36 switch (type) {
37 case kLinear_SegmentType:
38 return pts[0] + (pts[3] - pts[0]) * x;
39 case kCubic_SegmentType:
40 return eval_cubic(pts, x);
41 case kConstant_SegmentType:
42 default:
43 return pts[0];
44 }
45 }
46
eval(SkScalar x,SkScalar t,bool negate) const47 SkScalar SkCurveSegment::eval(SkScalar x, SkScalar t, bool negate) const {
48 SkScalar result = eval_segment(fMin, x, fType);
49 if (fRanged) {
50 result += (eval_segment(fMax, x, fType) - result) * t;
51 }
52 if (fBidirectional && negate) {
53 result = -result;
54 }
55 return result;
56 }
57
visitFields(SkFieldVisitor * v)58 void SkCurveSegment::visitFields(SkFieldVisitor* v) {
59 v->visit("Type", fType, gCurveSegmentTypeMapping, SK_ARRAY_COUNT(gCurveSegmentTypeMapping));
60 v->visit("Ranged", fRanged);
61 v->visit("Bidirectional", fBidirectional);
62 v->visit("A0", fMin[0]);
63 if (fType == kCubic_SegmentType) {
64 v->visit("B0", fMin[1]);
65 v->visit("C0", fMin[2]);
66 }
67 if (fType != kConstant_SegmentType) {
68 v->visit("D0", fMin[3]);
69 }
70 if (fRanged) {
71 v->visit("A1", fMax[0]);
72 if (fType == kCubic_SegmentType) {
73 v->visit("B1", fMax[1]);
74 v->visit("C1", fMax[2]);
75 }
76 if (fType != kConstant_SegmentType) {
77 v->visit("D1", fMax[3]);
78 }
79 }
80 }
81
eval(const SkParticleUpdateParams & params,SkParticleState & ps) const82 SkScalar SkCurve::eval(const SkParticleUpdateParams& params, SkParticleState& ps) const {
83 SkASSERT(fSegments.count() == fXValues.count() + 1);
84
85 float x = fInput.eval(params, ps);
86
87 int i = 0;
88 for (; i < fXValues.count(); ++i) {
89 if (x <= fXValues[i]) {
90 break;
91 }
92 }
93
94 SkScalar rangeMin = (i == 0) ? 0.0f : fXValues[i - 1];
95 SkScalar rangeMax = (i == fXValues.count()) ? 1.0f : fXValues[i];
96 SkScalar segmentX = (x - rangeMin) / (rangeMax - rangeMin);
97 if (!SkScalarIsFinite(segmentX)) {
98 segmentX = rangeMin;
99 }
100 SkASSERT(0.0f <= segmentX && segmentX <= 1.0f);
101
102 // Always pull t and negate here, so that the stable generator behaves consistently, even if
103 // our segments use an inconsistent feature-set.
104 SkScalar t = ps.fRandom.nextF();
105 bool negate = ps.fRandom.nextBool();
106 return fSegments[i].eval(segmentX, t, negate);
107 }
108
visitFields(SkFieldVisitor * v)109 void SkCurve::visitFields(SkFieldVisitor* v) {
110 v->visit("Input", fInput);
111 v->visit("XValues", fXValues);
112 v->visit("Segments", fSegments);
113
114 // Validate and fixup
115 if (fSegments.empty()) {
116 fSegments.push_back().setConstant(0.0f);
117 }
118 fXValues.resize_back(fSegments.count() - 1);
119 for (int i = 0; i < fXValues.count(); ++i) {
120 fXValues[i] = SkTPin(fXValues[i], i > 0 ? fXValues[i - 1] : 0.0f, 1.0f);
121 }
122 }
123
eval(SkScalar x,SkScalar t) const124 SkColor4f SkColorCurveSegment::eval(SkScalar x, SkScalar t) const {
125 SkColor4f result = eval_segment(fMin, x, fType);
126 if (fRanged) {
127 result = result + (eval_segment(fMax, x, fType) - result) * t;
128 }
129 return result;
130 }
131
visitFields(SkFieldVisitor * v)132 void SkColorCurveSegment::visitFields(SkFieldVisitor* v) {
133 v->visit("Type", fType, gCurveSegmentTypeMapping, SK_ARRAY_COUNT(gCurveSegmentTypeMapping));
134 v->visit("Ranged", fRanged);
135 v->visit("A0", fMin[0]);
136 if (fType == kCubic_SegmentType) {
137 v->visit("B0", fMin[1]);
138 v->visit("C0", fMin[2]);
139 }
140 if (fType != kConstant_SegmentType) {
141 v->visit("D0", fMin[3]);
142 }
143 if (fRanged) {
144 v->visit("A1", fMax[0]);
145 if (fType == kCubic_SegmentType) {
146 v->visit("B1", fMax[1]);
147 v->visit("C1", fMax[2]);
148 }
149 if (fType != kConstant_SegmentType) {
150 v->visit("D1", fMax[3]);
151 }
152 }
153 }
154
eval(const SkParticleUpdateParams & params,SkParticleState & ps) const155 SkColor4f SkColorCurve::eval(const SkParticleUpdateParams& params, SkParticleState& ps) const {
156 SkASSERT(fSegments.count() == fXValues.count() + 1);
157
158 float x = fInput.eval(params, ps);
159
160 int i = 0;
161 for (; i < fXValues.count(); ++i) {
162 if (x <= fXValues[i]) {
163 break;
164 }
165 }
166
167 SkScalar rangeMin = (i == 0) ? 0.0f : fXValues[i - 1];
168 SkScalar rangeMax = (i == fXValues.count()) ? 1.0f : fXValues[i];
169 SkScalar segmentX = (x - rangeMin) / (rangeMax - rangeMin);
170 if (!SkScalarIsFinite(segmentX)) {
171 segmentX = rangeMin;
172 }
173 SkASSERT(0.0f <= segmentX && segmentX <= 1.0f);
174 return fSegments[i].eval(segmentX, ps.fRandom.nextF());
175 }
176
visitFields(SkFieldVisitor * v)177 void SkColorCurve::visitFields(SkFieldVisitor* v) {
178 v->visit("Input", fInput);
179 v->visit("XValues", fXValues);
180 v->visit("Segments", fSegments);
181
182 // Validate and fixup
183 if (fSegments.empty()) {
184 fSegments.push_back().setConstant(SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f });
185 }
186 fXValues.resize_back(fSegments.count() - 1);
187 for (int i = 0; i < fXValues.count(); ++i) {
188 fXValues[i] = SkTPin(fXValues[i], i > 0 ? fXValues[i - 1] : 0.0f, 1.0f);
189 }
190 }
191