1 /* 2 * Copyright 2020 Google LLC 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 "gm/gm.h" 8 #include "include/core/SkCanvas.h" 9 #include "include/core/SkColor.h" 10 #include "include/core/SkImage.h" 11 #include "include/core/SkM44.h" 12 #include "include/core/SkMatrix.h" 13 #include "include/core/SkSurface.h" 14 #include "include/effects/SkGradientShader.h" 15 #include "tools/timer/TimeUtils.h" 16 17 // Adapted from https://codepen.io/adamdupuis/pen/qLYzqB 18 class CrBug224618GM : public skiagm::GM { 19 public: CrBug224618GM()20 CrBug224618GM() : fTime(0.f) {} 21 22 protected: onShortName()23 SkString onShortName() override { 24 return SkString("crbug_224618"); 25 } 26 onISize()27 SkISize onISize() override { 28 return SkISize::Make(kMaxVW, kMaxVW); 29 } 30 31 // This animates the FOV in viewer, to ensure the panorama covering rects are stable across 32 // a variety of perspective matrices onAnimate(double nanos)33 bool onAnimate(double nanos) override { 34 fTime = TimeUtils::Scaled(1e-9f * nanos, 0.5f); 35 return true; 36 } 37 onOnceBeforeDraw()38 void onOnceBeforeDraw() override { 39 static const SkColor kColors[2] = {SK_ColorTRANSPARENT, SkColorSetARGB(128, 255, 255, 255)}; 40 sk_sp<SkShader> gradient = SkGradientShader::MakeRadial( 41 {200.f, 200.f}, 25.f, kColors, nullptr, 2, SkTileMode::kMirror, 42 SkGradientShader::kInterpolateColorsInPremul_Flag, nullptr); 43 44 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(400, 400); 45 46 SkPaint bgPaint; 47 bgPaint.setShader(gradient); 48 surface->getCanvas()->drawPaint(bgPaint); 49 50 fCubeImage = surface->makeImageSnapshot(); 51 } 52 onDraw(SkCanvas * canvas)53 void onDraw(SkCanvas* canvas) override { 54 SkScalar viewportWidth = SkScalarMod(fTime, 10.f) / 10.f * (kMaxVW - kMinVW) + kMinVW; 55 SkScalar radius = viewportWidth / 2.f; // round? 56 // See https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/perspective 57 SkM44 proj{1.f, 0.f, 0.f, 0.f, 58 0.f, 1.f, 0.f, 0.f, 59 0.f, 0.f, 1.f, 0.f, 60 0.f, 0.f, -1.f / radius, 1.f}; 61 SkM44 zoom = SkM44::Translate(0.f, 0.f, radius); 62 SkM44 postZoom = SkM44::Translate(0.f, 0.f, -radius - 1.f); 63 SkM44 rotateHorizontal = SkM44::Rotate({0, 1, 0}, 2.356194490192345f); 64 65 // w in degrees will need to be converted to radians 66 SkV4 axisAngles[6] = { 67 {0.f, 1.f, 0.f, -90.f}, // rotateY(-90deg) 68 {1.f, 0.f, 0.f, 0.f}, // <none> 69 {0.f, 1.f, 0.f, 90.f}, // rotateY(90deg) 70 {0.f, 1.f, 0.f, 180.f}, // rotateY(180deg) 71 {1.f, 0.f, 0.f, -90.f}, // rotateX(-90deg) 72 {1.f, 0.f, 0.f, 90.f}, // rotateX(90deg) 73 }; 74 SkColor faceColors[6] = { 75 SK_ColorRED, 76 SK_ColorGREEN, 77 SK_ColorBLUE, 78 SK_ColorYELLOW, 79 SkColorSetARGB(0xFF, 0xFF, 0xA5, 0x00), // orange css 80 SkColorSetARGB(0xFF, 0x80, 0x00, 0x80) // purple css 81 }; 82 83 for (int i = 0; i < 6; ++i) { 84 SkM44 model = SkM44::Rotate({axisAngles[i].x, axisAngles[i].y, axisAngles[i].z}, 85 SkDegreesToRadians(axisAngles[i].w)); 86 model = SkM44::Translate(radius, radius) * proj * // project and place content 87 zoom * rotateHorizontal * model * postZoom * // main model matrix 88 SkM44::Translate(-radius, -radius); // center content 89 90 canvas->save(); 91 canvas->concat(model); 92 93 SkPaint fillPaint; 94 fillPaint.setAntiAlias(true); 95 fillPaint.setColor(faceColors[i]); 96 97 // Leverages FillRectOp on GPU backend 98 canvas->drawRect(SkRect::MakeWH(viewportWidth, viewportWidth), fillPaint); 99 100 // Leverages TextureOp on GPU backend, to ensure sure both quad paths handle clipping 101 canvas->drawImageRect(fCubeImage.get(), 102 SkRect::MakeWH(fCubeImage->width(), fCubeImage->height()), 103 SkRect::MakeWH(viewportWidth, viewportWidth), 104 SkSamplingOptions(SkFilterMode::kLinear), &fillPaint, 105 SkCanvas::kFast_SrcRectConstraint); 106 107 canvas->restore(); 108 } 109 } 110 private: 111 static const int kMaxVW = 800; 112 static const int kMinVW = 300; 113 114 SkScalar fTime; 115 sk_sp<SkImage> fCubeImage; 116 }; 117 118 DEF_GM(return new CrBug224618GM();) 119