| /* | |
| * 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/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/SkPathBuilder.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/SkGradient.h" | |
| #include "tools/DecodeUtils.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 getName() const override { | |
| SkString name; | |
| name.printf("persp_shaders_%s", | |
| fDoAA ? "aa" : "bw"); | |
| return name; | |
| } | |
| SkISize getISize() 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 SkColor4f colors[] = { | |
| SkColors::kRed, SkColors::kGreen, SkColors::kRed, SkColors::kGreen, SkColors::kRed | |
| }; | |
| constexpr SkScalar pos[] = { 0, 0.25f, 0.5f, 0.75f, SK_Scalar1 }; | |
| fLinearGrad1 = SkShaders::LinearGradient(pts1, {{colors, pos, SkTileMode::kClamp}, {}}); | |
| fLinearGrad2 = SkShaders::LinearGradient(pts2, {{colors, pos, SkTileMode::kClamp}, {}}); | |
| fPerspMatrix.reset(); | |
| fPerspMatrix.setPerspY(SK_Scalar1 / 50); | |
| fPath = SkPathBuilder() | |
| .moveTo(0, 0) | |
| .lineTo(0, SkIntToScalar(kCellSize)) | |
| .lineTo(kCellSize/2.0f, kCellSize/2.0f) | |
| .lineTo(SkIntToScalar(kCellSize), SkIntToScalar(kCellSize)) | |
| .lineTo(SkIntToScalar(kCellSize), 0) | |
| .close() | |
| .detach(); | |
| } | |
| 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->baseRecorder())) { | |
| 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)); | |
| this->drawRow(canvas, SkSamplingOptions::Aniso(16)); | |
| canvas->translate(0, SkIntToScalar(kCellSize)); | |
| } | |
| private: | |
| inline static constexpr int kCellSize = 50; | |
| inline static constexpr int kNumRows = 5; | |
| inline 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}; | |
| }; | |
| SkPathBuilder builder; | |
| for (int i = 0; i < 4; ++i) { | |
| SkPoint pts[6]; | |
| for (auto& p : pts) { | |
| p = rand_pt(); | |
| } | |
| builder.moveTo(pts[0]) | |
| .quadTo(pts[1], pts[2]) | |
| .quadTo(pts[3], pts[4]).lineTo(pts[5]); | |
| } | |
| return builder.detach(); | |
| } | |
| DEF_SIMPLE_GM(perspective_clip, canvas, 800, 800) { | |
| SkPath path = make_path(); | |
| auto shader = ToolUtils::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); | |
| } |