xref: /aosp_15_r20/external/skia/tools/viewer/MeshGradientSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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