mixercolorfilter.cpp 6.4 KB

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