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