| /* |
| * Copyright 2014 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/SkCanvas.h" |
| #include "include/core/SkColor.h" |
| #include "include/core/SkColorFilter.h" |
| #include "include/core/SkPaint.h" |
| #include "include/core/SkPoint.h" |
| #include "include/core/SkRect.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkShader.h" |
| #include "include/core/SkSize.h" |
| #include "include/core/SkString.h" |
| #include "include/core/SkTileMode.h" |
| #include "include/core/SkTypes.h" |
| #include "include/effects/SkGradientShader.h" |
| #include "tools/Resources.h" |
| |
| #include <vector> |
| #include <tuple> |
| |
| static sk_sp<SkShader> make_shader(const SkRect& bounds) { |
| const SkPoint pts[] = { |
| { bounds.left(), bounds.top() }, |
| { bounds.right(), bounds.bottom() }, |
| }; |
| const SkColor colors[] = { |
| SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK, |
| SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW, |
| }; |
| return SkGradientShader::MakeLinear(pts, colors, nullptr, std::size(colors), |
| SkTileMode::kClamp); |
| } |
| |
| typedef void (*InstallPaint)(SkPaint*, uint32_t, uint32_t); |
| |
| static void install_nothing(SkPaint* paint, uint32_t, uint32_t) { |
| paint->setColorFilter(nullptr); |
| } |
| |
| static void install_lighting(SkPaint* paint, uint32_t mul, uint32_t add) { |
| paint->setColorFilter(SkColorFilters::Lighting(mul, add)); |
| } |
| |
| class ColorFiltersGM : public skiagm::GM { |
| SkString onShortName() override { return SkString("lightingcolorfilter"); } |
| |
| SkISize onISize() override { return {620, 430}; } |
| |
| void onDraw(SkCanvas* canvas) override { |
| SkRect r = {0, 0, 600, 50}; |
| |
| SkPaint paint; |
| paint.setShader(make_shader(r)); |
| |
| const struct { |
| InstallPaint fProc; |
| uint32_t fData0, fData1; |
| } rec[] = { |
| { install_nothing, 0, 0 }, |
| { install_lighting, 0xFF0000, 0 }, |
| { install_lighting, 0x00FF00, 0 }, |
| { install_lighting, 0x0000FF, 0 }, |
| { install_lighting, 0x000000, 0xFF0000 }, |
| { install_lighting, 0x000000, 0x00FF00 }, |
| { install_lighting, 0x000000, 0x0000FF }, |
| }; |
| |
| canvas->translate(10, 10); |
| for (size_t i = 0; i < std::size(rec); ++i) { |
| rec[i].fProc(&paint, rec[i].fData0, rec[i].fData1); |
| canvas->drawRect(r, paint); |
| canvas->translate(0, r.height() + 10); |
| } |
| } |
| }; |
| |
| DEF_GM(return new ColorFiltersGM;) |
| |
| class HSLColorFilterGM : public skiagm::GM { |
| protected: |
| SkString onShortName() override { return SkString("hslcolorfilter"); } |
| |
| SkISize onISize() override { return { 840, 1100 }; } |
| |
| void onOnceBeforeDraw() override { |
| sk_sp<SkImage> mandrill = GetResourceAsImage("images/mandrill_256.png"); |
| const auto lm = SkMatrix::RectToRect(SkRect::MakeWH(mandrill->width(), mandrill->height()), |
| SkRect::MakeWH(kWheelSize, kWheelSize)); |
| fShaders.push_back(mandrill->makeShader(SkSamplingOptions(), &lm)); |
| |
| static constexpr SkColor gGrads[][4] = { |
| { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000 }, |
| { 0xdfc08040, 0xdf8040c0, 0xdf40c080, 0xdfc08040 }, |
| }; |
| |
| for (const auto& cols : gGrads) { |
| fShaders.push_back(SkGradientShader::MakeSweep(kWheelSize / 2, kWheelSize / 2, |
| cols, nullptr, std::size(cols), |
| SkTileMode::kRepeat, -90, 270, 0, |
| nullptr)); |
| } |
| } |
| |
| void onDraw(SkCanvas* canvas) override { |
| using std::make_tuple; |
| |
| static constexpr struct { |
| std::tuple<float, float> h, s, l; |
| } gTests[] = { |
| { make_tuple(-0.5f, 0.5f), make_tuple( 0.0f, 0.0f), make_tuple( 0.0f, 0.0f) }, |
| { make_tuple( 0.0f, 0.0f), make_tuple(-1.0f, 1.0f), make_tuple( 0.0f, 0.0f) }, |
| { make_tuple( 0.0f, 0.0f), make_tuple( 0.0f, 0.0f), make_tuple(-1.0f, 1.0f) }, |
| }; |
| |
| const auto rect = SkRect::MakeWH(kWheelSize, kWheelSize); |
| |
| canvas->drawColor(0xffcccccc); |
| SkPaint paint; |
| |
| for (const auto& shader : fShaders) { |
| paint.setShader(shader); |
| |
| for (const auto& tst: gTests) { |
| canvas->translate(0, kWheelSize * 0.1f); |
| |
| const auto dh = (std::get<1>(tst.h) - std::get<0>(tst.h)) / (kSteps - 1), |
| ds = (std::get<1>(tst.s) - std::get<0>(tst.s)) / (kSteps - 1), |
| dl = (std::get<1>(tst.l) - std::get<0>(tst.l)) / (kSteps - 1); |
| auto h = std::get<0>(tst.h), |
| s = std::get<0>(tst.s), |
| l = std::get<0>(tst.l); |
| { |
| SkAutoCanvasRestore acr(canvas, true); |
| for (size_t i = 0; i < kSteps; ++i) { |
| paint.setColorFilter(make_filter(h, s, l)); |
| canvas->translate(kWheelSize * 0.1f, 0); |
| canvas->drawRect(rect, paint); |
| canvas->translate(kWheelSize * 1.1f, 0); |
| h += dh; |
| s += ds; |
| l += dl; |
| } |
| } |
| canvas->translate(0, kWheelSize * 1.1f); |
| } |
| canvas->translate(0, kWheelSize * 0.1f); |
| } |
| } |
| |
| private: |
| inline static constexpr SkScalar kWheelSize = 100; |
| inline static constexpr size_t kSteps = 7; |
| |
| static sk_sp<SkColorFilter> make_filter(float h, float s, float l) { |
| // These are roughly AE semantics. |
| const auto h_bias = h, |
| h_scale = 1.0f, |
| s_bias = std::max(s, 0.0f), |
| s_scale = 1 - std::abs(s), |
| l_bias = std::max(l, 0.0f), |
| l_scale = 1 - std::abs(l); |
| |
| const float cm[20] = { |
| h_scale, 0, 0, 0, h_bias, |
| 0, s_scale, 0, 0, s_bias, |
| 0, 0, l_scale, 0, l_bias, |
| 0, 0, 0, 1, 0, |
| }; |
| |
| return SkColorFilters::HSLAMatrix(cm); |
| } |
| |
| std::vector<sk_sp<SkShader>> fShaders; |
| }; |
| |
| DEF_GM(return new HSLColorFilterGM;) |