• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 
8 #include "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPoint.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkScalar.h"
19 #include "include/core/SkShader.h"
20 #include "include/core/SkSize.h"
21 #include "include/core/SkString.h"
22 #include "include/core/SkTileMode.h"
23 #include "include/core/SkTypes.h"
24 #include "include/effects/SkGradientShader.h"
25 #include "include/effects/SkLumaColorFilter.h"
26 #include "tools/Resources.h"
27 
28 #include <math.h>
29 
30 // A tint filter maps colors to a given range (gradient), based on the input luminance:
31 //
32 //   c' = lerp(lo, hi, luma(c))
33 //
34 // TODO: move to public headers/API?
35 //
MakeTintColorFilter(SkColor lo,SkColor hi)36 static sk_sp<SkColorFilter> MakeTintColorFilter(SkColor lo, SkColor hi) {
37     const auto r_lo = SkColorGetR(lo),
38     g_lo = SkColorGetG(lo),
39     b_lo = SkColorGetB(lo),
40     a_lo = SkColorGetA(lo),
41     r_hi = SkColorGetR(hi),
42     g_hi = SkColorGetG(hi),
43     b_hi = SkColorGetB(hi),
44     a_hi = SkColorGetA(hi);
45 
46     // We map component-wise:
47     //
48     //   r' = lo.r + (hi.r - lo.r) * luma
49     //   g' = lo.g + (hi.g - lo.g) * luma
50     //   b' = lo.b + (hi.b - lo.b) * luma
51     //   a' = lo.a + (hi.a - lo.a) * luma
52     //
53     // The input luminance is stored in the alpha channel
54     // (and RGB are cleared -- see SkLumaColorFilter). Thus:
55     const float tint_matrix[] = {
56         0, 0, 0, (r_hi - r_lo) / 255.0f, SkIntToScalar(r_lo) / 255.0f,
57         0, 0, 0, (g_hi - g_lo) / 255.0f, SkIntToScalar(g_lo) / 255.0f,
58         0, 0, 0, (b_hi - b_lo) / 255.0f, SkIntToScalar(b_lo) / 255.0f,
59         0, 0, 0, (a_hi - a_lo) / 255.0f, SkIntToScalar(a_lo) / 255.0f,
60     };
61 
62     return SkColorFilters::Matrix(tint_matrix)
63     ->makeComposed(SkLumaColorFilter::Make());
64 }
65 
66 namespace {
67 
68 class MixerCFGM final : public skiagm::GM {
69 public:
MixerCFGM(const SkSize & tileSize,size_t tileCount)70     MixerCFGM(const SkSize& tileSize, size_t tileCount)
71         : fTileSize(tileSize)
72         , fTileCount(tileCount) {}
73 
74 protected:
onShortName()75     SkString onShortName() override {
76         return SkString("mixerCF");
77     }
78 
onISize()79     SkISize onISize() override {
80         return SkISize::Make(fTileSize.width()  * 1.2f * fTileCount,
81                              fTileSize.height() * 1.2f * 3);         // 3 rows
82     }
83 
onDraw(SkCanvas * canvas)84     void onDraw(SkCanvas* canvas) override {
85         SkPaint paint;
86 
87         const SkColor gradient_colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
88         paint.setShader(SkGradientShader::MakeSweep(fTileSize.width()  / 2,
89                                                     fTileSize.height() / 2,
90                                                     gradient_colors, nullptr,
91                                                     SK_ARRAY_COUNT(gradient_colors)));
92 
93         auto cf0 = MakeTintColorFilter(0xff300000, 0xffa00000);  // red tint
94         auto cf1 = MakeTintColorFilter(0xff003000, 0xff00a000);  // green tint
95 
96         this->mixRow(canvas, paint, nullptr,     cf1);
97         this->mixRow(canvas, paint,     cf0, nullptr);
98         this->mixRow(canvas, paint,     cf0,     cf1);
99     }
100 
101 private:
102     const SkSize fTileSize;
103     const size_t fTileCount;
104 
mixRow(SkCanvas * canvas,SkPaint & paint,sk_sp<SkColorFilter> cf0,sk_sp<SkColorFilter> cf1)105     void mixRow(SkCanvas* canvas, SkPaint& paint,
106                 sk_sp<SkColorFilter> cf0, sk_sp<SkColorFilter> cf1) {
107         canvas->translate(0, fTileSize.height() * 0.1f);
108         {
109             SkAutoCanvasRestore arc(canvas, true);
110             for (size_t i = 0; i < fTileCount; ++i) {
111                 paint.setColorFilter(
112                     SkColorFilters::Lerp(static_cast<float>(i) / (fTileCount - 1), cf0, cf1));
113                 canvas->translate(fTileSize.width() * 0.1f, 0);
114                 canvas->drawRect(SkRect::MakeWH(fTileSize.width(), fTileSize.height()), paint);
115                 canvas->translate(fTileSize.width() * 1.1f, 0);
116             }
117         }
118         canvas->translate(0, fTileSize.height() * 1.1f);
119     }
120 
121     using INHERITED = skiagm::GM;
122 };
123 
124 } // namespace
125 DEF_GM( return new MixerCFGM(SkSize::Make(200, 250), 5); )
126 
make_resource_shader(const char path[],int size)127 static sk_sp<SkShader> make_resource_shader(const char path[], int size) {
128     auto img = GetResourceAsImage(path);
129     if (!img) {
130         return nullptr;
131     }
132     SkRect src = SkRect::MakeIWH(img->width(), img->height());
133     SkRect dst = SkRect::MakeIWH(size, size);
134     SkMatrix m;
135     m.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
136     return img->makeShader(&m);
137 }
138 
make_grad(int size,float t)139 static sk_sp<SkShader> make_grad(int size, float t) {
140     SkASSERT(t >= 0 && t <= 1);
141     unsigned r = SkScalarRoundToInt(t * 255);
142     SkColor c = SkColorSetARGB(r, r, 0, 0);
143 
144     SkColor colors[] = { 0, c, SK_ColorRED };
145     SkPoint pts[] = {{0, 0}, {size*1.0f, size*1.0f}};
146     SkScalar pos[] = {0, 1 - t, 1.0f};
147     return SkGradientShader::MakeLinear(pts, colors, pos, SK_ARRAY_COUNT(colors),
148                                         SkTileMode::kClamp);
149 }
150 
151 class ShaderMixerGM final : public skiagm::GM {
152     enum { SIZE = 256 };
153     float fPos = 0.5f;
154     sk_sp<SkShader> fS0, fS1;
155 
156 public:
ShaderMixerGM()157     ShaderMixerGM() {}
158 
159 protected:
onShortName()160     SkString onShortName() override {
161         return SkString("mixershader_shadermixer");
162     }
163 
onOnceBeforeDraw()164     void onOnceBeforeDraw() override {
165         fS0 = make_resource_shader("images/mandrill_256.png", SIZE);
166         fS1 = make_resource_shader("images/baby_tux.png", SIZE);
167     }
168 
onISize()169     SkISize onISize() override { return {542, 542}; }
170 
onDraw(SkCanvas * canvas)171     void onDraw(SkCanvas* canvas) override {
172         SkRect r = SkRect::MakeIWH(SIZE, SIZE);
173 
174         SkPaint paint;
175 
176         canvas->translate(10, 10);
177 
178         canvas->save();
179         paint.setShader(fS0);
180         canvas->drawRect(r, paint);
181         canvas->translate(SIZE + 10.0f, 0);
182         paint.setShader(fS1);
183         canvas->drawRect(r, paint);
184         canvas->restore();
185 
186         auto sh2 = make_grad(SIZE, fPos);
187 
188         canvas->translate(0, SIZE + 10.0f);
189         paint.setShader(sh2);
190         canvas->drawRect(r, paint);
191 
192         auto sh = SkShaders::Lerp(sh2, fS0, fS1);
193         canvas->translate(SIZE + 10.0f, 0);
194         paint.setShader(sh);
195         canvas->drawRect(r, paint);
196     }
197 
onAnimate(double nanos)198     bool onAnimate(double nanos) override {
199         fPos = (sin(1e-9 * nanos) + 1) * 0.5f;
200         return true;
201     }
202 
203 private:
204     using INHERITED = skiagm::GM;
205 };
206 DEF_GM( return new ShaderMixerGM; )
207