1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 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/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCubicMap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkVertices.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tools/timer/TimeUtils.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/Slide.h"
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
27*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
28*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
29*c8dee2aaSAndroid Build Coastguard Worker #include <iterator>
30*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker #include "imgui.h"
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker namespace {
35*c8dee2aaSAndroid Build Coastguard Worker
lerp(float a,float b,float t)36*c8dee2aaSAndroid Build Coastguard Worker float lerp(float a, float b, float t) {
37*c8dee2aaSAndroid Build Coastguard Worker return a + (b - a)*t;
38*c8dee2aaSAndroid Build Coastguard Worker }
39*c8dee2aaSAndroid Build Coastguard Worker
make_image_shader(const char * resource)40*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> make_image_shader(const char* resource) {
41*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> img = ToolUtils::GetResourceAsImage(resource);
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker // Normalize to 1x1 for UV sampling.
44*c8dee2aaSAndroid Build Coastguard Worker const auto lm = SkMatrix::Scale(1.0f/img->width(), 1.0f/img->height());
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker return img->makeShader(SkTileMode::kDecal,
47*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kDecal,
48*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear),
49*c8dee2aaSAndroid Build Coastguard Worker &lm);
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct ShaderFactory {
53*c8dee2aaSAndroid Build Coastguard Worker const char* fName;
54*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> (*fBuild)();
55*c8dee2aaSAndroid Build Coastguard Worker } gShaderFactories[] = {
56*c8dee2aaSAndroid Build Coastguard Worker {
57*c8dee2aaSAndroid Build Coastguard Worker "Img (Mandrill)",
__anon58b8984e0202() 58*c8dee2aaSAndroid Build Coastguard Worker []() ->sk_sp<SkShader> { return make_image_shader("images/mandrill_512.png"); }
59*c8dee2aaSAndroid Build Coastguard Worker },
60*c8dee2aaSAndroid Build Coastguard Worker {
61*c8dee2aaSAndroid Build Coastguard Worker "Img (Baby Tux)",
__anon58b8984e0302() 62*c8dee2aaSAndroid Build Coastguard Worker []() ->sk_sp<SkShader> { return make_image_shader("images/baby_tux.png"); }
63*c8dee2aaSAndroid Build Coastguard Worker },
64*c8dee2aaSAndroid Build Coastguard Worker {
65*c8dee2aaSAndroid Build Coastguard Worker "Img (Brickwork)",
__anon58b8984e0402() 66*c8dee2aaSAndroid Build Coastguard Worker []() ->sk_sp<SkShader> { return make_image_shader("images/brickwork-texture.jpg"); }
67*c8dee2aaSAndroid Build Coastguard Worker },
68*c8dee2aaSAndroid Build Coastguard Worker {
69*c8dee2aaSAndroid Build Coastguard Worker "Radial Gradient",
__anon58b8984e0502() 70*c8dee2aaSAndroid Build Coastguard Worker []() ->sk_sp<SkShader> {
71*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor gColors[] = {
72*c8dee2aaSAndroid Build Coastguard Worker SK_ColorGREEN, SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN
73*c8dee2aaSAndroid Build Coastguard Worker };
74*c8dee2aaSAndroid Build Coastguard Worker return SkGradientShader::MakeRadial({0.5f, 0.5f}, 0.5f, gColors, nullptr,
75*c8dee2aaSAndroid Build Coastguard Worker std::size(gColors), SkTileMode::kRepeat);
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker },
78*c8dee2aaSAndroid Build Coastguard Worker {
79*c8dee2aaSAndroid Build Coastguard Worker "Colors",
__anon58b8984e0602() 80*c8dee2aaSAndroid Build Coastguard Worker []() ->sk_sp<SkShader> { return nullptr; }
81*c8dee2aaSAndroid Build Coastguard Worker },
82*c8dee2aaSAndroid Build Coastguard Worker };
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct VertexAnimator {
85*c8dee2aaSAndroid Build Coastguard Worker const char* fName;
86*c8dee2aaSAndroid Build Coastguard Worker void (*fAanimate)(const std::vector<SkPoint>& uv, float t, std::vector<SkPoint>& out);
87*c8dee2aaSAndroid Build Coastguard Worker } gVertexAnimators[] = {
88*c8dee2aaSAndroid Build Coastguard Worker {
89*c8dee2aaSAndroid Build Coastguard Worker "Cylinderator",
90*c8dee2aaSAndroid Build Coastguard Worker // Simulate a cylinder rolling sideways across the 1x1 uv space.
__anon58b8984e0702(const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) 91*c8dee2aaSAndroid Build Coastguard Worker [](const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) {
92*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kCylRadius = .2f;
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker const auto cyl_pos = t;
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
97*c8dee2aaSAndroid Build Coastguard Worker const auto& uv = uvs[i];
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker if (uv.fX <= cyl_pos) {
100*c8dee2aaSAndroid Build Coastguard Worker out[i] = uv;
101*c8dee2aaSAndroid Build Coastguard Worker continue;
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker const auto arc_len = uv.fX - cyl_pos,
105*c8dee2aaSAndroid Build Coastguard Worker arc_ang = arc_len/kCylRadius;
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker out[i] = SkPoint{
108*c8dee2aaSAndroid Build Coastguard Worker cyl_pos + std::sin(arc_ang)*kCylRadius,
109*c8dee2aaSAndroid Build Coastguard Worker uv.fY,
110*c8dee2aaSAndroid Build Coastguard Worker };
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker },
113*c8dee2aaSAndroid Build Coastguard Worker },
114*c8dee2aaSAndroid Build Coastguard Worker {
115*c8dee2aaSAndroid Build Coastguard Worker "Squircillator",
116*c8dee2aaSAndroid Build Coastguard Worker // Pull all vertices towards center, proportionally, such that the outer square edge
117*c8dee2aaSAndroid Build Coastguard Worker // is mapped to a circle for t == 1.
__anon58b8984e0802(const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) 118*c8dee2aaSAndroid Build Coastguard Worker [](const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) {
119*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
120*c8dee2aaSAndroid Build Coastguard Worker // remap to [-.5,.5]
121*c8dee2aaSAndroid Build Coastguard Worker const auto uv = (uvs[i] - SkPoint{0.5,0.5});
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker // Distance from center to outer edge for the line pasing through uv.
124*c8dee2aaSAndroid Build Coastguard Worker const auto d = uv.length()*0.5f/std::max(std::abs(uv.fX), std::abs(uv.fY));
125*c8dee2aaSAndroid Build Coastguard Worker // Scale needed to pull the outer edge to the r=0.5 circle at t == 1.
126*c8dee2aaSAndroid Build Coastguard Worker const auto s = lerp(1, (0.5f / d), t);
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker out[i] = uv*s + SkPoint{0.5, 0.5};
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker },
131*c8dee2aaSAndroid Build Coastguard Worker },
132*c8dee2aaSAndroid Build Coastguard Worker {
133*c8dee2aaSAndroid Build Coastguard Worker "Twirlinator",
134*c8dee2aaSAndroid Build Coastguard Worker // Rotate vertices proportional to their distance to center.
__anon58b8984e0902(const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) 135*c8dee2aaSAndroid Build Coastguard Worker [](const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) {
136*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kMaxRotate = SK_FloatPI*4;
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
139*c8dee2aaSAndroid Build Coastguard Worker // remap to [-.5,.5]
140*c8dee2aaSAndroid Build Coastguard Worker const auto uv = (uvs[i] - SkPoint{0.5,0.5});
141*c8dee2aaSAndroid Build Coastguard Worker const auto angle = kMaxRotate * t * uv.length();
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker out[i] = SkMatrix::RotateRad(angle).mapPoint(uv) + SkPoint{0.5, 0.5};
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker },
146*c8dee2aaSAndroid Build Coastguard Worker },
147*c8dee2aaSAndroid Build Coastguard Worker {
148*c8dee2aaSAndroid Build Coastguard Worker "Wigglynator",
__anon58b8984e0a02(const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) 149*c8dee2aaSAndroid Build Coastguard Worker [](const std::vector<SkPoint>& uvs, float t, std::vector<SkPoint>& out) {
150*c8dee2aaSAndroid Build Coastguard Worker const float radius = t*0.2f/(std::sqrt(uvs.size()) - 1);
151*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < uvs.size(); ++i) {
152*c8dee2aaSAndroid Build Coastguard Worker const float phase = i*SK_FloatPI*0.31f,
153*c8dee2aaSAndroid Build Coastguard Worker angle = phase + t*SK_FloatPI*2;
154*c8dee2aaSAndroid Build Coastguard Worker out[i] = uvs[i] + SkVector{
155*c8dee2aaSAndroid Build Coastguard Worker radius*std::cos(angle),
156*c8dee2aaSAndroid Build Coastguard Worker radius*std::sin(angle),
157*c8dee2aaSAndroid Build Coastguard Worker };
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker },
160*c8dee2aaSAndroid Build Coastguard Worker },
161*c8dee2aaSAndroid Build Coastguard Worker {
162*c8dee2aaSAndroid Build Coastguard Worker "None",
__anon58b8984e0b02(const std::vector<SkPoint>& uvs, float, std::vector<SkPoint>& out) 163*c8dee2aaSAndroid Build Coastguard Worker [](const std::vector<SkPoint>& uvs, float, std::vector<SkPoint>& out) { out = uvs; },
164*c8dee2aaSAndroid Build Coastguard Worker },
165*c8dee2aaSAndroid Build Coastguard Worker };
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker class MeshSlide final : public Slide {
168*c8dee2aaSAndroid Build Coastguard Worker public:
MeshSlide()169*c8dee2aaSAndroid Build Coastguard Worker MeshSlide() : fTimeMapper({0.5f, 0}, {0.5f, 1}) { fName = "Mesh"; }
170*c8dee2aaSAndroid Build Coastguard Worker
load(SkScalar w,SkScalar h)171*c8dee2aaSAndroid Build Coastguard Worker void load(SkScalar w, SkScalar h) override {
172*c8dee2aaSAndroid Build Coastguard Worker fSize = {w, h};
173*c8dee2aaSAndroid Build Coastguard Worker
174*c8dee2aaSAndroid Build Coastguard Worker this->initMesh(256);
175*c8dee2aaSAndroid Build Coastguard Worker this->initShader(gShaderFactories[0]);
176*c8dee2aaSAndroid Build Coastguard Worker }
177*c8dee2aaSAndroid Build Coastguard Worker
resize(SkScalar w,SkScalar h)178*c8dee2aaSAndroid Build Coastguard Worker void resize(SkScalar w, SkScalar h) override { fSize = {w, h}; }
179*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)180*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
181*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
184*c8dee2aaSAndroid Build Coastguard Worker p.setAntiAlias(true);
185*c8dee2aaSAndroid Build Coastguard Worker p.setColor(SK_ColorWHITE);
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kMeshFraction = 0.85f;
188*c8dee2aaSAndroid Build Coastguard Worker const float mesh_size = std::min(fSize.fWidth, fSize.fHeight)*kMeshFraction;
189*c8dee2aaSAndroid Build Coastguard Worker
190*c8dee2aaSAndroid Build Coastguard Worker canvas->translate((fSize.fWidth - mesh_size) * 0.5f,
191*c8dee2aaSAndroid Build Coastguard Worker (fSize.fHeight - mesh_size) * 0.5f);
192*c8dee2aaSAndroid Build Coastguard Worker canvas->scale(mesh_size, mesh_size);
193*c8dee2aaSAndroid Build Coastguard Worker
194*c8dee2aaSAndroid Build Coastguard Worker auto verts = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
195*c8dee2aaSAndroid Build Coastguard Worker fVertices.size(),
196*c8dee2aaSAndroid Build Coastguard Worker fVertices.data(),
197*c8dee2aaSAndroid Build Coastguard Worker fShader ? fUVs.data() : nullptr,
198*c8dee2aaSAndroid Build Coastguard Worker fShader ? nullptr : fColors.data(),
199*c8dee2aaSAndroid Build Coastguard Worker fIndices.size(),
200*c8dee2aaSAndroid Build Coastguard Worker fIndices.data());
201*c8dee2aaSAndroid Build Coastguard Worker p.setShader(fShader);
202*c8dee2aaSAndroid Build Coastguard Worker canvas->drawVertices(verts, SkBlendMode::kModulate, p);
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker if (fShowMesh) {
205*c8dee2aaSAndroid Build Coastguard Worker p.setShader(nullptr);
206*c8dee2aaSAndroid Build Coastguard Worker p.setColor(SK_ColorBLUE);
207*c8dee2aaSAndroid Build Coastguard Worker p.setStroke(true);
208*c8dee2aaSAndroid Build Coastguard Worker p.setStrokeWidth(0.5f/mesh_size);
209*c8dee2aaSAndroid Build Coastguard Worker
210*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fIndices.size() % 6 == 0);
211*c8dee2aaSAndroid Build Coastguard Worker for (auto i = fIndices.cbegin(); i < fIndices.cend(); i += 6) {
212*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fVertices[i[0]], fVertices[i[1]], p);
213*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fVertices[i[1]], fVertices[i[2]], p);
214*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fVertices[i[2]], fVertices[i[0]], p);
215*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fVertices[i[3]], fVertices[i[4]], p);
216*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fVertices[i[4]], fVertices[i[5]], p);
217*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fVertices[i[5]], fVertices[i[3]], p);
218*c8dee2aaSAndroid Build Coastguard Worker }
219*c8dee2aaSAndroid Build Coastguard Worker
220*c8dee2aaSAndroid Build Coastguard Worker p.setStrokeCap(SkPaint::kRound_Cap);
221*c8dee2aaSAndroid Build Coastguard Worker p.setStrokeWidth(5/mesh_size);
222*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPoints(SkCanvas::kPoints_PointMode, fVertices.size(), fVertices.data(), p);
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard Worker this->drawControls();
226*c8dee2aaSAndroid Build Coastguard Worker }
227*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)228*c8dee2aaSAndroid Build Coastguard Worker bool animate(double nanos) override {
229*c8dee2aaSAndroid Build Coastguard Worker if (!fTimeBase) {
230*c8dee2aaSAndroid Build Coastguard Worker fTimeBase = nanos;
231*c8dee2aaSAndroid Build Coastguard Worker }
232*c8dee2aaSAndroid Build Coastguard Worker
233*c8dee2aaSAndroid Build Coastguard Worker // Oscillating between 0..1
234*c8dee2aaSAndroid Build Coastguard Worker const float t =
235*c8dee2aaSAndroid Build Coastguard Worker std::abs((std::fmod((nanos - fTimeBase)*0.000000001*fAnimationSpeed, 2) - 1));
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker // Add some easing
238*c8dee2aaSAndroid Build Coastguard Worker fCurrentAnimator->fAanimate(fUVs, fTimeMapper.computeYFromX(t), fVertices);
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker return true;
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker private:
initMesh(size_t vertex_count)244*c8dee2aaSAndroid Build Coastguard Worker void initMesh(size_t vertex_count) {
245*c8dee2aaSAndroid Build Coastguard Worker // Generate an NxN mesh. For simplicity, we keep the vertices in normalized space
246*c8dee2aaSAndroid Build Coastguard Worker // (1x1 same as UVs), and scale the mesh up when rendering.
247*c8dee2aaSAndroid Build Coastguard Worker const auto n = static_cast<size_t>(std::sqrt(vertex_count));
248*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(n > 0);
249*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(n == std::sqrt(vertex_count));
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker fVertices.resize(vertex_count);
252*c8dee2aaSAndroid Build Coastguard Worker fUVs.resize(vertex_count);
253*c8dee2aaSAndroid Build Coastguard Worker fColors.resize(vertex_count);
254*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < vertex_count; ++i) {
255*c8dee2aaSAndroid Build Coastguard Worker fVertices[i] = fUVs[i] = {
256*c8dee2aaSAndroid Build Coastguard Worker static_cast<float>(i % n) / (n - 1),
257*c8dee2aaSAndroid Build Coastguard Worker static_cast<float>(i / n) / (n - 1),
258*c8dee2aaSAndroid Build Coastguard Worker };
259*c8dee2aaSAndroid Build Coastguard Worker fColors[i] = SkColorSetRGB(!!(i%2)*255,
260*c8dee2aaSAndroid Build Coastguard Worker !!(i%3)*255,
261*c8dee2aaSAndroid Build Coastguard Worker !!((i+1)%3)*255);
262*c8dee2aaSAndroid Build Coastguard Worker }
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker // Trivial triangle tessellation pattern:
265*c8dee2aaSAndroid Build Coastguard Worker //
266*c8dee2aaSAndroid Build Coastguard Worker // *---*---*
267*c8dee2aaSAndroid Build Coastguard Worker // | /|\ |
268*c8dee2aaSAndroid Build Coastguard Worker // | / | \ |
269*c8dee2aaSAndroid Build Coastguard Worker // |/ | \|
270*c8dee2aaSAndroid Build Coastguard Worker // *---*---*
271*c8dee2aaSAndroid Build Coastguard Worker // |\ | /|
272*c8dee2aaSAndroid Build Coastguard Worker // | \ | / |
273*c8dee2aaSAndroid Build Coastguard Worker // | \|/ |
274*c8dee2aaSAndroid Build Coastguard Worker // *---*---*
275*c8dee2aaSAndroid Build Coastguard Worker const size_t triangle_count = 2*(n - 1)*(n - 1),
276*c8dee2aaSAndroid Build Coastguard Worker index_count = 3*triangle_count;
277*c8dee2aaSAndroid Build Coastguard Worker
278*c8dee2aaSAndroid Build Coastguard Worker fIndices.clear();
279*c8dee2aaSAndroid Build Coastguard Worker fIndices.reserve(index_count);
280*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < n - 1; ++i) {
281*c8dee2aaSAndroid Build Coastguard Worker for (size_t j = 0; j < n - 1; ++j) {
282*c8dee2aaSAndroid Build Coastguard Worker const auto row_0_idx = j*n + i,
283*c8dee2aaSAndroid Build Coastguard Worker row_1_idx = row_0_idx + n,
284*c8dee2aaSAndroid Build Coastguard Worker off_0 = (i + j) % 2,
285*c8dee2aaSAndroid Build Coastguard Worker off_1 = 1 - off_0;
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker fIndices.push_back(row_0_idx + 0);
288*c8dee2aaSAndroid Build Coastguard Worker fIndices.push_back(row_0_idx + 1);
289*c8dee2aaSAndroid Build Coastguard Worker fIndices.push_back(row_1_idx + off_0);
290*c8dee2aaSAndroid Build Coastguard Worker
291*c8dee2aaSAndroid Build Coastguard Worker fIndices.push_back(row_0_idx + off_1);
292*c8dee2aaSAndroid Build Coastguard Worker fIndices.push_back(row_1_idx + 1);
293*c8dee2aaSAndroid Build Coastguard Worker fIndices.push_back(row_1_idx + 0);
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker }
296*c8dee2aaSAndroid Build Coastguard Worker
297*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fIndices.size() == index_count);
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker
initShader(const ShaderFactory & fact)300*c8dee2aaSAndroid Build Coastguard Worker void initShader(const ShaderFactory& fact) {
301*c8dee2aaSAndroid Build Coastguard Worker fShader = fact.fBuild();
302*c8dee2aaSAndroid Build Coastguard Worker fCurrentShaderFactory = &fact;
303*c8dee2aaSAndroid Build Coastguard Worker }
304*c8dee2aaSAndroid Build Coastguard Worker
drawControls()305*c8dee2aaSAndroid Build Coastguard Worker void drawControls() {
306*c8dee2aaSAndroid Build Coastguard Worker ImGui::Begin("Mesh Options");
307*c8dee2aaSAndroid Build Coastguard Worker
308*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::BeginCombo("Texture", fCurrentShaderFactory->fName)) {
309*c8dee2aaSAndroid Build Coastguard Worker for (const auto& fact : gShaderFactories) {
310*c8dee2aaSAndroid Build Coastguard Worker const auto is_selected = (fCurrentShaderFactory->fName == fact.fName);
311*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::Selectable(fact.fName) && !is_selected) {
312*c8dee2aaSAndroid Build Coastguard Worker this->initShader(fact);
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker if (is_selected) {
315*c8dee2aaSAndroid Build Coastguard Worker ImGui::SetItemDefaultFocus();
316*c8dee2aaSAndroid Build Coastguard Worker }
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker ImGui::EndCombo();
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::BeginCombo("Animator", fCurrentAnimator->fName)) {
322*c8dee2aaSAndroid Build Coastguard Worker for (const auto& anim : gVertexAnimators) {
323*c8dee2aaSAndroid Build Coastguard Worker const auto is_selected = (fCurrentAnimator->fName == anim.fName);
324*c8dee2aaSAndroid Build Coastguard Worker if (ImGui::Selectable(anim.fName) && !is_selected) {
325*c8dee2aaSAndroid Build Coastguard Worker fCurrentAnimator = &anim;
326*c8dee2aaSAndroid Build Coastguard Worker fTimeBase = 0;
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker if (is_selected) {
329*c8dee2aaSAndroid Build Coastguard Worker ImGui::SetItemDefaultFocus();
330*c8dee2aaSAndroid Build Coastguard Worker }
331*c8dee2aaSAndroid Build Coastguard Worker }
332*c8dee2aaSAndroid Build Coastguard Worker ImGui::EndCombo();
333*c8dee2aaSAndroid Build Coastguard Worker }
334*c8dee2aaSAndroid Build Coastguard Worker
335*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct {
336*c8dee2aaSAndroid Build Coastguard Worker const char* fLabel;
337*c8dee2aaSAndroid Build Coastguard Worker size_t fCount;
338*c8dee2aaSAndroid Build Coastguard Worker } gSizeInfo[] = {
339*c8dee2aaSAndroid Build Coastguard Worker { "4x4", 16 },
340*c8dee2aaSAndroid Build Coastguard Worker { "8x8", 64 },
341*c8dee2aaSAndroid Build Coastguard Worker { "16x16", 256 },
342*c8dee2aaSAndroid Build Coastguard Worker { "32x32", 1024 },
343*c8dee2aaSAndroid Build Coastguard Worker { "64x64", 4096 },
344*c8dee2aaSAndroid Build Coastguard Worker { "128x128", 16384 },
345*c8dee2aaSAndroid Build Coastguard Worker };
346*c8dee2aaSAndroid Build Coastguard Worker ImGui::SliderInt("Mesh Size",
347*c8dee2aaSAndroid Build Coastguard Worker &fMeshSizeSelector,
348*c8dee2aaSAndroid Build Coastguard Worker 0, std::size(gSizeInfo) - 1,
349*c8dee2aaSAndroid Build Coastguard Worker gSizeInfo[fMeshSizeSelector].fLabel);
350*c8dee2aaSAndroid Build Coastguard Worker if (fVertices.size() != gSizeInfo[fMeshSizeSelector].fCount) {
351*c8dee2aaSAndroid Build Coastguard Worker this->initMesh(gSizeInfo[fMeshSizeSelector].fCount);
352*c8dee2aaSAndroid Build Coastguard Worker }
353*c8dee2aaSAndroid Build Coastguard Worker
354*c8dee2aaSAndroid Build Coastguard Worker ImGui::SliderFloat("Speed", &fAnimationSpeed, 0.25, 4, "%.2f");
355*c8dee2aaSAndroid Build Coastguard Worker
356*c8dee2aaSAndroid Build Coastguard Worker ImGui::Checkbox("Show mesh", &fShowMesh);
357*c8dee2aaSAndroid Build Coastguard Worker
358*c8dee2aaSAndroid Build Coastguard Worker ImGui::End();
359*c8dee2aaSAndroid Build Coastguard Worker }
360*c8dee2aaSAndroid Build Coastguard Worker
361*c8dee2aaSAndroid Build Coastguard Worker SkSize fSize;
362*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader;
363*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkPoint> fVertices,
364*c8dee2aaSAndroid Build Coastguard Worker fUVs;
365*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkColor> fColors;
366*c8dee2aaSAndroid Build Coastguard Worker std::vector<uint16_t> fIndices;
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker double fTimeBase = 0;
369*c8dee2aaSAndroid Build Coastguard Worker const SkCubicMap fTimeMapper;
370*c8dee2aaSAndroid Build Coastguard Worker
371*c8dee2aaSAndroid Build Coastguard Worker // UI stuff
372*c8dee2aaSAndroid Build Coastguard Worker const ShaderFactory* fCurrentShaderFactory = &gShaderFactories[0];
373*c8dee2aaSAndroid Build Coastguard Worker const VertexAnimator* fCurrentAnimator = &gVertexAnimators[0];
374*c8dee2aaSAndroid Build Coastguard Worker int fMeshSizeSelector = 2;
375*c8dee2aaSAndroid Build Coastguard Worker float fAnimationSpeed = 1.f;
376*c8dee2aaSAndroid Build Coastguard Worker bool fShowMesh = false;
377*c8dee2aaSAndroid Build Coastguard Worker };
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
380*c8dee2aaSAndroid Build Coastguard Worker
381*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE(return new MeshSlide{};)
382