lightingshader2.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * Copyright 2016 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/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColor.h"
  11. #include "include/core/SkFont.h"
  12. #include "include/core/SkFontStyle.h"
  13. #include "include/core/SkMatrix.h"
  14. #include "include/core/SkPaint.h"
  15. #include "include/core/SkPoint3.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/SkTypeface.h"
  23. #include "src/core/SkNormalSource.h"
  24. #include "src/shaders/SkLightingShader.h"
  25. #include "src/shaders/SkLights.h"
  26. #include "tools/ToolUtils.h"
  27. #include <initializer_list>
  28. #include <utility>
  29. // Create a truncated pyramid normal map
  30. static SkBitmap make_frustum_normalmap(int texSize) {
  31. SkBitmap frustum;
  32. frustum.allocN32Pixels(texSize, texSize);
  33. ToolUtils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
  34. return frustum;
  35. }
  36. namespace skiagm {
  37. // This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using
  38. // normal maps, paint transparency, zero directional lights, multiple directional lights.
  39. class LightingShader2GM : public GM {
  40. public:
  41. LightingShader2GM() : fRect(SkRect::MakeIWH(kTexSize, kTexSize)) {
  42. this->setBGColor(ToolUtils::color_to_565(0xFF0000CC));
  43. }
  44. protected:
  45. SkString onShortName() override {
  46. return SkString("lightingshader2");
  47. }
  48. SkISize onISize() override {
  49. return SkISize::Make(600, 740);
  50. }
  51. void onOnceBeforeDraw() override {
  52. // The light direction is towards the light with +Z coming out of the screen
  53. const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f);
  54. const SkVector3 kLightFromUpperLeft = SkVector3::Make(-0.788f, 0.394f, 0.473f);
  55. // Standard set of lights
  56. {
  57. SkLights::Builder builder;
  58. builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
  59. kLightFromUpperRight));
  60. builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
  61. fLights = builder.finish();
  62. }
  63. // No directional lights
  64. {
  65. SkLights::Builder builder;
  66. builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
  67. fLightsNoDir = builder.finish();
  68. }
  69. // Two directional lights
  70. {
  71. SkLights::Builder builder;
  72. builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 0.0f, 0.0f),
  73. kLightFromUpperRight));
  74. builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.0f, 1.0f, 0.0f),
  75. kLightFromUpperLeft));
  76. builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
  77. fLightsTwoDir = builder.finish();
  78. }
  79. SkMatrix matrix;
  80. SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize);
  81. matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit);
  82. SkBitmap opaqueDiffuseMap = ToolUtils::create_checkerboard_bitmap(
  83. kTexSize, kTexSize, SK_ColorBLACK, 0xFF808080, 8);
  84. fOpaqueDiffuse = opaqueDiffuseMap.makeShader(&matrix);
  85. SkBitmap translucentDiffuseMap =
  86. ToolUtils::create_checkerboard_bitmap(kTexSize,
  87. kTexSize,
  88. SkColorSetARGB(0x55, 0x00, 0x00, 0x00),
  89. SkColorSetARGB(0x55, 0x80, 0x80, 0x80),
  90. 8);
  91. fTranslucentDiffuse = translucentDiffuseMap.makeShader(&matrix);
  92. SkBitmap normalMap = make_frustum_normalmap(kTexSize);
  93. fNormalMapShader = normalMap.makeShader(&matrix);
  94. }
  95. // Scales shape around origin, rotates shape around origin, then translates shape to origin
  96. void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const {
  97. canvas->translate(kTexSize/2.0f, kTexSize/2.0f);
  98. canvas->scale(scaleX, scaleY);
  99. canvas->rotate(rotate);
  100. canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f);
  101. }
  102. void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY,
  103. SkScalar rotate, bool useNormalSource, bool useDiffuseShader,
  104. bool useTranslucentPaint, bool useTranslucentShader, sk_sp<SkLights> lights) {
  105. canvas->save();
  106. this->positionCTM(canvas, scaleX, scaleY, rotate);
  107. const SkMatrix& ctm = canvas->getTotalMatrix();
  108. SkPaint paint;
  109. sk_sp<SkNormalSource> normalSource = nullptr;
  110. sk_sp<SkShader> diffuseShader = nullptr;
  111. if (useNormalSource) {
  112. normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm);
  113. }
  114. if (useDiffuseShader) {
  115. diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse;
  116. } else {
  117. paint.setColor(SK_ColorGREEN);
  118. }
  119. if (useTranslucentPaint) {
  120. paint.setAlpha(0x99);
  121. }
  122. paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
  123. std::move(lights)));
  124. canvas->drawRect(fRect, paint);
  125. canvas->restore();
  126. }
  127. void onDraw(SkCanvas* canvas) override {
  128. SkPaint labelPaint;
  129. SkFont font(ToolUtils::create_portable_typeface("sans-serif", SkFontStyle()), kLabelSize);
  130. int gridNum = 0;
  131. // Running through all possible bool parameter combinations
  132. for (bool useNormalSource : {true, false}) {
  133. for (bool useDiffuseShader : {true, false}) {
  134. for (bool useTranslucentPaint : {true, false}) {
  135. for (bool useTranslucentShader : {true, false}) {
  136. // Determining position
  137. SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
  138. SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
  139. canvas->save();
  140. canvas->translate(xPos, yPos);
  141. this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader,
  142. useTranslucentPaint, useTranslucentShader, fLights);
  143. // Drawing labels
  144. canvas->translate(0.0f, SkIntToScalar(kTexSize));
  145. {
  146. canvas->translate(0.0f, kLabelSize);
  147. SkString label;
  148. label.appendf("useNormalSource: %d", useNormalSource);
  149. canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
  150. }
  151. {
  152. canvas->translate(0.0f, kLabelSize);
  153. SkString label;
  154. label.appendf("useDiffuseShader: %d", useDiffuseShader);
  155. canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
  156. }
  157. {
  158. canvas->translate(0.0f, kLabelSize);
  159. SkString label;
  160. label.appendf("useTranslucentPaint: %d", useTranslucentPaint);
  161. canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
  162. }
  163. {
  164. canvas->translate(0.0f, kLabelSize);
  165. SkString label;
  166. label.appendf("useTranslucentShader: %d", useTranslucentShader);
  167. canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
  168. }
  169. canvas->restore();
  170. gridNum++;
  171. }
  172. }
  173. }
  174. }
  175. // Rotation/scale test
  176. {
  177. SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
  178. SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
  179. canvas->save();
  180. canvas->translate(xPos, yPos);
  181. this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true, fLights);
  182. canvas->restore();
  183. gridNum++;
  184. }
  185. // Anisotropic scale test
  186. {
  187. SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
  188. SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
  189. canvas->save();
  190. canvas->translate(xPos, yPos);
  191. this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true, fLights);
  192. canvas->restore();
  193. gridNum++;
  194. }
  195. // No directional lights test
  196. {
  197. SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
  198. SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
  199. canvas->save();
  200. canvas->translate(xPos, yPos);
  201. this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsNoDir);
  202. canvas->restore();
  203. gridNum++;
  204. }
  205. // Two directional lights test
  206. {
  207. SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
  208. SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
  209. canvas->save();
  210. canvas->translate(xPos, yPos);
  211. this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsTwoDir);
  212. canvas->restore();
  213. gridNum++;
  214. }
  215. }
  216. private:
  217. static constexpr int kTexSize = 96;
  218. static constexpr int kNumBooleanParams = 4;
  219. static constexpr SkScalar kLabelSize = 10.0f;
  220. static constexpr int kGridColumnNum = 4;
  221. static constexpr SkScalar kGridCellWidth = kTexSize + 20.0f + kNumBooleanParams * kLabelSize;
  222. sk_sp<SkShader> fOpaqueDiffuse;
  223. sk_sp<SkShader> fTranslucentDiffuse;
  224. sk_sp<SkShader> fNormalMapShader;
  225. const SkRect fRect;
  226. sk_sp<SkLights> fLights;
  227. sk_sp<SkLights> fLightsNoDir;
  228. sk_sp<SkLights> fLightsTwoDir;
  229. typedef GM INHERITED;
  230. };
  231. //////////////////////////////////////////////////////////////////////////////
  232. DEF_GM(return new LightingShader2GM;)
  233. }