blob: 0c88cf9f1953829ccf2f7aaba40279f57c54018e [file] [log] [blame]
Florin Malita346ce632019-02-16 22:12:59 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkColorFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040012#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "include/effects/SkGradientShader.h"
25#include "include/effects/SkLumaColorFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040026#include "tools/Resources.h"
Florin Malita346ce632019-02-16 22:12:59 -050027
Ben Wagner7fde8e12019-05-01 17:28:53 -040028#include <math.h>
29
Mike Reed05be23d2019-03-28 09:22:28 -060030// 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//
36static 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:
Mike Reede869a1e2019-04-30 12:18:54 -040055 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,
Mike Reed05be23d2019-03-28 09:22:28 -060060 };
61
Mike Reede869a1e2019-04-30 12:18:54 -040062 return SkColorFilters::Matrix(tint_matrix)
Mike Reed05be23d2019-03-28 09:22:28 -060063 ->makeComposed(SkLumaColorFilter::Make());
64}
65
Florin Malita346ce632019-02-16 22:12:59 -050066namespace {
67
68class MixerCFGM final : public skiagm::GM {
69public:
70 MixerCFGM(const SkSize& tileSize, size_t tileCount)
71 : fTileSize(tileSize)
72 , fTileCount(tileCount) {}
73
74protected:
75 SkString onShortName() override {
76 return SkString("mixerCF");
77 }
78
79 SkISize onISize() override {
80 return SkISize::Make(fTileSize.width() * 1.2f * fTileCount,
81 fTileSize.height() * 1.2f * 3); // 3 rows
82 }
83
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
101private:
102 const SkSize fTileSize;
103 const size_t fTileCount;
104
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(
Mike Reedb286bc22019-04-08 16:23:20 -0400112 SkColorFilters::Lerp(static_cast<float>(i) / (fTileCount - 1), cf0, cf1));
Florin Malita346ce632019-02-16 22:12:59 -0500113 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
Florin Malita346ce632019-02-16 22:12:59 -0500121 using INHERITED = skiagm::GM;
122};
123
124} // namespace
Florin Malita346ce632019-02-16 22:12:59 -0500125DEF_GM( return new MixerCFGM(SkSize::Make(200, 250), 5); )
Mike Reed79a75422019-03-15 15:45:09 -0400126
Mike Reed79a75422019-03-15 15:45:09 -0400127static 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
Mike Reede91825a2019-03-16 16:27:38 -0400139static 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 };
Mike Reed79a75422019-03-15 15:45:09 -0400145 SkPoint pts[] = {{0, 0}, {size*1.0f, size*1.0f}};
Mike Reede91825a2019-03-16 16:27:38 -0400146 SkScalar pos[] = {0, 1 - t, 1.0f};
147 return SkGradientShader::MakeLinear(pts, colors, pos, SK_ARRAY_COUNT(colors),
Mike Reedfae8fce2019-04-03 10:27:45 -0400148 SkTileMode::kClamp);
Mike Reed79a75422019-03-15 15:45:09 -0400149}
150
Mike Reede91825a2019-03-16 16:27:38 -0400151class ShaderMixerGM final : public skiagm::GM {
152 enum { SIZE = 256 };
153 float fPos = 0.5f;
154 sk_sp<SkShader> fS0, fS1;
Mike Reed79a75422019-03-15 15:45:09 -0400155
Mike Reede91825a2019-03-16 16:27:38 -0400156public:
157 ShaderMixerGM() {}
Mike Reed79a75422019-03-15 15:45:09 -0400158
Mike Reede91825a2019-03-16 16:27:38 -0400159protected:
160 SkString onShortName() override {
161 return SkString("mixershader_shadermixer");
162 }
Mike Reed79a75422019-03-15 15:45:09 -0400163
Mike Reede91825a2019-03-16 16:27:38 -0400164 void onOnceBeforeDraw() override {
165 fS0 = make_resource_shader("images/mandrill_256.png", SIZE);
166 fS1 = make_resource_shader("images/baby_tux.png", SIZE);
167 }
Mike Reed79a75422019-03-15 15:45:09 -0400168
Mike Reede91825a2019-03-16 16:27:38 -0400169 SkISize onISize() override { return {542, 542}; }
Mike Reed79a75422019-03-15 15:45:09 -0400170
Mike Reede91825a2019-03-16 16:27:38 -0400171 void onDraw(SkCanvas* canvas) override {
172 SkRect r = SkRect::MakeIWH(SIZE, SIZE);
Mike Reed79a75422019-03-15 15:45:09 -0400173
Mike Reede91825a2019-03-16 16:27:38 -0400174 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
Mike Reedc8bea7d2019-04-09 13:55:36 -0400192 auto sh = SkShaders::Lerp(sh2, fS0, fS1);
Mike Reede91825a2019-03-16 16:27:38 -0400193 canvas->translate(SIZE + 10.0f, 0);
194 paint.setShader(sh);
195 canvas->drawRect(r, paint);
196 }
197
Hal Canary41248072019-07-11 16:32:53 -0400198 bool onAnimate(double nanos) override {
199 fPos = (sin(1e-9 * nanos) + 1) * 0.5f;
Mike Reede91825a2019-03-16 16:27:38 -0400200 return true;
201 }
202
203private:
204 using INHERITED = skiagm::GM;
205};
206DEF_GM( return new ShaderMixerGM; )