1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2024 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCubicMap.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkVertices.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/Slide.h"
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
26*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
27*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
28*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker #include "delaunator.hpp"
31*c8dee2aaSAndroid Build Coastguard Worker #include "imgui.h"
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker namespace {
34*c8dee2aaSAndroid Build Coastguard Worker
triangulate_pts(const std::vector<SkPoint> & pts,const std::vector<SkColor> & colors)35*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkVertices> triangulate_pts(const std::vector<SkPoint>& pts, const std::vector<SkColor>& colors) {
36*c8dee2aaSAndroid Build Coastguard Worker // put points in the format delaunator wants
37*c8dee2aaSAndroid Build Coastguard Worker std::vector<double> coords;
38*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < pts.size(); ++i) {
39*c8dee2aaSAndroid Build Coastguard Worker coords.push_back(pts[i].x());
40*c8dee2aaSAndroid Build Coastguard Worker coords.push_back(pts[i].y());
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker // triangulation happens here
44*c8dee2aaSAndroid Build Coastguard Worker delaunator::Delaunator d(coords);
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker // SkVertices parameters
47*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> vertices;
48*c8dee2aaSAndroid Build Coastguard Worker std::vector<uint16_t> indices;
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker // populate vertices & colors
51*c8dee2aaSAndroid Build Coastguard Worker for(std::size_t i = 0; i < d.coords.size(); i+=2) {
52*c8dee2aaSAndroid Build Coastguard Worker vertices.push_back(SkPoint::Make(d.coords[i], d.coords[i+1]));
53*c8dee2aaSAndroid Build Coastguard Worker }
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker // populate triangle indices
56*c8dee2aaSAndroid Build Coastguard Worker for(std::size_t i = 0; i < d.triangles.size(); i+=3) {
57*c8dee2aaSAndroid Build Coastguard Worker indices.push_back(d.triangles[i]);
58*c8dee2aaSAndroid Build Coastguard Worker indices.push_back(d.triangles[i+1]);
59*c8dee2aaSAndroid Build Coastguard Worker indices.push_back(d.triangles[i+2]);
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker return SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, vertices.size(), vertices.data(), nullptr, colors.data(), indices.size(), indices.data());
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker
makeGradientShader(int w,int h,std::vector<SkPoint> & vertices,std::vector<SkColor> & colors)65*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> makeGradientShader(int w, int h, std::vector<SkPoint>& vertices, std::vector<SkColor>& colors) {
66*c8dee2aaSAndroid Build Coastguard Worker vertices.push_back(SkPoint::Make(0.f, 0.f));
67*c8dee2aaSAndroid Build Coastguard Worker vertices.push_back(SkPoint::Make(w, 0.f));
68*c8dee2aaSAndroid Build Coastguard Worker vertices.push_back(SkPoint::Make(0.f, h));
69*c8dee2aaSAndroid Build Coastguard Worker vertices.push_back(SkPoint::Make(w, h));
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker colors.push_back(SK_ColorTRANSPARENT);
72*c8dee2aaSAndroid Build Coastguard Worker colors.push_back(SK_ColorTRANSPARENT);
73*c8dee2aaSAndroid Build Coastguard Worker colors.push_back(SK_ColorTRANSPARENT);
74*c8dee2aaSAndroid Build Coastguard Worker colors.push_back(SK_ColorTRANSPARENT);
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkVertices> sk_vertices = triangulate_pts(vertices, colors);
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker // record with a picture
79*c8dee2aaSAndroid Build Coastguard Worker SkRect tile = SkRect::MakeWH(w, h);
80*c8dee2aaSAndroid Build Coastguard Worker SkPictureRecorder recorder;
81*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* c = recorder.beginRecording(tile);
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
84*c8dee2aaSAndroid Build Coastguard Worker p.setColor(SK_ColorWHITE);
85*c8dee2aaSAndroid Build Coastguard Worker c->drawVertices(sk_vertices, SkBlendMode::kModulate, p);
86*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker return picture->makeShader(SkTileMode::kDecal, SkTileMode::kDecal, SkFilterMode::kNearest);
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker class GradientRenderer : public SkRefCnt {
92*c8dee2aaSAndroid Build Coastguard Worker public:
93*c8dee2aaSAndroid Build Coastguard Worker virtual void draw(SkCanvas*) const = 0;
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker virtual sk_sp<SkShader> asShader() const = 0;
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Worker virtual void updateVertices(SkSpan<const SkPoint> vert_pos,
98*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkColor4f> vert_colors) = 0;
99*c8dee2aaSAndroid Build Coastguard Worker };
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker class SkSlRenderer : public GradientRenderer {
102*c8dee2aaSAndroid Build Coastguard Worker public:
draw(SkCanvas * canvas) const103*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) const override {
104*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
105*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(fShader);
106*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(1, 1), paint);
107*c8dee2aaSAndroid Build Coastguard Worker }
108*c8dee2aaSAndroid Build Coastguard Worker
asShader() const109*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> asShader() const override { return fShader; }
110*c8dee2aaSAndroid Build Coastguard Worker
updateVertices(SkSpan<const SkPoint> vert_pos,SkSpan<const SkColor4f> vert_colors)111*c8dee2aaSAndroid Build Coastguard Worker void updateVertices(SkSpan<const SkPoint> vert_pos,
112*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkColor4f> vert_colors) override {
113*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(vert_pos.size() == vert_colors.size());
114*c8dee2aaSAndroid Build Coastguard Worker const auto vert_count = vert_pos.size();
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker if (!vert_count) {
117*c8dee2aaSAndroid Build Coastguard Worker return;
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker // Effect compilation is expensive, so we cache and only recompile when the count changes.
121*c8dee2aaSAndroid Build Coastguard Worker if (vert_count != fCachedCount) {
122*c8dee2aaSAndroid Build Coastguard Worker this->buildEffect(vert_count);
123*c8dee2aaSAndroid Build Coastguard Worker fCachedCount = vert_count;
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffectBuilder builder(fEffect);
127*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_vertcolors").set(vert_colors.data(), vert_colors.size());
128*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_vertpos") .set(vert_pos.data() , vert_pos.size());
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker fShader = builder.makeShader();
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker virtual void buildEffect(size_t vert_count) = 0;
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker protected:
135*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> fEffect;
136*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader;
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker size_t fCachedCount = 0;
139*c8dee2aaSAndroid Build Coastguard Worker };
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker class AEGradientRenderer final : public SkSlRenderer {
142*c8dee2aaSAndroid Build Coastguard Worker public:
buildEffect(size_t vert_count)143*c8dee2aaSAndroid Build Coastguard Worker void buildEffect(size_t vert_count) override {
144*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gAEGradientSkSL[] =
145*c8dee2aaSAndroid Build Coastguard Worker "uniform half4 u_vertcolors[%zu];"
146*c8dee2aaSAndroid Build Coastguard Worker "uniform float2 u_vertpos[%zu];"
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker "half4 main(float2 xy) {"
149*c8dee2aaSAndroid Build Coastguard Worker "half4 c = half4(0);"
150*c8dee2aaSAndroid Build Coastguard Worker "float w_acc = 0;"
151*c8dee2aaSAndroid Build Coastguard Worker
152*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; ++i) {"
153*c8dee2aaSAndroid Build Coastguard Worker "float d = distance(xy, u_vertpos[i]);"
154*c8dee2aaSAndroid Build Coastguard Worker "float w = 1 / (d * d);"
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker "c += u_vertcolors[i] * w;"
157*c8dee2aaSAndroid Build Coastguard Worker "w_acc += w;"
158*c8dee2aaSAndroid Build Coastguard Worker "}"
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker "return c / w_acc;"
161*c8dee2aaSAndroid Build Coastguard Worker "}";
162*c8dee2aaSAndroid Build Coastguard Worker
163*c8dee2aaSAndroid Build Coastguard Worker const auto res = SkRuntimeEffect::MakeForShader(
164*c8dee2aaSAndroid Build Coastguard Worker SkStringPrintf(gAEGradientSkSL, vert_count, vert_count, vert_count));
165*c8dee2aaSAndroid Build Coastguard Worker if (!res.effect) {
166*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGF("%s\n", res.errorText.c_str());
167*c8dee2aaSAndroid Build Coastguard Worker }
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker fEffect = res.effect;
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fEffect);
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker };
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker class LinearGradientRenderer final : public SkSlRenderer {
176*c8dee2aaSAndroid Build Coastguard Worker public:
buildEffect(size_t vert_count)177*c8dee2aaSAndroid Build Coastguard Worker void buildEffect(size_t vert_count) override {
178*c8dee2aaSAndroid Build Coastguard Worker static constexpr char sksl[] =
179*c8dee2aaSAndroid Build Coastguard Worker "uniform half4 u_vertcolors[%zu];"
180*c8dee2aaSAndroid Build Coastguard Worker "uniform float2 u_vertpos[%zu];"
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker "half4 main(float2 xy) {"
183*c8dee2aaSAndroid Build Coastguard Worker "float v[%zu];"
184*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; i++) {"
185*c8dee2aaSAndroid Build Coastguard Worker "v[i] = 1.;"
186*c8dee2aaSAndroid Build Coastguard Worker "}"
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; ++i) {"
189*c8dee2aaSAndroid Build Coastguard Worker "for (int j = 0; j < %zu; ++j) {"
190*c8dee2aaSAndroid Build Coastguard Worker "vec2 delta;"
191*c8dee2aaSAndroid Build Coastguard Worker "delta.x = u_vertpos[j].x - u_vertpos[i].x;"
192*c8dee2aaSAndroid Build Coastguard Worker "delta.y = u_vertpos[j].y - u_vertpos[i].y;"
193*c8dee2aaSAndroid Build Coastguard Worker
194*c8dee2aaSAndroid Build Coastguard Worker "mat3 m = mat3 ("
195*c8dee2aaSAndroid Build Coastguard Worker "delta.x, delta.y, 0.," // 1st column
196*c8dee2aaSAndroid Build Coastguard Worker "-delta.y, delta.x, 0.," // 2nd column
197*c8dee2aaSAndroid Build Coastguard Worker "u_vertpos[i].x, u_vertpos[i].y, 1." // 3rd column
198*c8dee2aaSAndroid Build Coastguard Worker ");"
199*c8dee2aaSAndroid Build Coastguard Worker "mat3 m_inv = inverse(m);"
200*c8dee2aaSAndroid Build Coastguard Worker
201*c8dee2aaSAndroid Build Coastguard Worker "vec3 p_h = vec3(xy.x, xy.y, 1.);"
202*c8dee2aaSAndroid Build Coastguard Worker "vec3 u = m_inv*p_h;"
203*c8dee2aaSAndroid Build Coastguard Worker "float t = u.x;"
204*c8dee2aaSAndroid Build Coastguard Worker
205*c8dee2aaSAndroid Build Coastguard Worker "if (t < 0) {"
206*c8dee2aaSAndroid Build Coastguard Worker "v[j] = 0;"
207*c8dee2aaSAndroid Build Coastguard Worker "} else if (t > 1) {"
208*c8dee2aaSAndroid Build Coastguard Worker "v[i] = 0;"
209*c8dee2aaSAndroid Build Coastguard Worker "} else {"
210*c8dee2aaSAndroid Build Coastguard Worker "v[i] *= 1-t;"
211*c8dee2aaSAndroid Build Coastguard Worker "v[j] *= t;"
212*c8dee2aaSAndroid Build Coastguard Worker "}"
213*c8dee2aaSAndroid Build Coastguard Worker "}"
214*c8dee2aaSAndroid Build Coastguard Worker "}"
215*c8dee2aaSAndroid Build Coastguard Worker
216*c8dee2aaSAndroid Build Coastguard Worker "half4 c = half4(0);"
217*c8dee2aaSAndroid Build Coastguard Worker "float w_acc = 0;"
218*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; i++) {"
219*c8dee2aaSAndroid Build Coastguard Worker "c += u_vertcolors[i] * v[i];"
220*c8dee2aaSAndroid Build Coastguard Worker "w_acc += v[i];"
221*c8dee2aaSAndroid Build Coastguard Worker "}"
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker "return c / w_acc;"
224*c8dee2aaSAndroid Build Coastguard Worker "}";
225*c8dee2aaSAndroid Build Coastguard Worker
226*c8dee2aaSAndroid Build Coastguard Worker const auto res = SkRuntimeEffect::MakeForShader(
227*c8dee2aaSAndroid Build Coastguard Worker SkStringPrintf(sksl, vert_count, vert_count, vert_count, vert_count, vert_count, vert_count, vert_count));
228*c8dee2aaSAndroid Build Coastguard Worker if (!res.effect) {
229*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGF("%s\n", res.errorText.c_str());
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker
232*c8dee2aaSAndroid Build Coastguard Worker fEffect = res.effect;
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fEffect);
235*c8dee2aaSAndroid Build Coastguard Worker }
236*c8dee2aaSAndroid Build Coastguard Worker };
237*c8dee2aaSAndroid Build Coastguard Worker
238*c8dee2aaSAndroid Build Coastguard Worker class IllGradientRenderer final : public SkSlRenderer {
239*c8dee2aaSAndroid Build Coastguard Worker public:
buildEffect(size_t vert_count)240*c8dee2aaSAndroid Build Coastguard Worker void buildEffect(size_t vert_count) override {
241*c8dee2aaSAndroid Build Coastguard Worker static constexpr char sksl[] =
242*c8dee2aaSAndroid Build Coastguard Worker "uniform half4 u_vertcolors[%zu];"
243*c8dee2aaSAndroid Build Coastguard Worker "uniform float2 u_vertpos[%zu];"
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker "half4 main(float2 xy) {"
246*c8dee2aaSAndroid Build Coastguard Worker "float d[%zu];"
247*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; i++) {"
248*c8dee2aaSAndroid Build Coastguard Worker "d[i] = 0.;"
249*c8dee2aaSAndroid Build Coastguard Worker "}"
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; ++i) {"
252*c8dee2aaSAndroid Build Coastguard Worker "for (int j = 0; j < %zu; ++j) {"
253*c8dee2aaSAndroid Build Coastguard Worker "vec2 delta;"
254*c8dee2aaSAndroid Build Coastguard Worker "delta.x = u_vertpos[j].x - u_vertpos[i].x;"
255*c8dee2aaSAndroid Build Coastguard Worker "delta.y = u_vertpos[j].y - u_vertpos[i].y;"
256*c8dee2aaSAndroid Build Coastguard Worker
257*c8dee2aaSAndroid Build Coastguard Worker "mat3 m = mat3 ("
258*c8dee2aaSAndroid Build Coastguard Worker "delta.x, delta.y, 0.," // 1st column
259*c8dee2aaSAndroid Build Coastguard Worker "-delta.y, delta.x, 0.," // 2nd column
260*c8dee2aaSAndroid Build Coastguard Worker "u_vertpos[i].x, u_vertpos[i].y, 1." // 3rd column
261*c8dee2aaSAndroid Build Coastguard Worker ");"
262*c8dee2aaSAndroid Build Coastguard Worker "mat3 m_inv = inverse(m);"
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker "vec3 p_h = vec3(xy.x, xy.y, 1.);"
265*c8dee2aaSAndroid Build Coastguard Worker "vec3 u = m_inv*p_h;"
266*c8dee2aaSAndroid Build Coastguard Worker "float t = u.x;"
267*c8dee2aaSAndroid Build Coastguard Worker
268*c8dee2aaSAndroid Build Coastguard Worker "float s = length(delta);"
269*c8dee2aaSAndroid Build Coastguard Worker "if (t < 0) {"
270*c8dee2aaSAndroid Build Coastguard Worker "d[i] += s*abs(u.y);"
271*c8dee2aaSAndroid Build Coastguard Worker "d[j] += s*distance(vec2(u.x, u.y), vec2(1., 0.));"
272*c8dee2aaSAndroid Build Coastguard Worker "} else if (t > 1) {"
273*c8dee2aaSAndroid Build Coastguard Worker "d[j] += s*abs(u.y);"
274*c8dee2aaSAndroid Build Coastguard Worker "d[i] += s*distance(vec2(u.x, u.y), vec2(0., 0.));"
275*c8dee2aaSAndroid Build Coastguard Worker "} else {"
276*c8dee2aaSAndroid Build Coastguard Worker "d[i] += s*distance(vec2(u.x, u.y), vec2(0., 0.));"
277*c8dee2aaSAndroid Build Coastguard Worker "d[j] += s*distance(vec2(u.x, u.y), vec2(1., 0.));"
278*c8dee2aaSAndroid Build Coastguard Worker "}"
279*c8dee2aaSAndroid Build Coastguard Worker "}"
280*c8dee2aaSAndroid Build Coastguard Worker "}"
281*c8dee2aaSAndroid Build Coastguard Worker
282*c8dee2aaSAndroid Build Coastguard Worker "half4 c = half4(0);"
283*c8dee2aaSAndroid Build Coastguard Worker "float w_acc = 0;"
284*c8dee2aaSAndroid Build Coastguard Worker "for (int i = 0; i < %zu; i++) {"
285*c8dee2aaSAndroid Build Coastguard Worker "float w = 1 / (d[i] * d[i]);"
286*c8dee2aaSAndroid Build Coastguard Worker "c += u_vertcolors[i] * w;"
287*c8dee2aaSAndroid Build Coastguard Worker "w_acc += w;"
288*c8dee2aaSAndroid Build Coastguard Worker "}"
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker "return c / w_acc;"
291*c8dee2aaSAndroid Build Coastguard Worker "}";
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker const auto res = SkRuntimeEffect::MakeForShader(
294*c8dee2aaSAndroid Build Coastguard Worker SkStringPrintf(sksl, vert_count, vert_count, vert_count, vert_count, vert_count, vert_count, vert_count));
295*c8dee2aaSAndroid Build Coastguard Worker if (!res.effect) {
296*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGF("%s\n", res.errorText.c_str());
297*c8dee2aaSAndroid Build Coastguard Worker }
298*c8dee2aaSAndroid Build Coastguard Worker
299*c8dee2aaSAndroid Build Coastguard Worker fEffect = res.effect;
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fEffect);
302*c8dee2aaSAndroid Build Coastguard Worker }
303*c8dee2aaSAndroid Build Coastguard Worker };
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker class TriangulatedGradientRenderer final : public GradientRenderer {
306*c8dee2aaSAndroid Build Coastguard Worker public:
draw(SkCanvas * canvas) const307*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) const override {
308*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
309*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(fShader);
310*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(1, 1), paint);
311*c8dee2aaSAndroid Build Coastguard Worker }
312*c8dee2aaSAndroid Build Coastguard Worker
asShader() const313*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> asShader() const override { return fShader; }
314*c8dee2aaSAndroid Build Coastguard Worker
updateVertices(SkSpan<const SkPoint> vert_pos,SkSpan<const SkColor4f> vert_colors)315*c8dee2aaSAndroid Build Coastguard Worker void updateVertices(SkSpan<const SkPoint> vert_pos,
316*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkColor4f> vert_colors) override {
317*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(vert_pos.size() == vert_colors.size());
318*c8dee2aaSAndroid Build Coastguard Worker const auto vert_count = vert_pos.size();
319*c8dee2aaSAndroid Build Coastguard Worker
320*c8dee2aaSAndroid Build Coastguard Worker if (!vert_count) {
321*c8dee2aaSAndroid Build Coastguard Worker return;
322*c8dee2aaSAndroid Build Coastguard Worker }
323*c8dee2aaSAndroid Build Coastguard Worker
324*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> pos;
325*c8dee2aaSAndroid Build Coastguard Worker for (auto& p : vert_pos) {
326*c8dee2aaSAndroid Build Coastguard Worker pos.push_back(p);
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkColor> colors;
329*c8dee2aaSAndroid Build Coastguard Worker for (auto& c : vert_colors) {
330*c8dee2aaSAndroid Build Coastguard Worker colors.push_back(c.toSkColor());
331*c8dee2aaSAndroid Build Coastguard Worker }
332*c8dee2aaSAndroid Build Coastguard Worker
333*c8dee2aaSAndroid Build Coastguard Worker fShader = makeGradientShader(1, 1, pos, colors);
334*c8dee2aaSAndroid Build Coastguard Worker }
335*c8dee2aaSAndroid Build Coastguard Worker
336*c8dee2aaSAndroid Build Coastguard Worker private:
337*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader;
338*c8dee2aaSAndroid Build Coastguard Worker };
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct RendererChoice {
341*c8dee2aaSAndroid Build Coastguard Worker const char* fName;
342*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GradientRenderer>(*fFactory)();
343*c8dee2aaSAndroid Build Coastguard Worker } gGradientRenderers[] = {
344*c8dee2aaSAndroid Build Coastguard Worker {
345*c8dee2aaSAndroid Build Coastguard Worker "AfterEffects Gradient",
__anonc8458bdc0202() 346*c8dee2aaSAndroid Build Coastguard Worker []() -> sk_sp<GradientRenderer> { return sk_make_sp<AEGradientRenderer>(); }
347*c8dee2aaSAndroid Build Coastguard Worker },
348*c8dee2aaSAndroid Build Coastguard Worker {
349*c8dee2aaSAndroid Build Coastguard Worker "n-Linear gradient",
__anonc8458bdc0302() 350*c8dee2aaSAndroid Build Coastguard Worker []() -> sk_sp<GradientRenderer> { return sk_make_sp<LinearGradientRenderer>(); }
351*c8dee2aaSAndroid Build Coastguard Worker },
352*c8dee2aaSAndroid Build Coastguard Worker {
353*c8dee2aaSAndroid Build Coastguard Worker "Illustrator (attempt) gradient",
__anonc8458bdc0402() 354*c8dee2aaSAndroid Build Coastguard Worker []() -> sk_sp<GradientRenderer> { return sk_make_sp<IllGradientRenderer>(); }
355*c8dee2aaSAndroid Build Coastguard Worker },
356*c8dee2aaSAndroid Build Coastguard Worker {
357*c8dee2aaSAndroid Build Coastguard Worker "Triangulated gradient",
__anonc8458bdc0502() 358*c8dee2aaSAndroid Build Coastguard Worker []() -> sk_sp<GradientRenderer> { return sk_make_sp<TriangulatedGradientRenderer>(); }
359*c8dee2aaSAndroid Build Coastguard Worker }
360*c8dee2aaSAndroid Build Coastguard Worker };
361*c8dee2aaSAndroid Build Coastguard Worker
lerp(float a,float b,float t)362*c8dee2aaSAndroid Build Coastguard Worker float lerp(float a, float b, float t) {
363*c8dee2aaSAndroid Build Coastguard Worker return a + (b - a)*t;
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker
366*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct VertexAnimator {
367*c8dee2aaSAndroid Build Coastguard Worker const char* fName;
368*c8dee2aaSAndroid Build Coastguard Worker void (*fAanimate)(SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t);
369*c8dee2aaSAndroid Build Coastguard Worker } gVertexAnimators[] = {
370*c8dee2aaSAndroid Build Coastguard Worker {
371*c8dee2aaSAndroid Build Coastguard Worker "Wigglynator",
__anonc8458bdc0602(SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) 372*c8dee2aaSAndroid Build Coastguard Worker [](SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) {
373*c8dee2aaSAndroid Build Coastguard Worker const float radius = t*0.2f/(std::sqrt(uvs.size()) - 1);
374*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
375*c8dee2aaSAndroid Build Coastguard Worker const float phase = i*SK_FloatPI*0.31f,
376*c8dee2aaSAndroid Build Coastguard Worker angle = phase + t*SK_FloatPI*2;
377*c8dee2aaSAndroid Build Coastguard Worker pos[i] = uvs[i] + SkVector{
378*c8dee2aaSAndroid Build Coastguard Worker radius*std::cos(angle),
379*c8dee2aaSAndroid Build Coastguard Worker radius*std::sin(angle),
380*c8dee2aaSAndroid Build Coastguard Worker };
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker },
383*c8dee2aaSAndroid Build Coastguard Worker },
384*c8dee2aaSAndroid Build Coastguard Worker {
385*c8dee2aaSAndroid Build Coastguard Worker "Squircillator",
386*c8dee2aaSAndroid Build Coastguard Worker // Pull all vertices towards center, proportionally, such that the outer square edge
387*c8dee2aaSAndroid Build Coastguard Worker // is mapped to a circle for t == 1.
__anonc8458bdc0702(SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) 388*c8dee2aaSAndroid Build Coastguard Worker [](SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) {
389*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
390*c8dee2aaSAndroid Build Coastguard Worker // remap to [-.5,.5]
391*c8dee2aaSAndroid Build Coastguard Worker const auto uv = (uvs[i] - SkPoint{0.5,0.5});
392*c8dee2aaSAndroid Build Coastguard Worker // can't allow len to collapse to zero, lest bad things happen at {0.5, 0.5}
393*c8dee2aaSAndroid Build Coastguard Worker const auto len = std::max(uv.length(), std::numeric_limits<float>::min());
394*c8dee2aaSAndroid Build Coastguard Worker
395*c8dee2aaSAndroid Build Coastguard Worker // Distance from center to outer edge for the line pasing through uv.
396*c8dee2aaSAndroid Build Coastguard Worker const auto d = len*0.5f/std::max(std::abs(uv.fX), std::abs(uv.fY));
397*c8dee2aaSAndroid Build Coastguard Worker // Scale needed to pull the outer edge to the r=0.5 circle at t == 1.
398*c8dee2aaSAndroid Build Coastguard Worker const auto s = lerp(1, (0.5f / d), t);
399*c8dee2aaSAndroid Build Coastguard Worker
400*c8dee2aaSAndroid Build Coastguard Worker pos[i] = uv*s + SkPoint{0.5, 0.5};
401*c8dee2aaSAndroid Build Coastguard Worker }
402*c8dee2aaSAndroid Build Coastguard Worker },
403*c8dee2aaSAndroid Build Coastguard Worker },
404*c8dee2aaSAndroid Build Coastguard Worker {
405*c8dee2aaSAndroid Build Coastguard Worker "Twirlinator",
406*c8dee2aaSAndroid Build Coastguard Worker // Rotate vertices proportional to their distance to center.
__anonc8458bdc0802(SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) 407*c8dee2aaSAndroid Build Coastguard Worker [](SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) {
408*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kMaxRotate = SK_FloatPI*4;
409*c8dee2aaSAndroid Build Coastguard Worker
410*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
411*c8dee2aaSAndroid Build Coastguard Worker // remap to [-.5,.5]
412*c8dee2aaSAndroid Build Coastguard Worker const auto uv = (uvs[i] - SkPoint{0.5,0.5});
413*c8dee2aaSAndroid Build Coastguard Worker const auto angle = kMaxRotate * t * uv.length();
414*c8dee2aaSAndroid Build Coastguard Worker
415*c8dee2aaSAndroid Build Coastguard Worker pos[i] = SkMatrix::RotateRad(angle).mapPoint(uv) + SkPoint{0.5, 0.5};
416*c8dee2aaSAndroid Build Coastguard Worker }
417*c8dee2aaSAndroid Build Coastguard Worker },
418*c8dee2aaSAndroid Build Coastguard Worker },
419*c8dee2aaSAndroid Build Coastguard Worker {
420*c8dee2aaSAndroid Build Coastguard Worker "Cylinderator",
421*c8dee2aaSAndroid Build Coastguard Worker // Simulate a cylinder rolling sideways across the 1x1 uv space.
__anonc8458bdc0902(SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) 422*c8dee2aaSAndroid Build Coastguard Worker [](SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) {
423*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kCylRadius = .2f;
424*c8dee2aaSAndroid Build Coastguard Worker
425*c8dee2aaSAndroid Build Coastguard Worker const auto cyl_pos = t;
426*c8dee2aaSAndroid Build Coastguard Worker
427*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
428*c8dee2aaSAndroid Build Coastguard Worker if (uvs[i].fX <= cyl_pos) {
429*c8dee2aaSAndroid Build Coastguard Worker pos[i] = uvs[i];
430*c8dee2aaSAndroid Build Coastguard Worker continue;
431*c8dee2aaSAndroid Build Coastguard Worker }
432*c8dee2aaSAndroid Build Coastguard Worker
433*c8dee2aaSAndroid Build Coastguard Worker const auto arc_len = uvs[i].fX - cyl_pos,
434*c8dee2aaSAndroid Build Coastguard Worker arc_ang = arc_len/kCylRadius;
435*c8dee2aaSAndroid Build Coastguard Worker
436*c8dee2aaSAndroid Build Coastguard Worker pos[i] = SkPoint{
437*c8dee2aaSAndroid Build Coastguard Worker cyl_pos + std::sin(arc_ang)*kCylRadius,
438*c8dee2aaSAndroid Build Coastguard Worker uvs[i].fY,
439*c8dee2aaSAndroid Build Coastguard Worker };
440*c8dee2aaSAndroid Build Coastguard Worker }
441*c8dee2aaSAndroid Build Coastguard Worker },
442*c8dee2aaSAndroid Build Coastguard Worker },
443*c8dee2aaSAndroid Build Coastguard Worker {
444*c8dee2aaSAndroid Build Coastguard Worker "None",
__anonc8458bdc0a02(SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) 445*c8dee2aaSAndroid Build Coastguard Worker [](SkSpan<const SkPoint> uvs, SkSpan<SkPoint> pos, float t) {
446*c8dee2aaSAndroid Build Coastguard Worker memcpy(pos.data(), uvs.data(), uvs.size() * sizeof(SkPoint));
447*c8dee2aaSAndroid Build Coastguard Worker },
448*c8dee2aaSAndroid Build Coastguard Worker },
449*c8dee2aaSAndroid Build Coastguard Worker };
450*c8dee2aaSAndroid Build Coastguard Worker
451*c8dee2aaSAndroid Build Coastguard Worker class MeshGradientSlide final : public Slide {
452*c8dee2aaSAndroid Build Coastguard Worker public:
MeshGradientSlide()453*c8dee2aaSAndroid Build Coastguard Worker MeshGradientSlide()
454*c8dee2aaSAndroid Build Coastguard Worker : fCurrentRenderer(gGradientRenderers[0].fFactory())
455*c8dee2aaSAndroid Build Coastguard Worker , fFont(ToolUtils::DefaultPortableTypeface(), .75f)
456*c8dee2aaSAndroid Build Coastguard Worker , fTimeMapper({0.5f, 0}, {0.5f, 1})
457*c8dee2aaSAndroid Build Coastguard Worker , fVertedCountTimeMapper({0, 0.5f}, {0.5f, 1})
458*c8dee2aaSAndroid Build Coastguard Worker {
459*c8dee2aaSAndroid Build Coastguard Worker fName = "MeshGradient";
460*c8dee2aaSAndroid Build Coastguard Worker }
461*c8dee2aaSAndroid Build Coastguard Worker
load(SkScalar w,SkScalar h)462*c8dee2aaSAndroid Build Coastguard Worker void load(SkScalar w, SkScalar h) override {
463*c8dee2aaSAndroid Build Coastguard Worker fSize = {w, h};
464*c8dee2aaSAndroid Build Coastguard Worker }
465*c8dee2aaSAndroid Build Coastguard Worker
resize(SkScalar w,SkScalar h)466*c8dee2aaSAndroid Build Coastguard Worker void resize(SkScalar w, SkScalar h) override { fSize = {w, h}; }
467*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)468*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
469*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
470*c8dee2aaSAndroid Build Coastguard Worker
471*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kMeshViewFract = 0.85f;
472*c8dee2aaSAndroid Build Coastguard Worker const float mesh_size = std::min(fSize.fWidth, fSize.fHeight) * kMeshViewFract;
473*c8dee2aaSAndroid Build Coastguard Worker
474*c8dee2aaSAndroid Build Coastguard Worker canvas->translate((fSize.fWidth - mesh_size) * 0.5f,
475*c8dee2aaSAndroid Build Coastguard Worker (fSize.fHeight - mesh_size) * 0.5f);
476*c8dee2aaSAndroid Build Coastguard Worker canvas->scale(mesh_size, mesh_size);
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker if (fShaderFill) {
479*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
480*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
481*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(fCurrentRenderer->asShader());
482*c8dee2aaSAndroid Build Coastguard Worker canvas->drawString("SK", 0, 0.75f, fFont, paint);
483*c8dee2aaSAndroid Build Coastguard Worker } else {
484*c8dee2aaSAndroid Build Coastguard Worker fCurrentRenderer->draw(canvas);
485*c8dee2aaSAndroid Build Coastguard Worker }
486*c8dee2aaSAndroid Build Coastguard Worker
487*c8dee2aaSAndroid Build Coastguard Worker this->drawControls();
488*c8dee2aaSAndroid Build Coastguard Worker }
489*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)490*c8dee2aaSAndroid Build Coastguard Worker bool animate(double nanos) override {
491*c8dee2aaSAndroid Build Coastguard Worker // Mesh count animation
492*c8dee2aaSAndroid Build Coastguard Worker {
493*c8dee2aaSAndroid Build Coastguard Worker if (!fVertexCountTimeBase) {
494*c8dee2aaSAndroid Build Coastguard Worker fVertexCountTimeBase = nanos;
495*c8dee2aaSAndroid Build Coastguard Worker }
496*c8dee2aaSAndroid Build Coastguard Worker
497*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kSizeAdjustSeconds = 2;
498*c8dee2aaSAndroid Build Coastguard Worker const float t = (nanos - fVertexCountTimeBase) * 0.000000001 / kSizeAdjustSeconds;
499*c8dee2aaSAndroid Build Coastguard Worker
500*c8dee2aaSAndroid Build Coastguard Worker this->updateMesh(lerp(fVertexCountFrom,
501*c8dee2aaSAndroid Build Coastguard Worker fVertexCountTo,
502*c8dee2aaSAndroid Build Coastguard Worker fVertedCountTimeMapper.computeYFromX(t)));
503*c8dee2aaSAndroid Build Coastguard Worker }
504*c8dee2aaSAndroid Build Coastguard Worker
505*c8dee2aaSAndroid Build Coastguard Worker // Vertex animation
506*c8dee2aaSAndroid Build Coastguard Worker {
507*c8dee2aaSAndroid Build Coastguard Worker if (!fTimeBase) {
508*c8dee2aaSAndroid Build Coastguard Worker fTimeBase = nanos;
509*c8dee2aaSAndroid Build Coastguard Worker }
510*c8dee2aaSAndroid Build Coastguard Worker
511*c8dee2aaSAndroid Build Coastguard Worker const float t =
512*c8dee2aaSAndroid Build Coastguard Worker std::abs((std::fmod((nanos - fTimeBase) * 0.000000001 * fAnimationSpeed, 2) - 1));
513*c8dee2aaSAndroid Build Coastguard Worker
514*c8dee2aaSAndroid Build Coastguard Worker fCurrentAnimator->fAanimate(fVertUVs, fVertPos, fTimeMapper.computeYFromX(t));
515*c8dee2aaSAndroid Build Coastguard Worker
516*c8dee2aaSAndroid Build Coastguard Worker fCurrentRenderer->updateVertices(fVertPos, fVertColors);
517*c8dee2aaSAndroid Build Coastguard Worker }
518*c8dee2aaSAndroid Build Coastguard Worker
519*c8dee2aaSAndroid Build Coastguard Worker return true;
520*c8dee2aaSAndroid Build Coastguard Worker }
521*c8dee2aaSAndroid Build Coastguard Worker
522*c8dee2aaSAndroid Build Coastguard Worker private:
updateMesh(size_t new_count)523*c8dee2aaSAndroid Build Coastguard Worker void updateMesh(size_t new_count) {
524*c8dee2aaSAndroid Build Coastguard Worker // These look better than rng when the count is low.
525*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct {
526*c8dee2aaSAndroid Build Coastguard Worker SkPoint fUv;
527*c8dee2aaSAndroid Build Coastguard Worker SkColor4f fColor;
528*c8dee2aaSAndroid Build Coastguard Worker } gFixedVertices[] = {
529*c8dee2aaSAndroid Build Coastguard Worker {{ .25f, .25f}, {1, 0, 0, 1}},
530*c8dee2aaSAndroid Build Coastguard Worker {{ .75f, .75f}, {0, 1, 0, 1}},
531*c8dee2aaSAndroid Build Coastguard Worker {{ .75f, .25f}, {0, 0, 1, 1}},
532*c8dee2aaSAndroid Build Coastguard Worker {{ .25f, .75f}, {1, 1, 0, 1}},
533*c8dee2aaSAndroid Build Coastguard Worker {{ .50f, .50f}, {0, 1, 1, 1}},
534*c8dee2aaSAndroid Build Coastguard Worker };
535*c8dee2aaSAndroid Build Coastguard Worker
536*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertUVs.size() == fVertPos.size());
537*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertUVs.size() == fVertColors.size());
538*c8dee2aaSAndroid Build Coastguard Worker const size_t current_count = fVertUVs.size();
539*c8dee2aaSAndroid Build Coastguard Worker
540*c8dee2aaSAndroid Build Coastguard Worker fVertUVs.resize(new_count);
541*c8dee2aaSAndroid Build Coastguard Worker fVertPos.resize(new_count);
542*c8dee2aaSAndroid Build Coastguard Worker fVertColors.resize(new_count);
543*c8dee2aaSAndroid Build Coastguard Worker
544*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = current_count; i < new_count; ++i) {
545*c8dee2aaSAndroid Build Coastguard Worker const SkPoint uv = i < std::size(gFixedVertices)
546*c8dee2aaSAndroid Build Coastguard Worker ? gFixedVertices[i].fUv
547*c8dee2aaSAndroid Build Coastguard Worker : SkPoint{ fRNG.nextF(), fRNG.nextF() };
548*c8dee2aaSAndroid Build Coastguard Worker const SkColor4f color = i < std::size(gFixedVertices)
549*c8dee2aaSAndroid Build Coastguard Worker ? gFixedVertices[i].fColor
550*c8dee2aaSAndroid Build Coastguard Worker : SkColor4f{ fRNG.nextF(), fRNG.nextF(), fRNG.nextF(), 1.f };
551*c8dee2aaSAndroid Build Coastguard Worker
552*c8dee2aaSAndroid Build Coastguard Worker fVertUVs[i] = fVertPos[i] = uv;
553*c8dee2aaSAndroid Build Coastguard Worker fVertColors[i] = color;
554*c8dee2aaSAndroid Build Coastguard Worker }
555*c8dee2aaSAndroid Build Coastguard Worker
556*c8dee2aaSAndroid Build Coastguard Worker if (new_count < current_count) {
557*c8dee2aaSAndroid Build Coastguard Worker // Reset the RNG state
558*c8dee2aaSAndroid Build Coastguard Worker fRNG.setSeed(0);
559*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kRandsPerVertex = 5;
560*c8dee2aaSAndroid Build Coastguard Worker const size_t rand_vertex_count =
561*c8dee2aaSAndroid Build Coastguard Worker std::max(new_count, std::size(gFixedVertices)) - std::size(gFixedVertices);
562*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < rand_vertex_count * kRandsPerVertex; ++i) { fRNG.nextF(); }
563*c8dee2aaSAndroid Build Coastguard Worker }
564*c8dee2aaSAndroid Build Coastguard Worker }
565*c8dee2aaSAndroid Build Coastguard Worker
drawControls()566*c8dee2aaSAndroid Build Coastguard Worker void drawControls() {
567*c8dee2aaSAndroid Build Coastguard Worker ImGui::Begin("Mesh Options");
568*c8dee2aaSAndroid Build Coastguard Worker
569*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::BeginCombo("Gradient Type", fCurrentRendererChoice->fName)) {
570*c8dee2aaSAndroid Build Coastguard Worker for (const auto& renderer : gGradientRenderers) {
571*c8dee2aaSAndroid Build Coastguard Worker const auto is_selected = (fCurrentRendererChoice->fName == renderer.fName);
572*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::Selectable(renderer.fName) && !is_selected) {
573*c8dee2aaSAndroid Build Coastguard Worker fCurrentRendererChoice = &renderer;
574*c8dee2aaSAndroid Build Coastguard Worker fCurrentRenderer = renderer.fFactory();
575*c8dee2aaSAndroid Build Coastguard Worker fCurrentRenderer->updateVertices(fVertPos, fVertColors);
576*c8dee2aaSAndroid Build Coastguard Worker }
577*c8dee2aaSAndroid Build Coastguard Worker if (is_selected) {
578*c8dee2aaSAndroid Build Coastguard Worker ImGui::SetItemDefaultFocus();
579*c8dee2aaSAndroid Build Coastguard Worker }
580*c8dee2aaSAndroid Build Coastguard Worker }
581*c8dee2aaSAndroid Build Coastguard Worker ImGui::EndCombo();
582*c8dee2aaSAndroid Build Coastguard Worker }
583*c8dee2aaSAndroid Build Coastguard Worker
584*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::BeginCombo("Animator", fCurrentAnimator->fName)) {
585*c8dee2aaSAndroid Build Coastguard Worker for (const auto& anim : gVertexAnimators) {
586*c8dee2aaSAndroid Build Coastguard Worker const auto is_selected = (fCurrentAnimator->fName == anim.fName);
587*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::Selectable(anim.fName) && !is_selected) {
588*c8dee2aaSAndroid Build Coastguard Worker fCurrentAnimator = &anim;
589*c8dee2aaSAndroid Build Coastguard Worker fTimeBase = 0;
590*c8dee2aaSAndroid Build Coastguard Worker }
591*c8dee2aaSAndroid Build Coastguard Worker if (is_selected) {
592*c8dee2aaSAndroid Build Coastguard Worker ImGui::SetItemDefaultFocus();
593*c8dee2aaSAndroid Build Coastguard Worker }
594*c8dee2aaSAndroid Build Coastguard Worker }
595*c8dee2aaSAndroid Build Coastguard Worker ImGui::EndCombo();
596*c8dee2aaSAndroid Build Coastguard Worker }
597*c8dee2aaSAndroid Build Coastguard Worker
598*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::SliderInt("Vertex Count", &fVertexCountTo, 3, 64)) {
599*c8dee2aaSAndroid Build Coastguard Worker fVertexCountTimeBase = 0;
600*c8dee2aaSAndroid Build Coastguard Worker fVertexCountFrom = fVertUVs.size();
601*c8dee2aaSAndroid Build Coastguard Worker }
602*c8dee2aaSAndroid Build Coastguard Worker
603*c8dee2aaSAndroid Build Coastguard Worker ImGui::SliderFloat("Speed", &fAnimationSpeed, 0.25, 4, "%.2f");
604*c8dee2aaSAndroid Build Coastguard Worker
605*c8dee2aaSAndroid Build Coastguard Worker ImGui::Checkbox("Shader Fill", &fShaderFill);
606*c8dee2aaSAndroid Build Coastguard Worker
607*c8dee2aaSAndroid Build Coastguard Worker ImGui::End();
608*c8dee2aaSAndroid Build Coastguard Worker }
609*c8dee2aaSAndroid Build Coastguard Worker
610*c8dee2aaSAndroid Build Coastguard Worker SkSize fSize;
611*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> fVertUVs;
612*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> fVertPos; // fVertUVs after animation
613*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkColor4f> fVertColors;
614*c8dee2aaSAndroid Build Coastguard Worker
615*c8dee2aaSAndroid Build Coastguard Worker SkRandom fRNG;
616*c8dee2aaSAndroid Build Coastguard Worker
617*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GradientRenderer> fCurrentRenderer;
618*c8dee2aaSAndroid Build Coastguard Worker
619*c8dee2aaSAndroid Build Coastguard Worker const SkFont fFont;
620*c8dee2aaSAndroid Build Coastguard Worker
621*c8dee2aaSAndroid Build Coastguard Worker // Animation state
622*c8dee2aaSAndroid Build Coastguard Worker const SkCubicMap fTimeMapper,
623*c8dee2aaSAndroid Build Coastguard Worker fVertedCountTimeMapper;
624*c8dee2aaSAndroid Build Coastguard Worker double fTimeBase = 0,
625*c8dee2aaSAndroid Build Coastguard Worker fVertexCountTimeBase = 0;
626*c8dee2aaSAndroid Build Coastguard Worker int fVertexCountFrom = 0,
627*c8dee2aaSAndroid Build Coastguard Worker fVertexCountTo = 5;
628*c8dee2aaSAndroid Build Coastguard Worker
629*c8dee2aaSAndroid Build Coastguard Worker // UI stuff
630*c8dee2aaSAndroid Build Coastguard Worker const RendererChoice* fCurrentRendererChoice = &gGradientRenderers[0];
631*c8dee2aaSAndroid Build Coastguard Worker const VertexAnimator* fCurrentAnimator = &gVertexAnimators[0];
632*c8dee2aaSAndroid Build Coastguard Worker float fAnimationSpeed = 1.f;
633*c8dee2aaSAndroid Build Coastguard Worker bool fShaderFill = false;
634*c8dee2aaSAndroid Build Coastguard Worker };
635*c8dee2aaSAndroid Build Coastguard Worker
636*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
637*c8dee2aaSAndroid Build Coastguard Worker
638*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE(return new MeshGradientSlide{};)
639