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