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 8 #include "gm.h" 9 10 #include "SkLightingShader.h" 11 #include "SkPoint3.h" 12 #include "SkShader.h" 13 14 // Create a hemispherical normal map 15 static SkBitmap make_hemi_normalmap(int texSize) { 16 SkBitmap hemi; 17 hemi.allocN32Pixels(texSize, texSize); 18 19 sk_tool_utils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize)); 20 return hemi; 21 } 22 23 // Create a truncated pyramid normal map 24 static SkBitmap make_frustum_normalmap(int texSize) { 25 SkBitmap frustum; 26 frustum.allocN32Pixels(texSize, texSize); 27 28 sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize)); 29 return frustum; 30 } 31 32 // Create a tetrahedral normal map 33 static SkBitmap make_tetra_normalmap(int texSize) { 34 SkBitmap tetra; 35 tetra.allocN32Pixels(texSize, texSize); 36 37 sk_tool_utils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize)); 38 return tetra; 39 } 40 41 namespace skiagm { 42 43 // This GM exercises lighting shaders. 44 class LightingShaderGM : public GM { 45 public: 46 LightingShaderGM() { 47 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); 48 49 SkLightingShader::Lights::Builder builder; 50 51 builder.add(SkLight(SkColor3f::Make(1.0f, 1.0f, 1.0f), 52 SkVector3::Make(1.0f, 0.0f, 0.0f))); 53 builder.add(SkLight(SkColor3f::Make(0.2f, 0.2f, 0.2f))); 54 55 fLights.reset(builder.finish()); 56 } 57 58 protected: 59 enum NormalMap { 60 kHemi_NormalMap, 61 kFrustum_NormalMap, 62 kTetra_NormalMap, 63 64 kLast_NormalMap = kTetra_NormalMap 65 }; 66 67 static const int kNormalMapCount = kLast_NormalMap+1; 68 69 SkString onShortName() override { 70 return SkString("lightingshader"); 71 } 72 73 SkISize onISize() override { 74 return SkISize::Make(kGMSize, kGMSize); 75 } 76 77 void onOnceBeforeDraw() override { 78 fDiffuse = sk_tool_utils::create_checkerboard_bitmap( 79 kTexSize, kTexSize, 80 sk_tool_utils::color_to_565(0x0), 81 sk_tool_utils::color_to_565(0xFF804020), 82 8); 83 84 fNormalMaps[kHemi_NormalMap] = make_hemi_normalmap(kTexSize); 85 fNormalMaps[kFrustum_NormalMap] = make_frustum_normalmap(kTexSize); 86 fNormalMaps[kTetra_NormalMap] = make_tetra_normalmap(kTexSize); 87 } 88 89 void drawRect(SkCanvas* canvas, const SkRect& r, NormalMap mapType) { 90 91 SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height()); 92 93 SkMatrix matrix; 94 matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit); 95 96 const SkMatrix& ctm = canvas->getTotalMatrix(); 97 98 // TODO: correctly pull out the pure rotation 99 SkVector invNormRotation = { ctm[SkMatrix::kMScaleX], ctm[SkMatrix::kMSkewY] }; 100 101 SkAutoTUnref<SkShader> fShader(SkLightingShader::Create( 102 fDiffuse, 103 fNormalMaps[mapType], 104 fLights, 105 invNormRotation, &matrix, &matrix)); 106 107 SkPaint paint; 108 paint.setShader(fShader); 109 110 canvas->drawRect(r, paint); 111 } 112 113 void onDraw(SkCanvas* canvas) override { 114 SkMatrix m; 115 SkRect r; 116 117 { 118 r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize)); 119 this->drawRect(canvas, r, kHemi_NormalMap); 120 121 canvas->save(); 122 m.setRotate(45.0f, r.centerX(), r.centerY()); 123 m.postTranslate(kGMSize/2.0f - kTexSize/2.0f, 0.0f); 124 canvas->setMatrix(m); 125 this->drawRect(canvas, r, kHemi_NormalMap); 126 canvas->restore(); 127 } 128 129 { 130 r.offset(kGMSize - kTexSize, 0); 131 this->drawRect(canvas, r, kFrustum_NormalMap); 132 133 canvas->save(); 134 m.setRotate(45.0f, r.centerX(), r.centerY()); 135 m.postTranslate(0.0f, kGMSize/2.0f - kTexSize/2.0f); 136 canvas->setMatrix(m); 137 this->drawRect(canvas, r, kFrustum_NormalMap); 138 canvas->restore(); 139 } 140 141 { 142 r.offset(0, kGMSize - kTexSize); 143 this->drawRect(canvas, r, kTetra_NormalMap); 144 145 canvas->save(); 146 m.setRotate(45.0f, r.centerX(), r.centerY()); 147 m.postTranslate(-kGMSize/2.0f + kTexSize/2.0f, 0.0f); 148 canvas->setMatrix(m); 149 this->drawRect(canvas, r, kTetra_NormalMap); 150 canvas->restore(); 151 } 152 153 { 154 r.offset(kTexSize - kGMSize, 0); 155 this->drawRect(canvas, r, kHemi_NormalMap); 156 157 canvas->save(); 158 m.setRotate(45.0f, r.centerX(), r.centerY()); 159 m.postTranslate(0.0f, -kGMSize/2.0f + kTexSize/2.0f); 160 canvas->setMatrix(m); 161 this->drawRect(canvas, r, kHemi_NormalMap); 162 canvas->restore(); 163 } 164 } 165 166 private: 167 static const int kTexSize = 128; 168 static const int kGMSize = 512; 169 170 SkBitmap fDiffuse; 171 SkBitmap fNormalMaps[kNormalMapCount]; 172 173 SkAutoTUnref<const SkLightingShader::Lights> fLights; 174 175 typedef GM INHERITED; 176 }; 177 178 ////////////////////////////////////////////////////////////////////////////// 179 180 DEF_GM(return new LightingShaderGM;) 181 } 182