| /* | 
 |  * Copyright 2015 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "gm/gm.h" | 
 | #include "include/core/SkBitmap.h" | 
 | #include "include/core/SkCanvas.h" | 
 | #include "include/core/SkColor.h" | 
 | #include "include/core/SkFilterQuality.h" | 
 | #include "include/core/SkImage.h" | 
 | #include "include/core/SkImageInfo.h" | 
 | #include "include/core/SkMatrix.h" | 
 | #include "include/core/SkPaint.h" | 
 | #include "include/core/SkPath.h" | 
 | #include "include/core/SkPoint.h" | 
 | #include "include/core/SkRect.h" | 
 | #include "include/core/SkRefCnt.h" | 
 | #include "include/core/SkScalar.h" | 
 | #include "include/core/SkShader.h" | 
 | #include "include/core/SkSize.h" | 
 | #include "include/core/SkString.h" | 
 | #include "include/core/SkSurface.h" | 
 | #include "include/core/SkTileMode.h" | 
 | #include "include/core/SkTypes.h" | 
 | #include "include/effects/SkGradientShader.h" | 
 | #include "tools/ToolUtils.h" | 
 |  | 
 | static sk_sp<SkImage> make_image(SkCanvas* origCanvas, int w, int h) { | 
 |     SkImageInfo info = SkImageInfo::MakeN32Premul(w, h); | 
 |     auto        surface(ToolUtils::makeSurface(origCanvas, info)); | 
 |     SkCanvas* canvas = surface->getCanvas(); | 
 |  | 
 |     ToolUtils::draw_checkerboard(canvas, SK_ColorRED, SK_ColorGREEN, w / 10); | 
 |     return surface->makeImageSnapshot(); | 
 | } | 
 |  | 
 | namespace skiagm { | 
 |  | 
 | class PerspShadersGM : public GM { | 
 | public: | 
 |     PerspShadersGM(bool doAA) : fDoAA(doAA) { } | 
 |  | 
 | protected: | 
 |     SkString onShortName() override { | 
 |         SkString name; | 
 |         name.printf("persp_shaders_%s", | 
 |                      fDoAA ? "aa" : "bw"); | 
 |         return name; | 
 |     } | 
 |  | 
 |     SkISize onISize() override { | 
 |         return SkISize::Make(kCellSize*kNumCols, kCellSize*kNumRows); | 
 |     } | 
 |  | 
 |     void onOnceBeforeDraw() override { | 
 |         fBitmapImage = ToolUtils::create_checkerboard_image( | 
 |                 kCellSize, kCellSize, SK_ColorBLUE, SK_ColorYELLOW, kCellSize / 10); | 
 |  | 
 |         SkPoint pts1[] = { | 
 |             { 0, 0 }, | 
 |             { SkIntToScalar(kCellSize), SkIntToScalar(kCellSize) } | 
 |         }; | 
 |         SkPoint pts2[] = { | 
 |             { 0, 0 }, | 
 |             { 0, SkIntToScalar(kCellSize) } | 
 |         }; | 
 |         constexpr SkColor colors[] = { | 
 |             SK_ColorRED, SK_ColorGREEN, SK_ColorRED, SK_ColorGREEN, SK_ColorRED | 
 |         }; | 
 |         constexpr SkScalar pos[] = { 0, 0.25f, 0.5f, 0.75f, SK_Scalar1 }; | 
 |  | 
 |         fLinearGrad1 = SkGradientShader::MakeLinear(pts1, colors, pos, SK_ARRAY_COUNT(colors), | 
 |                                                     SkTileMode::kClamp); | 
 |         fLinearGrad2 = SkGradientShader::MakeLinear(pts2, colors, pos, SK_ARRAY_COUNT(colors), | 
 |                                                     SkTileMode::kClamp); | 
 |  | 
 |         fPerspMatrix.reset(); | 
 |         fPerspMatrix.setPerspY(SK_Scalar1 / 50); | 
 |  | 
 |         fPath.moveTo(0, 0); | 
 |         fPath.lineTo(0, SkIntToScalar(kCellSize)); | 
 |         fPath.lineTo(kCellSize/2.0f, kCellSize/2.0f); | 
 |         fPath.lineTo(SkIntToScalar(kCellSize), SkIntToScalar(kCellSize)); | 
 |         fPath.lineTo(SkIntToScalar(kCellSize), 0); | 
 |         fPath.close(); | 
 |     } | 
 |  | 
 |     void drawRow(SkCanvas* canvas, const SkSamplingOptions& sampling) { | 
 |         SkPaint filterPaint; | 
 |         filterPaint.setAntiAlias(fDoAA); | 
 |  | 
 |         SkPaint pathPaint; | 
 |         pathPaint.setShader(fBitmapImage->makeShader(sampling)); | 
 |         pathPaint.setAntiAlias(fDoAA); | 
 |  | 
 |         SkPaint gradPaint1; | 
 |         gradPaint1.setShader(fLinearGrad1); | 
 |         gradPaint1.setAntiAlias(fDoAA); | 
 |         SkPaint gradPaint2; | 
 |         gradPaint2.setShader(fLinearGrad2); | 
 |         gradPaint2.setAntiAlias(fDoAA); | 
 |  | 
 |         SkRect r = SkRect::MakeWH(SkIntToScalar(kCellSize), SkIntToScalar(kCellSize)); | 
 |  | 
 |         canvas->save(); | 
 |  | 
 |         canvas->save(); | 
 |         canvas->concat(fPerspMatrix); | 
 |         canvas->drawImageRect(fBitmapImage, r, sampling, &filterPaint); | 
 |         canvas->restore(); | 
 |  | 
 |         canvas->translate(SkIntToScalar(kCellSize), 0); | 
 |         canvas->save(); | 
 |         canvas->concat(fPerspMatrix); | 
 |         canvas->drawImage(fImage.get(), 0, 0, sampling, &filterPaint); | 
 |         canvas->restore(); | 
 |  | 
 |         canvas->translate(SkIntToScalar(kCellSize), 0); | 
 |         canvas->save(); | 
 |         canvas->concat(fPerspMatrix); | 
 |         canvas->drawRect(r, pathPaint); | 
 |         canvas->restore(); | 
 |  | 
 |         canvas->translate(SkIntToScalar(kCellSize), 0); | 
 |         canvas->save(); | 
 |         canvas->concat(fPerspMatrix); | 
 |         canvas->drawPath(fPath, pathPaint); | 
 |         canvas->restore(); | 
 |  | 
 |         canvas->translate(SkIntToScalar(kCellSize), 0); | 
 |         canvas->save(); | 
 |         canvas->concat(fPerspMatrix); | 
 |         canvas->drawRect(r, gradPaint1); | 
 |         canvas->restore(); | 
 |  | 
 |         canvas->translate(SkIntToScalar(kCellSize), 0); | 
 |         canvas->save(); | 
 |         canvas->concat(fPerspMatrix); | 
 |         canvas->drawPath(fPath, gradPaint2); | 
 |         canvas->restore(); | 
 |  | 
 |         canvas->restore(); | 
 |     } | 
 |  | 
 |     void onDraw(SkCanvas* canvas) override { | 
 |         if (!fImage || !fImage->isValid(canvas->recordingContext())) { | 
 |             fImage = make_image(canvas, kCellSize, kCellSize); | 
 |         } | 
 |  | 
 |         this->drawRow(canvas, SkSamplingOptions(SkFilterMode::kNearest)); | 
 |         canvas->translate(0, SkIntToScalar(kCellSize)); | 
 |         this->drawRow(canvas, SkSamplingOptions(SkFilterMode::kLinear)); | 
 |         canvas->translate(0, SkIntToScalar(kCellSize)); | 
 |         this->drawRow(canvas, SkSamplingOptions(SkFilterMode::kLinear, | 
 |                                                 SkMipmapMode::kNearest)); | 
 |         canvas->translate(0, SkIntToScalar(kCellSize)); | 
 |         this->drawRow(canvas, SkSamplingOptions(SkCubicResampler::Mitchell())); | 
 |         canvas->translate(0, SkIntToScalar(kCellSize)); | 
 |     } | 
 | private: | 
 |     static constexpr int kCellSize = 50; | 
 |     static constexpr int kNumRows = 4; | 
 |     static constexpr int kNumCols = 6; | 
 |  | 
 |     bool            fDoAA; | 
 |     SkPath          fPath; | 
 |     sk_sp<SkShader> fLinearGrad1; | 
 |     sk_sp<SkShader> fLinearGrad2; | 
 |     SkMatrix        fPerspMatrix; | 
 |     sk_sp<SkImage>  fImage; | 
 |     sk_sp<SkImage>  fBitmapImage; | 
 |  | 
 |     using INHERITED = GM; | 
 | }; | 
 | DEF_GM(return new PerspShadersGM(true);) | 
 | DEF_GM(return new PerspShadersGM(false);) | 
 | }  // namespace skiagm | 
 |  | 
 | ////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | #include "tools/Resources.h" | 
 |  | 
 | static SkPath make_path() { | 
 |     SkRandom rand; | 
 |     auto rand_pt = [&rand]() { | 
 |         auto x = rand.nextF(); | 
 |         auto y = rand.nextF(); | 
 |         return SkPoint{x * 400, y * 400}; | 
 |     }; | 
 |  | 
 |     SkPath path; | 
 |     for (int i = 0; i < 4; ++i) { | 
 |         SkPoint pts[6]; | 
 |         for (auto& p : pts) { | 
 |             p = rand_pt(); | 
 |         } | 
 |         path.moveTo(pts[0]).quadTo(pts[1], pts[2]).quadTo(pts[3], pts[4]).lineTo(pts[5]); | 
 |     } | 
 |     return path; | 
 | } | 
 |  | 
 | DEF_SIMPLE_GM(perspective_clip, canvas, 800, 800) { | 
 |     SkPath path = make_path(); | 
 |     auto shader = GetResourceAsImage("images/mandrill_128.png") | 
 |                                     ->makeShader(SkSamplingOptions(), SkMatrix::Scale(3, 3)); | 
 |  | 
 |     SkPaint paint; | 
 |     paint.setColor({0.75, 0.75, 0.75, 1}); | 
 |     canvas->drawPath(path, paint); | 
 |  | 
 |     // This is a crazy perspective matrix, derived from halfplanes3, to draw a shape where | 
 |     // part of it is "behind" the viewer, hence showing the need for "half-plane" clipping | 
 |     // when in perspective. | 
 |     SkMatrix mx; | 
 |     const SkScalar array[] = { | 
 |         -1.7866f,  1.3357f, 273.0295f, | 
 |         -1.0820f,  1.3186f, 135.5196f, | 
 |         -0.0047f, -0.0015f,  2.1485f, | 
 |     }; | 
 |     mx.set9(array); | 
 |  | 
 |     paint.setShader(shader); | 
 |     canvas->concat(mx); | 
 |     canvas->drawPath(path, paint); | 
 | } |