lightingshader.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright 2015 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/SkMatrix.h"
  11. #include "include/core/SkPaint.h"
  12. #include "include/core/SkPoint.h"
  13. #include "include/core/SkPoint3.h"
  14. #include "include/core/SkRect.h"
  15. #include "include/core/SkRefCnt.h"
  16. #include "include/core/SkScalar.h"
  17. #include "include/core/SkShader.h"
  18. #include "include/core/SkSize.h"
  19. #include "include/core/SkString.h"
  20. #include "src/core/SkNormalSource.h"
  21. #include "src/shaders/SkLightingShader.h"
  22. #include "src/shaders/SkLights.h"
  23. #include "tools/ToolUtils.h"
  24. #include <utility>
  25. // Create a hemispherical normal map
  26. static SkBitmap make_hemi_normalmap(int texSize) {
  27. SkBitmap hemi;
  28. hemi.allocN32Pixels(texSize, texSize);
  29. ToolUtils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize));
  30. return hemi;
  31. }
  32. // Create a truncated pyramid normal map
  33. static SkBitmap make_frustum_normalmap(int texSize) {
  34. SkBitmap frustum;
  35. frustum.allocN32Pixels(texSize, texSize);
  36. ToolUtils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
  37. return frustum;
  38. }
  39. // Create a tetrahedral normal map
  40. static SkBitmap make_tetra_normalmap(int texSize) {
  41. SkBitmap tetra;
  42. tetra.allocN32Pixels(texSize, texSize);
  43. ToolUtils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize));
  44. return tetra;
  45. }
  46. namespace skiagm {
  47. // This GM exercises lighting shaders by drawing rotated and non-rotated normal mapped rects with
  48. // a directional light off to the viewers right.
  49. class LightingShaderGM : public GM {
  50. public:
  51. LightingShaderGM() {
  52. this->setBGColor(0xFFCCCCCC);
  53. }
  54. protected:
  55. enum NormalMap {
  56. kHemi_NormalMap,
  57. kFrustum_NormalMap,
  58. kTetra_NormalMap,
  59. kLast_NormalMap = kTetra_NormalMap
  60. };
  61. static constexpr int kNormalMapCount = kLast_NormalMap+1;
  62. SkString onShortName() override { return SkString("lightingshader"); }
  63. SkISize onISize() override { return SkISize::Make(kGMSize, kGMSize); }
  64. void onOnceBeforeDraw() override {
  65. {
  66. SkLights::Builder builder;
  67. // The direction vector is towards the light w/ +Z coming out of the screen
  68. builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
  69. SkVector3::Make(SK_ScalarRoot2Over2,
  70. 0.0f,
  71. SK_ScalarRoot2Over2)));
  72. builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
  73. fLights = builder.finish();
  74. }
  75. fDiffuse = ToolUtils::create_checkerboard_bitmap(
  76. kTexSize, kTexSize, 0x00000000, ToolUtils::color_to_565(0xFF804020), 8);
  77. fNormalMaps[kHemi_NormalMap] = make_hemi_normalmap(kTexSize);
  78. fNormalMaps[kFrustum_NormalMap] = make_frustum_normalmap(kTexSize);
  79. fNormalMaps[kTetra_NormalMap] = make_tetra_normalmap(kTexSize);
  80. }
  81. void drawRect(SkCanvas* canvas, const SkRect& r, NormalMap mapType) {
  82. SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height());
  83. SkMatrix matrix;
  84. matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
  85. const SkMatrix& ctm = canvas->getTotalMatrix();
  86. SkPaint paint;
  87. sk_sp<SkShader> diffuseShader = fDiffuse.makeShader(&matrix);
  88. sk_sp<SkShader> normalMap = fNormalMaps[mapType].makeShader(&matrix);
  89. sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap),
  90. ctm);
  91. paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
  92. fLights));
  93. canvas->drawRect(r, paint);
  94. }
  95. // Draw an axis-aligned and rotated version of the normal mapped rect
  96. void drawPair(SkCanvas* canvas, const SkRect& r, NormalMap mapType, const SkVector& v) {
  97. SkMatrix m;
  98. m.setRotate(45.0f, r.centerX(), r.centerY());
  99. m.postTranslate(kScale * v.fX, kScale * v.fY);
  100. this->drawRect(canvas, r, mapType);
  101. canvas->save();
  102. canvas->setMatrix(m);
  103. this->drawRect(canvas, r, mapType);
  104. canvas->restore();
  105. }
  106. void onDraw(SkCanvas* canvas) override {
  107. SkRect r;
  108. r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
  109. this->drawPair(canvas, r, kHemi_NormalMap, SkVector::Make(1.0f, 0.0f));
  110. r.offset(kGMSize - kTexSize, 0);
  111. this->drawPair(canvas, r, kFrustum_NormalMap, SkVector::Make(0.0f, 1.0f));
  112. r.offset(0, kGMSize - kTexSize);
  113. this->drawPair(canvas, r, kTetra_NormalMap, SkVector::Make(-1.0, 0.0f));
  114. r.offset(kTexSize - kGMSize, 0);
  115. this->drawPair(canvas, r, kHemi_NormalMap, SkVector::Make(0.0f, -1));
  116. }
  117. private:
  118. static constexpr int kTexSize = 128;
  119. static constexpr int kGMSize = 512;
  120. static constexpr SkScalar kScale = kGMSize/2.0f - kTexSize/2.0f;
  121. SkBitmap fDiffuse;
  122. SkBitmap fNormalMaps[kNormalMapCount];
  123. sk_sp<SkLights> fLights;
  124. typedef GM INHERITED;
  125. };
  126. //////////////////////////////////////////////////////////////////////////////
  127. DEF_GM(return new LightingShaderGM;)
  128. }