1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 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 #include <vector>
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/YUVUtils.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/Slide.h"
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker // Implementation in C++ of some WebKit MotionMark tests
18*c8dee2aaSAndroid Build Coastguard Worker // Tests implemented so far:
19*c8dee2aaSAndroid Build Coastguard Worker // * Canvas Lines
20*c8dee2aaSAndroid Build Coastguard Worker // * Canvas Arcs
21*c8dee2aaSAndroid Build Coastguard Worker // * Paths
22*c8dee2aaSAndroid Build Coastguard Worker // Based on https://github.com/WebKit/MotionMark/blob/main/MotionMark/
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker class MMObject {
25*c8dee2aaSAndroid Build Coastguard Worker public:
26*c8dee2aaSAndroid Build Coastguard Worker virtual ~MMObject() = default;
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker virtual void draw(SkCanvas* canvas) = 0;
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker virtual void animate(double /*nanos*/) = 0;
31*c8dee2aaSAndroid Build Coastguard Worker };
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker class Stage {
34*c8dee2aaSAndroid Build Coastguard Worker public:
Stage(SkSize size,int startingObjectCount,int objectIncrement)35*c8dee2aaSAndroid Build Coastguard Worker Stage(SkSize size, int startingObjectCount, int objectIncrement)
36*c8dee2aaSAndroid Build Coastguard Worker : fSize(size)
37*c8dee2aaSAndroid Build Coastguard Worker , fStartingObjectCount(startingObjectCount)
38*c8dee2aaSAndroid Build Coastguard Worker , fObjectIncrement(objectIncrement) {}
39*c8dee2aaSAndroid Build Coastguard Worker virtual ~Stage() = default;
40*c8dee2aaSAndroid Build Coastguard Worker
41*c8dee2aaSAndroid Build Coastguard Worker // The default impls of draw() and animate() simply iterate over fObjects and call the
42*c8dee2aaSAndroid Build Coastguard Worker // MMObject function.
draw(SkCanvas * canvas)43*c8dee2aaSAndroid Build Coastguard Worker virtual void draw(SkCanvas* canvas) {
44*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < fObjects.size(); ++i) {
45*c8dee2aaSAndroid Build Coastguard Worker fObjects[i]->draw(canvas);
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)49*c8dee2aaSAndroid Build Coastguard Worker virtual bool animate(double nanos) {
50*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < fObjects.size(); ++i) {
51*c8dee2aaSAndroid Build Coastguard Worker fObjects[i]->animate(nanos);
52*c8dee2aaSAndroid Build Coastguard Worker }
53*c8dee2aaSAndroid Build Coastguard Worker return true;
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Worker // The default impl handles +/- to add or remove N objects from the scene
onChar(SkUnichar uni)57*c8dee2aaSAndroid Build Coastguard Worker virtual bool onChar(SkUnichar uni) {
58*c8dee2aaSAndroid Build Coastguard Worker bool handled = false;
59*c8dee2aaSAndroid Build Coastguard Worker switch (uni) {
60*c8dee2aaSAndroid Build Coastguard Worker case '+':
61*c8dee2aaSAndroid Build Coastguard Worker case '=':
62*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fObjectIncrement; ++i) {
63*c8dee2aaSAndroid Build Coastguard Worker fObjects.push_back(this->createObject());
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker handled = true;
66*c8dee2aaSAndroid Build Coastguard Worker break;
67*c8dee2aaSAndroid Build Coastguard Worker case '-':
68*c8dee2aaSAndroid Build Coastguard Worker case '_':
69*c8dee2aaSAndroid Build Coastguard Worker if (fObjects.size() > (size_t) fObjectIncrement) {
70*c8dee2aaSAndroid Build Coastguard Worker fObjects.resize(fObjects.size() - (size_t) fObjectIncrement);
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker handled = true;
73*c8dee2aaSAndroid Build Coastguard Worker break;
74*c8dee2aaSAndroid Build Coastguard Worker default:
75*c8dee2aaSAndroid Build Coastguard Worker break;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker return handled;
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker protected:
82*c8dee2aaSAndroid Build Coastguard Worker virtual std::unique_ptr<MMObject> createObject() = 0;
83*c8dee2aaSAndroid Build Coastguard Worker
initializeObjects()84*c8dee2aaSAndroid Build Coastguard Worker void initializeObjects() {
85*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fStartingObjectCount; ++i) {
86*c8dee2aaSAndroid Build Coastguard Worker fObjects.push_back(this->createObject());
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker
90*c8dee2aaSAndroid Build Coastguard Worker [[maybe_unused]] SkSize fSize;
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker int fStartingObjectCount;
93*c8dee2aaSAndroid Build Coastguard Worker int fObjectIncrement;
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker std::vector<std::unique_ptr<MMObject>> fObjects;
96*c8dee2aaSAndroid Build Coastguard Worker SkRandom fRandom;
97*c8dee2aaSAndroid Build Coastguard Worker };
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker class MotionMarkSlide : public Slide {
100*c8dee2aaSAndroid Build Coastguard Worker public:
101*c8dee2aaSAndroid Build Coastguard Worker MotionMarkSlide() = default;
102*c8dee2aaSAndroid Build Coastguard Worker
onChar(SkUnichar uni)103*c8dee2aaSAndroid Build Coastguard Worker bool onChar(SkUnichar uni) override {
104*c8dee2aaSAndroid Build Coastguard Worker return fStage->onChar(uni);
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)107*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
108*c8dee2aaSAndroid Build Coastguard Worker fStage->draw(canvas);
109*c8dee2aaSAndroid Build Coastguard Worker }
110*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)111*c8dee2aaSAndroid Build Coastguard Worker bool animate(double nanos) override {
112*c8dee2aaSAndroid Build Coastguard Worker return fStage->animate(nanos);
113*c8dee2aaSAndroid Build Coastguard Worker }
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker protected:
116*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Stage> fStage;
117*c8dee2aaSAndroid Build Coastguard Worker };
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker namespace {
121*c8dee2aaSAndroid Build Coastguard Worker
time_counter_value(double nanos,float factor)122*c8dee2aaSAndroid Build Coastguard Worker float time_counter_value(double nanos, float factor) {
123*c8dee2aaSAndroid Build Coastguard Worker constexpr double kMillisPerNano = 0.0000001;
124*c8dee2aaSAndroid Build Coastguard Worker return static_cast<float>(nanos*kMillisPerNano)/factor;
125*c8dee2aaSAndroid Build Coastguard Worker }
126*c8dee2aaSAndroid Build Coastguard Worker
time_fractional_value(double nanos,float cycleLengthMs)127*c8dee2aaSAndroid Build Coastguard Worker float time_fractional_value(double nanos, float cycleLengthMs) {
128*c8dee2aaSAndroid Build Coastguard Worker return SkScalarFraction(time_counter_value(nanos, cycleLengthMs));
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker // The following functions match the input processing that Chrome's canvas2d layer performs before
132*c8dee2aaSAndroid Build Coastguard Worker // calling into Skia.
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker // See https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc;drc=572074cb06425797e7e110511db405134cf67e2f;l=299
canonicalize_angle(float * startAngle,float * endAngle)135*c8dee2aaSAndroid Build Coastguard Worker void canonicalize_angle(float* startAngle, float* endAngle) {
136*c8dee2aaSAndroid Build Coastguard Worker float newStartAngle = SkScalarMod(*startAngle, 360.f);
137*c8dee2aaSAndroid Build Coastguard Worker float delta = newStartAngle - *startAngle;
138*c8dee2aaSAndroid Build Coastguard Worker *startAngle = newStartAngle;
139*c8dee2aaSAndroid Build Coastguard Worker *endAngle = *endAngle + delta;
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker // See https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc;drc=572074cb06425797e7e110511db405134cf67e2f;l=245
adjust_end_angle(float startAngle,float endAngle,bool ccw)143*c8dee2aaSAndroid Build Coastguard Worker float adjust_end_angle(float startAngle, float endAngle, bool ccw) {
144*c8dee2aaSAndroid Build Coastguard Worker float newEndAngle = endAngle;
145*c8dee2aaSAndroid Build Coastguard Worker if (!ccw && endAngle - startAngle >= 360.f) {
146*c8dee2aaSAndroid Build Coastguard Worker newEndAngle = startAngle + 360.f;
147*c8dee2aaSAndroid Build Coastguard Worker } else if (ccw && startAngle - endAngle >= 360.f) {
148*c8dee2aaSAndroid Build Coastguard Worker newEndAngle = startAngle - 360.f;
149*c8dee2aaSAndroid Build Coastguard Worker } else if (!ccw && startAngle > endAngle) {
150*c8dee2aaSAndroid Build Coastguard Worker newEndAngle = startAngle + (360.f - SkScalarMod(startAngle - endAngle, 360.f));
151*c8dee2aaSAndroid Build Coastguard Worker } else if (ccw && startAngle < endAngle) {
152*c8dee2aaSAndroid Build Coastguard Worker newEndAngle = startAngle - (360.f - SkScalarMod(endAngle - startAngle, 360.f));
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker return newEndAngle;
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker
158*c8dee2aaSAndroid Build Coastguard Worker } // namespace
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
161*c8dee2aaSAndroid Build Coastguard Worker // Canvas Lines
162*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
163*c8dee2aaSAndroid Build Coastguard Worker struct LineSegmentParams {
164*c8dee2aaSAndroid Build Coastguard Worker float fCircleRadius;
165*c8dee2aaSAndroid Build Coastguard Worker SkPoint fCircleCenters[4];
166*c8dee2aaSAndroid Build Coastguard Worker float fLineLengthMaximum;
167*c8dee2aaSAndroid Build Coastguard Worker float fLineMinimum;
168*c8dee2aaSAndroid Build Coastguard Worker };
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker class CanvasLineSegment : public MMObject {
171*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasLineSegment(SkRandom * random,const LineSegmentParams & params)172*c8dee2aaSAndroid Build Coastguard Worker CanvasLineSegment(SkRandom* random, const LineSegmentParams& params) {
173*c8dee2aaSAndroid Build Coastguard Worker int circle = random->nextRangeU(0, 3);
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kColors[] = {
176*c8dee2aaSAndroid Build Coastguard Worker 0xffe01040, 0xff10c030, 0xff744cba, 0xffe05010
177*c8dee2aaSAndroid Build Coastguard Worker };
178*c8dee2aaSAndroid Build Coastguard Worker fColor = kColors[circle];
179*c8dee2aaSAndroid Build Coastguard Worker fLineWidth = std::pow(random->nextF(), 12) * 20 + 3;
180*c8dee2aaSAndroid Build Coastguard Worker fOmega = random->nextF() * 3 + 0.2f;
181*c8dee2aaSAndroid Build Coastguard Worker float theta = random->nextRangeF(0, 2*SK_ScalarPI);
182*c8dee2aaSAndroid Build Coastguard Worker fCosTheta = std::cos(theta);
183*c8dee2aaSAndroid Build Coastguard Worker fSinTheta = std::sin(theta);
184*c8dee2aaSAndroid Build Coastguard Worker fStart = params.fCircleCenters[circle] + SkPoint::Make(params.fCircleRadius * fCosTheta,
185*c8dee2aaSAndroid Build Coastguard Worker params.fCircleRadius * fSinTheta);
186*c8dee2aaSAndroid Build Coastguard Worker fLength = params.fLineMinimum;
187*c8dee2aaSAndroid Build Coastguard Worker fLength += std::pow(random->nextF(), 8) * params.fLineLengthMaximum;
188*c8dee2aaSAndroid Build Coastguard Worker fSegmentDirection = random->nextF() > 0.5 ? -1 : 1;
189*c8dee2aaSAndroid Build Coastguard Worker }
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker ~CanvasLineSegment() override = default;
192*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)193*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
194*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
195*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
196*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(fColor);
197*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(fLineWidth);
198*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
199*c8dee2aaSAndroid Build Coastguard Worker
200*c8dee2aaSAndroid Build Coastguard Worker SkPoint end = {
201*c8dee2aaSAndroid Build Coastguard Worker fStart.fX + fSegmentDirection * fLength * fCosTheta,
202*c8dee2aaSAndroid Build Coastguard Worker fStart.fY + fSegmentDirection * fLength * fSinTheta
203*c8dee2aaSAndroid Build Coastguard Worker };
204*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(fStart, end, paint);
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)207*c8dee2aaSAndroid Build Coastguard Worker void animate(double nanos) override {
208*c8dee2aaSAndroid Build Coastguard Worker fLength += std::sin(time_counter_value(nanos, 100) * fOmega);
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker private:
212*c8dee2aaSAndroid Build Coastguard Worker SkColor fColor;
213*c8dee2aaSAndroid Build Coastguard Worker float fLineWidth;
214*c8dee2aaSAndroid Build Coastguard Worker float fOmega;
215*c8dee2aaSAndroid Build Coastguard Worker float fCosTheta;
216*c8dee2aaSAndroid Build Coastguard Worker float fSinTheta;
217*c8dee2aaSAndroid Build Coastguard Worker SkPoint fStart;
218*c8dee2aaSAndroid Build Coastguard Worker float fLength;
219*c8dee2aaSAndroid Build Coastguard Worker float fSegmentDirection;
220*c8dee2aaSAndroid Build Coastguard Worker };
221*c8dee2aaSAndroid Build Coastguard Worker
222*c8dee2aaSAndroid Build Coastguard Worker class CanvasLineSegmentStage : public Stage {
223*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasLineSegmentStage(SkSize size)224*c8dee2aaSAndroid Build Coastguard Worker CanvasLineSegmentStage(SkSize size)
225*c8dee2aaSAndroid Build Coastguard Worker : Stage(size, /*startingObjectCount=*/5000, /*objectIncrement*/1000) {
226*c8dee2aaSAndroid Build Coastguard Worker fParams.fLineMinimum = 20;
227*c8dee2aaSAndroid Build Coastguard Worker fParams.fLineLengthMaximum = 40;
228*c8dee2aaSAndroid Build Coastguard Worker fParams.fCircleRadius = fSize.fWidth/8 - .4 * (fParams.fLineMinimum +
229*c8dee2aaSAndroid Build Coastguard Worker fParams.fLineLengthMaximum);
230*c8dee2aaSAndroid Build Coastguard Worker fParams.fCircleCenters[0] = SkPoint::Make(5.5 / 32 * fSize.fWidth, 2.1 / 3*fSize.fHeight);
231*c8dee2aaSAndroid Build Coastguard Worker fParams.fCircleCenters[1] = SkPoint::Make(12.5 / 32 * fSize.fWidth, .9 / 3*fSize.fHeight);
232*c8dee2aaSAndroid Build Coastguard Worker fParams.fCircleCenters[2] = SkPoint::Make(19.5 / 32 * fSize.fWidth, 2.1 / 3*fSize.fHeight);
233*c8dee2aaSAndroid Build Coastguard Worker fParams.fCircleCenters[3] = SkPoint::Make(26.5 / 32 * fSize.fWidth, .9 / 3*fSize.fHeight);
234*c8dee2aaSAndroid Build Coastguard Worker fHalfSize = SkSize::Make(fSize.fWidth * 0.5f, fSize.fHeight * 0.5f);
235*c8dee2aaSAndroid Build Coastguard Worker fTwoFifthsSizeX = fSize.fWidth * .4;
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker this->initializeObjects();
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker ~CanvasLineSegmentStage() override = default;
241*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)242*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
243*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorWHITE);
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker float dx = fTwoFifthsSizeX * std::cos(fCurrentAngle);
246*c8dee2aaSAndroid Build Coastguard Worker float dy = fTwoFifthsSizeX * std::sin(fCurrentAngle);
247*c8dee2aaSAndroid Build Coastguard Worker
248*c8dee2aaSAndroid Build Coastguard Worker float colorStopStep = SkScalarInterp(-.1f, .1f, fCurrentGradientStep);
249*c8dee2aaSAndroid Build Coastguard Worker int brightnessStep = SkScalarRoundToInt(SkScalarInterp(32, 64, fCurrentGradientStep));
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker SkColor color1Step = SkColorSetARGB(brightnessStep,
252*c8dee2aaSAndroid Build Coastguard Worker brightnessStep,
253*c8dee2aaSAndroid Build Coastguard Worker (brightnessStep << 1),
254*c8dee2aaSAndroid Build Coastguard Worker 102);
255*c8dee2aaSAndroid Build Coastguard Worker SkColor color2Step = SkColorSetARGB((brightnessStep << 1),
256*c8dee2aaSAndroid Build Coastguard Worker (brightnessStep << 1),
257*c8dee2aaSAndroid Build Coastguard Worker brightnessStep,
258*c8dee2aaSAndroid Build Coastguard Worker 102);
259*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[2] = {
260*c8dee2aaSAndroid Build Coastguard Worker {fHalfSize.fWidth + dx, fHalfSize.fHeight + dy},
261*c8dee2aaSAndroid Build Coastguard Worker {fHalfSize.fWidth - dx, fHalfSize.fHeight - dy}
262*c8dee2aaSAndroid Build Coastguard Worker };
263*c8dee2aaSAndroid Build Coastguard Worker SkColor colors[] = {
264*c8dee2aaSAndroid Build Coastguard Worker color1Step,
265*c8dee2aaSAndroid Build Coastguard Worker color1Step,
266*c8dee2aaSAndroid Build Coastguard Worker color2Step,
267*c8dee2aaSAndroid Build Coastguard Worker color2Step
268*c8dee2aaSAndroid Build Coastguard Worker };
269*c8dee2aaSAndroid Build Coastguard Worker float pos[] = {
270*c8dee2aaSAndroid Build Coastguard Worker 0,
271*c8dee2aaSAndroid Build Coastguard Worker 0.2f + colorStopStep,
272*c8dee2aaSAndroid Build Coastguard Worker 0.8f - colorStopStep,
273*c8dee2aaSAndroid Build Coastguard Worker 1
274*c8dee2aaSAndroid Build Coastguard Worker };
275*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> gradientShader = SkGradientShader::MakeLinear(pts, colors, pos, 4,
276*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, 0);
277*c8dee2aaSAndroid Build Coastguard Worker
278*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
279*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
280*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(15);
281*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; i++) {
282*c8dee2aaSAndroid Build Coastguard Worker const SkColor strokeColors[] = {
283*c8dee2aaSAndroid Build Coastguard Worker 0xffe01040, 0xff10c030, 0xff744cba, 0xffe05010
284*c8dee2aaSAndroid Build Coastguard Worker };
285*c8dee2aaSAndroid Build Coastguard Worker const SkColor fillColors[] = {
286*c8dee2aaSAndroid Build Coastguard Worker 0xff70051d, 0xff016112, 0xff2F0C6E, 0xff702701
287*c8dee2aaSAndroid Build Coastguard Worker };
288*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(strokeColors[i]);
289*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
290*c8dee2aaSAndroid Build Coastguard Worker SkRect arcRect = SkRect::MakeXYWH(fParams.fCircleCenters[i].fX - fParams.fCircleRadius,
291*c8dee2aaSAndroid Build Coastguard Worker fParams.fCircleCenters[i].fY- fParams.fCircleRadius,
292*c8dee2aaSAndroid Build Coastguard Worker 2*fParams.fCircleRadius,
293*c8dee2aaSAndroid Build Coastguard Worker 2*fParams.fCircleRadius);
294*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arcRect, 0, 360, false, paint);
295*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(fillColors[i]);
296*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kFill_Style);
297*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arcRect, 0, 360, false, paint);
298*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(gradientShader);
299*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arcRect, 0, 360, false, paint);
300*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(nullptr);
301*c8dee2aaSAndroid Build Coastguard Worker }
302*c8dee2aaSAndroid Build Coastguard Worker
303*c8dee2aaSAndroid Build Coastguard Worker this->Stage::draw(canvas);
304*c8dee2aaSAndroid Build Coastguard Worker }
305*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)306*c8dee2aaSAndroid Build Coastguard Worker bool animate(double nanos) override {
307*c8dee2aaSAndroid Build Coastguard Worker fCurrentAngle = time_fractional_value(nanos, 3000) * SK_ScalarPI * 2;
308*c8dee2aaSAndroid Build Coastguard Worker fCurrentGradientStep = 0.5f + 0.5f * std::sin(
309*c8dee2aaSAndroid Build Coastguard Worker time_fractional_value(nanos, 5000) * SK_ScalarPI * 2);
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker this->Stage::animate(nanos);
312*c8dee2aaSAndroid Build Coastguard Worker return true;
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker
createObject()315*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<MMObject> createObject() override {
316*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<CanvasLineSegment>(&fRandom,fParams);
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker private:
319*c8dee2aaSAndroid Build Coastguard Worker LineSegmentParams fParams;
320*c8dee2aaSAndroid Build Coastguard Worker SkSize fHalfSize;
321*c8dee2aaSAndroid Build Coastguard Worker float fTwoFifthsSizeX;
322*c8dee2aaSAndroid Build Coastguard Worker float fCurrentAngle = 0;
323*c8dee2aaSAndroid Build Coastguard Worker float fCurrentGradientStep = 0.5f;
324*c8dee2aaSAndroid Build Coastguard Worker };
325*c8dee2aaSAndroid Build Coastguard Worker
326*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
327*c8dee2aaSAndroid Build Coastguard Worker // Canvas Arcs
328*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
329*c8dee2aaSAndroid Build Coastguard Worker
330*c8dee2aaSAndroid Build Coastguard Worker class CanvasArc : public MMObject {
331*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasArc(SkRandom * random,SkSize size)332*c8dee2aaSAndroid Build Coastguard Worker CanvasArc(SkRandom* random, SkSize size) {
333*c8dee2aaSAndroid Build Coastguard Worker constexpr float kMaxX = 6;
334*c8dee2aaSAndroid Build Coastguard Worker constexpr float kMaxY = 3;
335*c8dee2aaSAndroid Build Coastguard Worker
336*c8dee2aaSAndroid Build Coastguard Worker const SkColor baseColors[3] = {
337*c8dee2aaSAndroid Build Coastguard Worker 0xff101010, 0xff808080, 0xffc0c0c0
338*c8dee2aaSAndroid Build Coastguard Worker };
339*c8dee2aaSAndroid Build Coastguard Worker const SkColor bonusColors[3] = {
340*c8dee2aaSAndroid Build Coastguard Worker 0xffe01040, 0xff10c030, 0xffe05010
341*c8dee2aaSAndroid Build Coastguard Worker };
342*c8dee2aaSAndroid Build Coastguard Worker float distanceX = size.fWidth / kMaxX;
343*c8dee2aaSAndroid Build Coastguard Worker float distanceY = size.fHeight / (kMaxY + 1);
344*c8dee2aaSAndroid Build Coastguard Worker int randY = random->nextRangeU(0, kMaxY);
345*c8dee2aaSAndroid Build Coastguard Worker int randX = random->nextRangeU(0, kMaxX - 1 * (randY % 2));
346*c8dee2aaSAndroid Build Coastguard Worker
347*c8dee2aaSAndroid Build Coastguard Worker fPoint = SkPoint::Make(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + 0.5f));
348*c8dee2aaSAndroid Build Coastguard Worker
349*c8dee2aaSAndroid Build Coastguard Worker fRadius = 20 + std::pow(random->nextF(), 5) * (std::min(distanceX, distanceY) / 1.8f);
350*c8dee2aaSAndroid Build Coastguard Worker fStartAngle = random->nextRangeF(0, 2*SK_ScalarPI);
351*c8dee2aaSAndroid Build Coastguard Worker fEndAngle = random->nextRangeF(0, 2*SK_ScalarPI);
352*c8dee2aaSAndroid Build Coastguard Worker fOmega = (random->nextF() - 0.5f) * 0.3f;
353*c8dee2aaSAndroid Build Coastguard Worker fCounterclockwise = random->nextBool();
354*c8dee2aaSAndroid Build Coastguard Worker // The MotionMark code appends a random element from an array and appends it to the color
355*c8dee2aaSAndroid Build Coastguard Worker // array, then randomly picks from that. We'll just pick that random element and use it
356*c8dee2aaSAndroid Build Coastguard Worker // if the index is out of bounds for the base color array.
357*c8dee2aaSAndroid Build Coastguard Worker SkColor bonusColor = bonusColors[(randX + sk_float_ceil2int(randY * 0.5f)) % 3];
358*c8dee2aaSAndroid Build Coastguard Worker int colorIndex = random->nextRangeU(0, 3);
359*c8dee2aaSAndroid Build Coastguard Worker fColor = colorIndex == 3 ? bonusColor : baseColors[colorIndex];
360*c8dee2aaSAndroid Build Coastguard Worker fLineWidth = 1 + std::pow(random->nextF(), 5) * 30;
361*c8dee2aaSAndroid Build Coastguard Worker fDoStroke = random->nextRangeU(0, 3) != 0;
362*c8dee2aaSAndroid Build Coastguard Worker }
363*c8dee2aaSAndroid Build Coastguard Worker
364*c8dee2aaSAndroid Build Coastguard Worker ~CanvasArc() override = default;
365*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)366*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
367*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
368*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
369*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(fColor);
370*c8dee2aaSAndroid Build Coastguard Worker SkRect arcRect = SkRect::MakeXYWH(fPoint.fX - fRadius, fPoint.fY - fRadius,
371*c8dee2aaSAndroid Build Coastguard Worker 2*fRadius, 2*fRadius);
372*c8dee2aaSAndroid Build Coastguard Worker
373*c8dee2aaSAndroid Build Coastguard Worker float startAngleDeg = fStartAngle * 180.f / SK_ScalarPI;
374*c8dee2aaSAndroid Build Coastguard Worker float endAngleDeg = fEndAngle * 180.f / SK_ScalarPI;
375*c8dee2aaSAndroid Build Coastguard Worker canonicalize_angle(&startAngleDeg, &endAngleDeg);
376*c8dee2aaSAndroid Build Coastguard Worker endAngleDeg = adjust_end_angle(startAngleDeg, endAngleDeg, fCounterclockwise);
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker float sweepAngle = startAngleDeg - endAngleDeg;
379*c8dee2aaSAndroid Build Coastguard Worker
380*c8dee2aaSAndroid Build Coastguard Worker if (fDoStroke) {
381*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(fLineWidth);
382*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
383*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arcRect, startAngleDeg, sweepAngle, false, paint);
384*c8dee2aaSAndroid Build Coastguard Worker } else {
385*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kFill_Style);
386*c8dee2aaSAndroid Build Coastguard Worker // The MotionMark code creates a path for fills via lineTo(point), arc(), lineTo(point).
387*c8dee2aaSAndroid Build Coastguard Worker // For now we'll just use drawArc for both but might need to revisit.
388*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arcRect, startAngleDeg, sweepAngle, true, paint);
389*c8dee2aaSAndroid Build Coastguard Worker }
390*c8dee2aaSAndroid Build Coastguard Worker }
391*c8dee2aaSAndroid Build Coastguard Worker
animate(double)392*c8dee2aaSAndroid Build Coastguard Worker void animate(double /*nanos*/) override {
393*c8dee2aaSAndroid Build Coastguard Worker fStartAngle += fOmega;
394*c8dee2aaSAndroid Build Coastguard Worker fEndAngle += fOmega / 2;
395*c8dee2aaSAndroid Build Coastguard Worker }
396*c8dee2aaSAndroid Build Coastguard Worker
397*c8dee2aaSAndroid Build Coastguard Worker private:
398*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPoint;
399*c8dee2aaSAndroid Build Coastguard Worker float fRadius;
400*c8dee2aaSAndroid Build Coastguard Worker float fStartAngle; // in radians
401*c8dee2aaSAndroid Build Coastguard Worker float fEndAngle; // in radians
402*c8dee2aaSAndroid Build Coastguard Worker SkColor fColor;
403*c8dee2aaSAndroid Build Coastguard Worker float fOmega; // in radians
404*c8dee2aaSAndroid Build Coastguard Worker bool fDoStroke;
405*c8dee2aaSAndroid Build Coastguard Worker bool fCounterclockwise;
406*c8dee2aaSAndroid Build Coastguard Worker float fLineWidth;
407*c8dee2aaSAndroid Build Coastguard Worker };
408*c8dee2aaSAndroid Build Coastguard Worker
409*c8dee2aaSAndroid Build Coastguard Worker class CanvasArcStage : public Stage {
410*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasArcStage(SkSize size)411*c8dee2aaSAndroid Build Coastguard Worker CanvasArcStage(SkSize size)
412*c8dee2aaSAndroid Build Coastguard Worker : Stage(size, /*startingObjectCount=*/1000, /*objectIncrement=*/200) {
413*c8dee2aaSAndroid Build Coastguard Worker this->initializeObjects();
414*c8dee2aaSAndroid Build Coastguard Worker }
415*c8dee2aaSAndroid Build Coastguard Worker
416*c8dee2aaSAndroid Build Coastguard Worker ~CanvasArcStage() override = default;
417*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)418*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
419*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorWHITE);
420*c8dee2aaSAndroid Build Coastguard Worker this->Stage::draw(canvas);
421*c8dee2aaSAndroid Build Coastguard Worker }
422*c8dee2aaSAndroid Build Coastguard Worker
createObject()423*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<MMObject> createObject() override {
424*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<CanvasArc>(&fRandom, fSize);
425*c8dee2aaSAndroid Build Coastguard Worker }
426*c8dee2aaSAndroid Build Coastguard Worker };
427*c8dee2aaSAndroid Build Coastguard Worker
428*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
429*c8dee2aaSAndroid Build Coastguard Worker // Paths
430*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
431*c8dee2aaSAndroid Build Coastguard Worker
432*c8dee2aaSAndroid Build Coastguard Worker class CanvasLinePoint : public MMObject {
433*c8dee2aaSAndroid Build Coastguard Worker protected:
setEndPoint(SkRandom * random,SkSize size,SkPoint * prevCoord)434*c8dee2aaSAndroid Build Coastguard Worker void setEndPoint(SkRandom* random, SkSize size, SkPoint* prevCoord) {
435*c8dee2aaSAndroid Build Coastguard Worker const SkSize kGridSize = { 80, 40 };
436*c8dee2aaSAndroid Build Coastguard Worker const SkPoint kGridCenter = { 40, 20 };
437*c8dee2aaSAndroid Build Coastguard Worker const SkPoint kOffsets[4] = {
438*c8dee2aaSAndroid Build Coastguard Worker {-4, 0},
439*c8dee2aaSAndroid Build Coastguard Worker {2, 0},
440*c8dee2aaSAndroid Build Coastguard Worker {1, -2},
441*c8dee2aaSAndroid Build Coastguard Worker {1, 2}
442*c8dee2aaSAndroid Build Coastguard Worker };
443*c8dee2aaSAndroid Build Coastguard Worker
444*c8dee2aaSAndroid Build Coastguard Worker SkPoint coordinate = prevCoord ? *prevCoord : kGridCenter;
445*c8dee2aaSAndroid Build Coastguard Worker if (prevCoord) {
446*c8dee2aaSAndroid Build Coastguard Worker SkPoint offset = kOffsets[random->nextRangeU(0, 3)];
447*c8dee2aaSAndroid Build Coastguard Worker coordinate += offset;
448*c8dee2aaSAndroid Build Coastguard Worker if (coordinate.fX < 0 || coordinate.fX > kGridSize.width())
449*c8dee2aaSAndroid Build Coastguard Worker coordinate.fX -= offset.fX * 2;
450*c8dee2aaSAndroid Build Coastguard Worker if (coordinate.fY < 0 || coordinate.fY > kGridSize.height())
451*c8dee2aaSAndroid Build Coastguard Worker coordinate.fY -= offset.fY * 2;
452*c8dee2aaSAndroid Build Coastguard Worker }
453*c8dee2aaSAndroid Build Coastguard Worker
454*c8dee2aaSAndroid Build Coastguard Worker fPoint = SkPoint::Make((coordinate.fX + 0.5f) * size.width() / (kGridSize.width() + 1),
455*c8dee2aaSAndroid Build Coastguard Worker (coordinate.fY + 0.5f) * size.height() / (kGridSize.height() + 1));
456*c8dee2aaSAndroid Build Coastguard Worker fCoordinate = coordinate;
457*c8dee2aaSAndroid Build Coastguard Worker }
458*c8dee2aaSAndroid Build Coastguard Worker
459*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasLinePoint(SkRandom * random,SkSize size,SkPoint * prev)460*c8dee2aaSAndroid Build Coastguard Worker CanvasLinePoint(SkRandom* random, SkSize size, SkPoint* prev) {
461*c8dee2aaSAndroid Build Coastguard Worker const SkColor kColors[7] = {
462*c8dee2aaSAndroid Build Coastguard Worker 0xff101010, 0xff808080, 0xffc0c0c0, 0xff101010, 0xff808080, 0xffc0c0c0, 0xffe01040
463*c8dee2aaSAndroid Build Coastguard Worker };
464*c8dee2aaSAndroid Build Coastguard Worker fColor = kColors[random->nextRangeU(0, 6)];
465*c8dee2aaSAndroid Build Coastguard Worker
466*c8dee2aaSAndroid Build Coastguard Worker fWidth = std::pow(random->nextF(), 5) * 20 + 1;
467*c8dee2aaSAndroid Build Coastguard Worker fIsSplit = random->nextBool();
468*c8dee2aaSAndroid Build Coastguard Worker
469*c8dee2aaSAndroid Build Coastguard Worker this->setEndPoint(random, size, prev);
470*c8dee2aaSAndroid Build Coastguard Worker }
471*c8dee2aaSAndroid Build Coastguard Worker
472*c8dee2aaSAndroid Build Coastguard Worker ~CanvasLinePoint() override = default;
473*c8dee2aaSAndroid Build Coastguard Worker
append(SkPath * path)474*c8dee2aaSAndroid Build Coastguard Worker virtual void append(SkPath* path) {
475*c8dee2aaSAndroid Build Coastguard Worker path->lineTo(fPoint);
476*c8dee2aaSAndroid Build Coastguard Worker }
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker // unused, all the work is done by append
draw(SkCanvas *)479*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas*) override {}
animate(double)480*c8dee2aaSAndroid Build Coastguard Worker void animate(double) override {}
481*c8dee2aaSAndroid Build Coastguard Worker
getColor()482*c8dee2aaSAndroid Build Coastguard Worker SkColor getColor() { return fColor; }
getWidth()483*c8dee2aaSAndroid Build Coastguard Worker float getWidth() { return fWidth; }
getPoint()484*c8dee2aaSAndroid Build Coastguard Worker SkPoint getPoint() { return fPoint; }
getCoord()485*c8dee2aaSAndroid Build Coastguard Worker SkPoint getCoord() { return fCoordinate; }
isSplit()486*c8dee2aaSAndroid Build Coastguard Worker bool isSplit() { return fIsSplit; }
toggleIsSplit()487*c8dee2aaSAndroid Build Coastguard Worker void toggleIsSplit() { fIsSplit = !fIsSplit; }
488*c8dee2aaSAndroid Build Coastguard Worker
489*c8dee2aaSAndroid Build Coastguard Worker private:
490*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPoint;
491*c8dee2aaSAndroid Build Coastguard Worker SkPoint fCoordinate;
492*c8dee2aaSAndroid Build Coastguard Worker SkColor fColor;
493*c8dee2aaSAndroid Build Coastguard Worker float fWidth;
494*c8dee2aaSAndroid Build Coastguard Worker bool fIsSplit;
495*c8dee2aaSAndroid Build Coastguard Worker };
496*c8dee2aaSAndroid Build Coastguard Worker
497*c8dee2aaSAndroid Build Coastguard Worker class CanvasQuadraticSegment : public CanvasLinePoint {
498*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasQuadraticSegment(SkRandom * random,SkSize size,SkPoint * prev)499*c8dee2aaSAndroid Build Coastguard Worker CanvasQuadraticSegment(SkRandom* random, SkSize size, SkPoint* prev)
500*c8dee2aaSAndroid Build Coastguard Worker : CanvasLinePoint(random, size, prev) {
501*c8dee2aaSAndroid Build Coastguard Worker // Note: The construction of these points is odd but mirrors the Javascript code.
502*c8dee2aaSAndroid Build Coastguard Worker
503*c8dee2aaSAndroid Build Coastguard Worker // The chosen point from the base constructor is instead the control point.
504*c8dee2aaSAndroid Build Coastguard Worker fPoint2 = this->getPoint();
505*c8dee2aaSAndroid Build Coastguard Worker
506*c8dee2aaSAndroid Build Coastguard Worker // Get another random point for the actual end point of the segment.
507*c8dee2aaSAndroid Build Coastguard Worker this->setEndPoint(random, size, prev);
508*c8dee2aaSAndroid Build Coastguard Worker }
509*c8dee2aaSAndroid Build Coastguard Worker
append(SkPath * path)510*c8dee2aaSAndroid Build Coastguard Worker void append(SkPath* path) override {
511*c8dee2aaSAndroid Build Coastguard Worker path->quadTo(fPoint2, this->getPoint());
512*c8dee2aaSAndroid Build Coastguard Worker }
513*c8dee2aaSAndroid Build Coastguard Worker
514*c8dee2aaSAndroid Build Coastguard Worker private:
515*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPoint2;
516*c8dee2aaSAndroid Build Coastguard Worker };
517*c8dee2aaSAndroid Build Coastguard Worker
518*c8dee2aaSAndroid Build Coastguard Worker class CanvasBezierSegment : public CanvasLinePoint {
519*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasBezierSegment(SkRandom * random,SkSize size,SkPoint * prev)520*c8dee2aaSAndroid Build Coastguard Worker CanvasBezierSegment(SkRandom* random, SkSize size, SkPoint* prev)
521*c8dee2aaSAndroid Build Coastguard Worker : CanvasLinePoint(random, size, prev) {
522*c8dee2aaSAndroid Build Coastguard Worker // Note: The construction of these points is odd but mirrors the Javascript code.
523*c8dee2aaSAndroid Build Coastguard Worker
524*c8dee2aaSAndroid Build Coastguard Worker // The chosen point from the base constructor is instead the control point.
525*c8dee2aaSAndroid Build Coastguard Worker fPoint2 = this->getPoint();
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker // Get the second control point.
528*c8dee2aaSAndroid Build Coastguard Worker this->setEndPoint(random, size, prev);
529*c8dee2aaSAndroid Build Coastguard Worker fPoint3 = this->getPoint();
530*c8dee2aaSAndroid Build Coastguard Worker
531*c8dee2aaSAndroid Build Coastguard Worker // Get third random point for the actual end point of the segment.
532*c8dee2aaSAndroid Build Coastguard Worker this->setEndPoint(random, size, prev);
533*c8dee2aaSAndroid Build Coastguard Worker }
534*c8dee2aaSAndroid Build Coastguard Worker
append(SkPath * path)535*c8dee2aaSAndroid Build Coastguard Worker void append(SkPath* path) override {
536*c8dee2aaSAndroid Build Coastguard Worker path->cubicTo(fPoint2, fPoint3, this->getPoint());
537*c8dee2aaSAndroid Build Coastguard Worker }
538*c8dee2aaSAndroid Build Coastguard Worker
539*c8dee2aaSAndroid Build Coastguard Worker private:
540*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPoint2;
541*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPoint3;
542*c8dee2aaSAndroid Build Coastguard Worker };
543*c8dee2aaSAndroid Build Coastguard Worker
544*c8dee2aaSAndroid Build Coastguard Worker
make_line_path(SkRandom * random,SkSize size,SkPoint * prev)545*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<CanvasLinePoint> make_line_path(SkRandom* random, SkSize size, SkPoint* prev) {
546*c8dee2aaSAndroid Build Coastguard Worker int choice = random->nextRangeU(0, 3);
547*c8dee2aaSAndroid Build Coastguard Worker switch (choice) {
548*c8dee2aaSAndroid Build Coastguard Worker case 0:
549*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<CanvasQuadraticSegment>(random, size, prev);
550*c8dee2aaSAndroid Build Coastguard Worker break;
551*c8dee2aaSAndroid Build Coastguard Worker case 1:
552*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<CanvasBezierSegment>(random, size, prev);
553*c8dee2aaSAndroid Build Coastguard Worker break;
554*c8dee2aaSAndroid Build Coastguard Worker case 2:
555*c8dee2aaSAndroid Build Coastguard Worker case 3:
556*c8dee2aaSAndroid Build Coastguard Worker default:
557*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<CanvasLinePoint>(random, size, prev);
558*c8dee2aaSAndroid Build Coastguard Worker break;
559*c8dee2aaSAndroid Build Coastguard Worker }
560*c8dee2aaSAndroid Build Coastguard Worker }
561*c8dee2aaSAndroid Build Coastguard Worker
562*c8dee2aaSAndroid Build Coastguard Worker class CanvasLinePathStage : public Stage {
563*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasLinePathStage(SkSize size)564*c8dee2aaSAndroid Build Coastguard Worker CanvasLinePathStage(SkSize size)
565*c8dee2aaSAndroid Build Coastguard Worker : Stage(size, /*startingObjectCount=*/5000, /*objectIncrement=*/1000) {
566*c8dee2aaSAndroid Build Coastguard Worker this->initializeObjects();
567*c8dee2aaSAndroid Build Coastguard Worker }
568*c8dee2aaSAndroid Build Coastguard Worker
569*c8dee2aaSAndroid Build Coastguard Worker ~CanvasLinePathStage() override = default;
570*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)571*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
572*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorWHITE);
573*c8dee2aaSAndroid Build Coastguard Worker
574*c8dee2aaSAndroid Build Coastguard Worker SkPath currentPath;
575*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
576*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
577*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
578*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < fObjects.size(); ++i) {
579*c8dee2aaSAndroid Build Coastguard Worker CanvasLinePoint* object = reinterpret_cast<CanvasLinePoint*>(fObjects[i].get());
580*c8dee2aaSAndroid Build Coastguard Worker if (i == 0) {
581*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(object->getWidth());
582*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(object->getColor());
583*c8dee2aaSAndroid Build Coastguard Worker currentPath.moveTo(object->getPoint());
584*c8dee2aaSAndroid Build Coastguard Worker } else {
585*c8dee2aaSAndroid Build Coastguard Worker object->append(¤tPath);
586*c8dee2aaSAndroid Build Coastguard Worker
587*c8dee2aaSAndroid Build Coastguard Worker if (object->isSplit()) {
588*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(currentPath, paint);
589*c8dee2aaSAndroid Build Coastguard Worker
590*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(object->getWidth());
591*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(object->getColor());
592*c8dee2aaSAndroid Build Coastguard Worker currentPath.reset();
593*c8dee2aaSAndroid Build Coastguard Worker currentPath.moveTo(object->getPoint());
594*c8dee2aaSAndroid Build Coastguard Worker }
595*c8dee2aaSAndroid Build Coastguard Worker
596*c8dee2aaSAndroid Build Coastguard Worker if (fRandom.nextF() > 0.995) {
597*c8dee2aaSAndroid Build Coastguard Worker object->toggleIsSplit();
598*c8dee2aaSAndroid Build Coastguard Worker }
599*c8dee2aaSAndroid Build Coastguard Worker }
600*c8dee2aaSAndroid Build Coastguard Worker }
601*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(currentPath, paint);
602*c8dee2aaSAndroid Build Coastguard Worker }
603*c8dee2aaSAndroid Build Coastguard Worker
animate(double)604*c8dee2aaSAndroid Build Coastguard Worker bool animate(double /*nanos*/) override {
605*c8dee2aaSAndroid Build Coastguard Worker // Nothing to do, but return true so we redraw.
606*c8dee2aaSAndroid Build Coastguard Worker return true;
607*c8dee2aaSAndroid Build Coastguard Worker }
608*c8dee2aaSAndroid Build Coastguard Worker
createObject()609*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<MMObject> createObject() override {
610*c8dee2aaSAndroid Build Coastguard Worker if (fObjects.empty()) {
611*c8dee2aaSAndroid Build Coastguard Worker return make_line_path(&fRandom, fSize, nullptr);
612*c8dee2aaSAndroid Build Coastguard Worker } else {
613*c8dee2aaSAndroid Build Coastguard Worker CanvasLinePoint* prevObject = reinterpret_cast<CanvasLinePoint*>(fObjects.back().get());
614*c8dee2aaSAndroid Build Coastguard Worker SkPoint coord = prevObject->getCoord();
615*c8dee2aaSAndroid Build Coastguard Worker return make_line_path(&fRandom, fSize, &coord);
616*c8dee2aaSAndroid Build Coastguard Worker }
617*c8dee2aaSAndroid Build Coastguard Worker }
618*c8dee2aaSAndroid Build Coastguard Worker };
619*c8dee2aaSAndroid Build Coastguard Worker
620*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
621*c8dee2aaSAndroid Build Coastguard Worker // Bouncing Particles
622*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
623*c8dee2aaSAndroid Build Coastguard Worker
random_position(SkRandom * random,SkSize maxPosition)624*c8dee2aaSAndroid Build Coastguard Worker SkPoint random_position(SkRandom* random, SkSize maxPosition) {
625*c8dee2aaSAndroid Build Coastguard Worker return {(float)random->nextRangeU(0, maxPosition.width()),
626*c8dee2aaSAndroid Build Coastguard Worker (float)random->nextRangeU(0, maxPosition.height())};
627*c8dee2aaSAndroid Build Coastguard Worker }
628*c8dee2aaSAndroid Build Coastguard Worker
random_angle(SkRandom * random)629*c8dee2aaSAndroid Build Coastguard Worker float random_angle(SkRandom* random) {
630*c8dee2aaSAndroid Build Coastguard Worker return random->nextRangeF(0, 2*SK_FloatPI);
631*c8dee2aaSAndroid Build Coastguard Worker }
632*c8dee2aaSAndroid Build Coastguard Worker
random_velocity(SkRandom * random,float maxVelocity)633*c8dee2aaSAndroid Build Coastguard Worker float random_velocity(SkRandom* random, float maxVelocity) {
634*c8dee2aaSAndroid Build Coastguard Worker return random->nextRangeF(maxVelocity/8, maxVelocity);
635*c8dee2aaSAndroid Build Coastguard Worker }
636*c8dee2aaSAndroid Build Coastguard Worker
637*c8dee2aaSAndroid Build Coastguard Worker class Rotater {
638*c8dee2aaSAndroid Build Coastguard Worker public:
Rotater(float rotateInterval)639*c8dee2aaSAndroid Build Coastguard Worker Rotater(float rotateInterval)
640*c8dee2aaSAndroid Build Coastguard Worker : fTimeDelta(0)
641*c8dee2aaSAndroid Build Coastguard Worker , fRotateInterval(rotateInterval) {}
642*c8dee2aaSAndroid Build Coastguard Worker
next(float timeDelta)643*c8dee2aaSAndroid Build Coastguard Worker void next(float timeDelta) {
644*c8dee2aaSAndroid Build Coastguard Worker fTimeDelta = SkScalarMod(fTimeDelta + timeDelta, fRotateInterval);
645*c8dee2aaSAndroid Build Coastguard Worker }
646*c8dee2aaSAndroid Build Coastguard Worker
degrees()647*c8dee2aaSAndroid Build Coastguard Worker float degrees() {
648*c8dee2aaSAndroid Build Coastguard Worker return (360 * fTimeDelta) / fRotateInterval;
649*c8dee2aaSAndroid Build Coastguard Worker }
650*c8dee2aaSAndroid Build Coastguard Worker
651*c8dee2aaSAndroid Build Coastguard Worker private:
652*c8dee2aaSAndroid Build Coastguard Worker float fTimeDelta;
653*c8dee2aaSAndroid Build Coastguard Worker float fRotateInterval;
654*c8dee2aaSAndroid Build Coastguard Worker };
655*c8dee2aaSAndroid Build Coastguard Worker
random_rotater(SkRandom * random)656*c8dee2aaSAndroid Build Coastguard Worker Rotater random_rotater(SkRandom* random) {
657*c8dee2aaSAndroid Build Coastguard Worker return Rotater(random->nextRangeF(10, 100));
658*c8dee2aaSAndroid Build Coastguard Worker }
659*c8dee2aaSAndroid Build Coastguard Worker
point_on_circle(float angle,float radius)660*c8dee2aaSAndroid Build Coastguard Worker SkPoint point_on_circle(float angle, float radius) {
661*c8dee2aaSAndroid Build Coastguard Worker return {radius * SkScalarCos(angle), radius * SkScalarSin(angle)};
662*c8dee2aaSAndroid Build Coastguard Worker }
663*c8dee2aaSAndroid Build Coastguard Worker
664*c8dee2aaSAndroid Build Coastguard Worker class BouncingParticle : public MMObject {
665*c8dee2aaSAndroid Build Coastguard Worker public:
BouncingParticle(SkRandom * random,SkSize stageSize,SkSize particleSize,float maxVelocity)666*c8dee2aaSAndroid Build Coastguard Worker BouncingParticle(SkRandom* random, SkSize stageSize, SkSize particleSize, float maxVelocity)
667*c8dee2aaSAndroid Build Coastguard Worker : fStageSize(stageSize)
668*c8dee2aaSAndroid Build Coastguard Worker , fSize(particleSize)
669*c8dee2aaSAndroid Build Coastguard Worker , fPosition(random_position(random,
670*c8dee2aaSAndroid Build Coastguard Worker {stageSize.fWidth - particleSize.fWidth,
671*c8dee2aaSAndroid Build Coastguard Worker stageSize.fHeight - particleSize.fHeight}))
672*c8dee2aaSAndroid Build Coastguard Worker , fAngle(random_angle(random))
673*c8dee2aaSAndroid Build Coastguard Worker , fVelocity(random_velocity(random, maxVelocity))
674*c8dee2aaSAndroid Build Coastguard Worker , fRotater(random_rotater(random)) {
675*c8dee2aaSAndroid Build Coastguard Worker }
676*c8dee2aaSAndroid Build Coastguard Worker
animate(double deltaNanos)677*c8dee2aaSAndroid Build Coastguard Worker void animate(double deltaNanos) override {
678*c8dee2aaSAndroid Build Coastguard Worker // TODO: consolidate and pass in millis to the Stages
679*c8dee2aaSAndroid Build Coastguard Worker constexpr double kMillisPerNano = 0.0000001;
680*c8dee2aaSAndroid Build Coastguard Worker fPosition += point_on_circle(fAngle, fVelocity * (deltaNanos * kMillisPerNano));
681*c8dee2aaSAndroid Build Coastguard Worker fRotater.next(deltaNanos * kMillisPerNano);
682*c8dee2aaSAndroid Build Coastguard Worker
683*c8dee2aaSAndroid Build Coastguard Worker // If particle is going to move off right side
684*c8dee2aaSAndroid Build Coastguard Worker if (fPosition.fX + fSize.width() > fStageSize.width()) {
685*c8dee2aaSAndroid Build Coastguard Worker // If direction is East-South, go West-South.
686*c8dee2aaSAndroid Build Coastguard Worker if (fAngle >= 0 && fAngle < SK_FloatPI / 2)
687*c8dee2aaSAndroid Build Coastguard Worker fAngle = SK_FloatPI - fAngle;
688*c8dee2aaSAndroid Build Coastguard Worker // If angle is East-North, go West-North.
689*c8dee2aaSAndroid Build Coastguard Worker else if (fAngle > SK_FloatPI / 2 * 3)
690*c8dee2aaSAndroid Build Coastguard Worker fAngle = fAngle - (fAngle - SK_FloatPI / 2 * 3) * 2;
691*c8dee2aaSAndroid Build Coastguard Worker // Make sure the particle does not go outside the stage boundaries.
692*c8dee2aaSAndroid Build Coastguard Worker fPosition.fX = fStageSize.width() - fSize.width();
693*c8dee2aaSAndroid Build Coastguard Worker }
694*c8dee2aaSAndroid Build Coastguard Worker
695*c8dee2aaSAndroid Build Coastguard Worker // If particle is going to move off left side
696*c8dee2aaSAndroid Build Coastguard Worker if (fPosition.fX < 0) {
697*c8dee2aaSAndroid Build Coastguard Worker // If angle is West-South, go East-South.
698*c8dee2aaSAndroid Build Coastguard Worker if (fAngle > SK_FloatPI / 2 && fAngle < SK_FloatPI)
699*c8dee2aaSAndroid Build Coastguard Worker fAngle = SK_FloatPI - fAngle;
700*c8dee2aaSAndroid Build Coastguard Worker // If angle is West-North, go East-North.
701*c8dee2aaSAndroid Build Coastguard Worker else if (fAngle > SK_FloatPI && fAngle < SK_FloatPI / 2 * 3)
702*c8dee2aaSAndroid Build Coastguard Worker fAngle = fAngle + (SK_FloatPI / 2 * 3 - fAngle) * 2;
703*c8dee2aaSAndroid Build Coastguard Worker // Make sure the particle does not go outside the stage boundaries.
704*c8dee2aaSAndroid Build Coastguard Worker fPosition.fX = 0;
705*c8dee2aaSAndroid Build Coastguard Worker }
706*c8dee2aaSAndroid Build Coastguard Worker
707*c8dee2aaSAndroid Build Coastguard Worker // If particle is going to move off bottom side
708*c8dee2aaSAndroid Build Coastguard Worker if (fPosition.fY + fSize.height() > fStageSize.height()) {
709*c8dee2aaSAndroid Build Coastguard Worker // If direction is South, go North.
710*c8dee2aaSAndroid Build Coastguard Worker if (fAngle > 0 && fAngle < SK_FloatPI)
711*c8dee2aaSAndroid Build Coastguard Worker fAngle = SK_FloatPI * 2 - fAngle;
712*c8dee2aaSAndroid Build Coastguard Worker // Make sure the particle does not go outside the stage boundaries.
713*c8dee2aaSAndroid Build Coastguard Worker fPosition.fY = fStageSize.height() - fSize.height();
714*c8dee2aaSAndroid Build Coastguard Worker }
715*c8dee2aaSAndroid Build Coastguard Worker
716*c8dee2aaSAndroid Build Coastguard Worker // If particle is going to move off top side
717*c8dee2aaSAndroid Build Coastguard Worker if (fPosition.fY < 0) {
718*c8dee2aaSAndroid Build Coastguard Worker // If direction is North, go South.
719*c8dee2aaSAndroid Build Coastguard Worker if (fAngle > SK_FloatPI && fAngle < SK_FloatPI * 2)
720*c8dee2aaSAndroid Build Coastguard Worker fAngle = fAngle - (fAngle - SK_FloatPI) * 2;
721*c8dee2aaSAndroid Build Coastguard Worker // Make sure the particle does not go outside the stage boundaries.
722*c8dee2aaSAndroid Build Coastguard Worker fPosition.fY = 0;
723*c8dee2aaSAndroid Build Coastguard Worker }
724*c8dee2aaSAndroid Build Coastguard Worker }
725*c8dee2aaSAndroid Build Coastguard Worker
726*c8dee2aaSAndroid Build Coastguard Worker protected:
727*c8dee2aaSAndroid Build Coastguard Worker SkSize fStageSize;
728*c8dee2aaSAndroid Build Coastguard Worker SkSize fSize;
729*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPosition;
730*c8dee2aaSAndroid Build Coastguard Worker float fAngle;
731*c8dee2aaSAndroid Build Coastguard Worker float fVelocity;
732*c8dee2aaSAndroid Build Coastguard Worker Rotater fRotater;
733*c8dee2aaSAndroid Build Coastguard Worker };
734*c8dee2aaSAndroid Build Coastguard Worker
735*c8dee2aaSAndroid Build Coastguard Worker class BouncingParticlesStage : public Stage {
736*c8dee2aaSAndroid Build Coastguard Worker public:
BouncingParticlesStage(SkSize size)737*c8dee2aaSAndroid Build Coastguard Worker BouncingParticlesStage(SkSize size)
738*c8dee2aaSAndroid Build Coastguard Worker : Stage(size, /*startingObjectCount=*/3000, /*objectIncrement=*/500)
739*c8dee2aaSAndroid Build Coastguard Worker , fParticleSize({150, 150})
740*c8dee2aaSAndroid Build Coastguard Worker , fMaxVelocity(10){
741*c8dee2aaSAndroid Build Coastguard Worker }
742*c8dee2aaSAndroid Build Coastguard Worker
animate(double nanos)743*c8dee2aaSAndroid Build Coastguard Worker bool animate(double nanos) override {
744*c8dee2aaSAndroid Build Coastguard Worker // The particles take delta time
745*c8dee2aaSAndroid Build Coastguard Worker if (fLastTime < 0) {
746*c8dee2aaSAndroid Build Coastguard Worker fLastTime = nanos;
747*c8dee2aaSAndroid Build Coastguard Worker }
748*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < fObjects.size(); ++i) {
749*c8dee2aaSAndroid Build Coastguard Worker fObjects[i]->animate(nanos - fLastTime);
750*c8dee2aaSAndroid Build Coastguard Worker }
751*c8dee2aaSAndroid Build Coastguard Worker fLastTime = nanos;
752*c8dee2aaSAndroid Build Coastguard Worker return true;
753*c8dee2aaSAndroid Build Coastguard Worker }
754*c8dee2aaSAndroid Build Coastguard Worker
755*c8dee2aaSAndroid Build Coastguard Worker protected:
756*c8dee2aaSAndroid Build Coastguard Worker SkSize fParticleSize;
757*c8dee2aaSAndroid Build Coastguard Worker float fMaxVelocity;
758*c8dee2aaSAndroid Build Coastguard Worker double fLastTime = -1;
759*c8dee2aaSAndroid Build Coastguard Worker };
760*c8dee2aaSAndroid Build Coastguard Worker
761*c8dee2aaSAndroid Build Coastguard Worker
762*c8dee2aaSAndroid Build Coastguard Worker class BouncingTaggedImage : public BouncingParticle {
763*c8dee2aaSAndroid Build Coastguard Worker public:
BouncingTaggedImage(SkRandom * random,SkSize stageSize,SkSize particleSize,float maxVelocity)764*c8dee2aaSAndroid Build Coastguard Worker BouncingTaggedImage(SkRandom* random, SkSize stageSize, SkSize particleSize, float maxVelocity)
765*c8dee2aaSAndroid Build Coastguard Worker : BouncingParticle(random, stageSize, particleSize, maxVelocity) {
766*c8dee2aaSAndroid Build Coastguard Worker this->move();
767*c8dee2aaSAndroid Build Coastguard Worker fRect = SkRect::MakeSize(fSize);
768*c8dee2aaSAndroid Build Coastguard Worker fRect.offset(-fSize.width()/2, -fSize.height()/2);
769*c8dee2aaSAndroid Build Coastguard Worker }
770*c8dee2aaSAndroid Build Coastguard Worker
move()771*c8dee2aaSAndroid Build Coastguard Worker void move() {
772*c8dee2aaSAndroid Build Coastguard Worker fTransform = SkMatrix::RotateDeg(std::floor(fRotater.degrees()));
773*c8dee2aaSAndroid Build Coastguard Worker fTransform.setTranslateX(fPosition.fX);
774*c8dee2aaSAndroid Build Coastguard Worker fTransform.setTranslateY(fPosition.fY);
775*c8dee2aaSAndroid Build Coastguard Worker }
776*c8dee2aaSAndroid Build Coastguard Worker
animate(double deltaNanos)777*c8dee2aaSAndroid Build Coastguard Worker void animate(double deltaNanos) override {
778*c8dee2aaSAndroid Build Coastguard Worker BouncingParticle::animate(deltaNanos);
779*c8dee2aaSAndroid Build Coastguard Worker this->move();
780*c8dee2aaSAndroid Build Coastguard Worker }
781*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)782*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
783*c8dee2aaSAndroid Build Coastguard Worker // handled by the Stage
784*c8dee2aaSAndroid Build Coastguard Worker }
785*c8dee2aaSAndroid Build Coastguard Worker
transform()786*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& transform() { return fTransform; }
rect()787*c8dee2aaSAndroid Build Coastguard Worker SkRect rect() { return fRect; }
788*c8dee2aaSAndroid Build Coastguard Worker
789*c8dee2aaSAndroid Build Coastguard Worker private:
790*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fTransform;
791*c8dee2aaSAndroid Build Coastguard Worker SkRect fRect;
792*c8dee2aaSAndroid Build Coastguard Worker };
793*c8dee2aaSAndroid Build Coastguard Worker
794*c8dee2aaSAndroid Build Coastguard Worker
795*c8dee2aaSAndroid Build Coastguard Worker class BouncingTaggedImagesStage : public BouncingParticlesStage {
796*c8dee2aaSAndroid Build Coastguard Worker public:
BouncingTaggedImagesStage(SkSize size)797*c8dee2aaSAndroid Build Coastguard Worker BouncingTaggedImagesStage(SkSize size) : BouncingParticlesStage(size) {
798*c8dee2aaSAndroid Build Coastguard Worker
799*c8dee2aaSAndroid Build Coastguard Worker this->initializeObjects();
800*c8dee2aaSAndroid Build Coastguard Worker }
801*c8dee2aaSAndroid Build Coastguard Worker
802*c8dee2aaSAndroid Build Coastguard Worker ~BouncingTaggedImagesStage() override = default;
803*c8dee2aaSAndroid Build Coastguard Worker
initImages(SkCanvas * canvas)804*c8dee2aaSAndroid Build Coastguard Worker void initImages(SkCanvas* canvas) {
805*c8dee2aaSAndroid Build Coastguard Worker const char* kImageSrcs[kImageCount] = {
806*c8dee2aaSAndroid Build Coastguard Worker "images/brickwork-texture.jpg",
807*c8dee2aaSAndroid Build Coastguard Worker "images/dog.jpg",
808*c8dee2aaSAndroid Build Coastguard Worker "images/color_wheel.jpg",
809*c8dee2aaSAndroid Build Coastguard Worker "images/mandrill_512_q075.jpg",
810*c8dee2aaSAndroid Build Coastguard Worker "images/flutter_logo.jpg",
811*c8dee2aaSAndroid Build Coastguard Worker };
812*c8dee2aaSAndroid Build Coastguard Worker
813*c8dee2aaSAndroid Build Coastguard Worker auto rContext = canvas->recordingContext();
814*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
815*c8dee2aaSAndroid Build Coastguard Worker skgpu::graphite::Recorder* recorder = nullptr;
816*c8dee2aaSAndroid Build Coastguard Worker recorder = canvas->recorder();
817*c8dee2aaSAndroid Build Coastguard Worker #endif
818*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kImageCount; ++i) {
819*c8dee2aaSAndroid Build Coastguard Worker auto lazyYUV = sk_gpu_test::LazyYUVImage::Make(GetResourceAsData(kImageSrcs[i]),
820*c8dee2aaSAndroid Build Coastguard Worker skgpu::Mipmapped::kYes);
821*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(lazyYUV);
822*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
823*c8dee2aaSAndroid Build Coastguard Worker if (recorder) {
824*c8dee2aaSAndroid Build Coastguard Worker fImages[i] = lazyYUV->refImage(recorder,
825*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::LazyYUVImage::Type::kFromPixmaps);
826*c8dee2aaSAndroid Build Coastguard Worker } else
827*c8dee2aaSAndroid Build Coastguard Worker #endif
828*c8dee2aaSAndroid Build Coastguard Worker {
829*c8dee2aaSAndroid Build Coastguard Worker fImages[i] = lazyYUV->refImage(rContext,
830*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::LazyYUVImage::Type::kFromPixmaps);
831*c8dee2aaSAndroid Build Coastguard Worker }
832*c8dee2aaSAndroid Build Coastguard Worker }
833*c8dee2aaSAndroid Build Coastguard Worker }
834*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas)835*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas) override {
836*c8dee2aaSAndroid Build Coastguard Worker if (fNeedToInitImages) {
837*c8dee2aaSAndroid Build Coastguard Worker this->initImages(canvas);
838*c8dee2aaSAndroid Build Coastguard Worker fNeedToInitImages = false;
839*c8dee2aaSAndroid Build Coastguard Worker }
840*c8dee2aaSAndroid Build Coastguard Worker
841*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorWHITE);
842*c8dee2aaSAndroid Build Coastguard Worker
843*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
844*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions sampling(SkFilterMode::kLinear,
845*c8dee2aaSAndroid Build Coastguard Worker SkMipmapMode::kNearest);
846*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < fObjects.size(); ++i) {
847*c8dee2aaSAndroid Build Coastguard Worker BouncingTaggedImage* object = reinterpret_cast<BouncingTaggedImage*>(fObjects[i].get());
848*c8dee2aaSAndroid Build Coastguard Worker
849*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
850*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(object->transform());
851*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImageRect(fImages[i % kImageCount], object->rect(), sampling, nullptr);
852*c8dee2aaSAndroid Build Coastguard Worker
853*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
854*c8dee2aaSAndroid Build Coastguard Worker }
855*c8dee2aaSAndroid Build Coastguard Worker }
856*c8dee2aaSAndroid Build Coastguard Worker
createObject()857*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<MMObject> createObject() override {
858*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<BouncingTaggedImage>(&fRandom, fSize, fParticleSize, fMaxVelocity);
859*c8dee2aaSAndroid Build Coastguard Worker }
860*c8dee2aaSAndroid Build Coastguard Worker
reset()861*c8dee2aaSAndroid Build Coastguard Worker void reset() {
862*c8dee2aaSAndroid Build Coastguard Worker fNeedToInitImages = true;
863*c8dee2aaSAndroid Build Coastguard Worker }
864*c8dee2aaSAndroid Build Coastguard Worker
865*c8dee2aaSAndroid Build Coastguard Worker private:
866*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kImageCount = 5;
867*c8dee2aaSAndroid Build Coastguard Worker
868*c8dee2aaSAndroid Build Coastguard Worker bool fNeedToInitImages = true;
869*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImages[kImageCount];
870*c8dee2aaSAndroid Build Coastguard Worker };
871*c8dee2aaSAndroid Build Coastguard Worker
872*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
873*c8dee2aaSAndroid Build Coastguard Worker
874*c8dee2aaSAndroid Build Coastguard Worker class CanvasLinesSlide : public MotionMarkSlide {
875*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasLinesSlide()876*c8dee2aaSAndroid Build Coastguard Worker CanvasLinesSlide() {fName = "MotionMarkCanvasLines"; }
877*c8dee2aaSAndroid Build Coastguard Worker
load(SkScalar w,SkScalar h)878*c8dee2aaSAndroid Build Coastguard Worker void load(SkScalar w, SkScalar h) override {
879*c8dee2aaSAndroid Build Coastguard Worker fStage = std::make_unique<CanvasLineSegmentStage>(SkSize::Make(w, h));
880*c8dee2aaSAndroid Build Coastguard Worker }
881*c8dee2aaSAndroid Build Coastguard Worker };
882*c8dee2aaSAndroid Build Coastguard Worker
883*c8dee2aaSAndroid Build Coastguard Worker class CanvasArcsSlide : public MotionMarkSlide {
884*c8dee2aaSAndroid Build Coastguard Worker public:
CanvasArcsSlide()885*c8dee2aaSAndroid Build Coastguard Worker CanvasArcsSlide() {fName = "MotionMarkCanvasArcs"; }
886*c8dee2aaSAndroid Build Coastguard Worker
load(SkScalar w,SkScalar h)887*c8dee2aaSAndroid Build Coastguard Worker void load(SkScalar w, SkScalar h) override {
888*c8dee2aaSAndroid Build Coastguard Worker fStage = std::make_unique<CanvasArcStage>(SkSize::Make(w, h));
889*c8dee2aaSAndroid Build Coastguard Worker }
890*c8dee2aaSAndroid Build Coastguard Worker };
891*c8dee2aaSAndroid Build Coastguard Worker
892*c8dee2aaSAndroid Build Coastguard Worker class PathsSlide : public MotionMarkSlide {
893*c8dee2aaSAndroid Build Coastguard Worker public:
PathsSlide()894*c8dee2aaSAndroid Build Coastguard Worker PathsSlide() {fName = "MotionMarkPaths"; }
895*c8dee2aaSAndroid Build Coastguard Worker
load(SkScalar w,SkScalar h)896*c8dee2aaSAndroid Build Coastguard Worker void load(SkScalar w, SkScalar h) override {
897*c8dee2aaSAndroid Build Coastguard Worker fStage = std::make_unique<CanvasLinePathStage>(SkSize::Make(w, h));
898*c8dee2aaSAndroid Build Coastguard Worker }
899*c8dee2aaSAndroid Build Coastguard Worker };
900*c8dee2aaSAndroid Build Coastguard Worker
901*c8dee2aaSAndroid Build Coastguard Worker class BouncingTaggedImagesSlide : public MotionMarkSlide {
902*c8dee2aaSAndroid Build Coastguard Worker public:
BouncingTaggedImagesSlide()903*c8dee2aaSAndroid Build Coastguard Worker BouncingTaggedImagesSlide() {fName = "MotionMarkBouncingTaggedImages"; }
904*c8dee2aaSAndroid Build Coastguard Worker
load(SkScalar w,SkScalar h)905*c8dee2aaSAndroid Build Coastguard Worker void load(SkScalar w, SkScalar h) override {
906*c8dee2aaSAndroid Build Coastguard Worker fStage = std::make_unique<BouncingTaggedImagesStage>(SkSize::Make(w, h));
907*c8dee2aaSAndroid Build Coastguard Worker }
908*c8dee2aaSAndroid Build Coastguard Worker
gpuTeardown()909*c8dee2aaSAndroid Build Coastguard Worker void gpuTeardown() override {
910*c8dee2aaSAndroid Build Coastguard Worker if (fStage) {
911*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<BouncingTaggedImagesStage*>(fStage.get())->reset();
912*c8dee2aaSAndroid Build Coastguard Worker }
913*c8dee2aaSAndroid Build Coastguard Worker }
914*c8dee2aaSAndroid Build Coastguard Worker };
915*c8dee2aaSAndroid Build Coastguard Worker
916*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new CanvasLinesSlide(); )
917*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new CanvasArcsSlide(); )
918*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new PathsSlide(); )
919*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new BouncingTaggedImagesSlide(); )
920