lightingshader2.cpp revision 84cddf6fa7a2ee4a8163f99c9238d5fba6b49566
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 8#include "gm.h" 9#include "SkLightingShader.h" 10#include "SkNormalSource.h" 11#include "SkPoint3.h" 12#include "SkShader.h" 13 14// Create a truncated pyramid normal map 15static SkBitmap make_frustum_normalmap(int texSize) { 16 SkBitmap frustum; 17 frustum.allocN32Pixels(texSize, texSize); 18 19 sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize)); 20 return frustum; 21} 22 23namespace skiagm { 24 25// This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using 26// normal maps, paint transparency, zero directional lights, multiple directional lights. 27class LightingShader2GM : public GM { 28public: 29 LightingShader2GM() { 30 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); 31 } 32 33protected: 34 SkString onShortName() override { 35 return SkString("lightingshader2"); 36 } 37 38 SkISize onISize() override { 39 return SkISize::Make(600, 740); 40 } 41 42 void onOnceBeforeDraw() override { 43 const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f); 44 const SkVector3 kLightFromUpperLeft = SkVector3::Make(-0.788f, 0.394f, 0.473f); 45 46 // Standard set of lights 47 SkLights::Builder builder; 48 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f), 49 kLightFromUpperRight)); 50 builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.2f, 0.2f, 0.2f))); 51 fLights = builder.finish(); 52 53 // No directional lights 54 SkLights::Builder builderNoDir; 55 builderNoDir.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.2f, 0.2f, 0.2f))); 56 fLightsNoDir = builderNoDir.finish(); 57 58 // Two directional lights 59 SkLights::Builder builderTwoDir; 60 builderTwoDir.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 0.0f, 1.0f), 61 kLightFromUpperRight)); 62 builderTwoDir.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.0f, 1.0f, 1.0f), 63 kLightFromUpperLeft)); 64 builderTwoDir.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.2f, 0.2f, 0.2f))); 65 fLightsTwoDir = builderTwoDir.finish(); 66 67 fRect = SkRect::MakeIWH(kTexSize, kTexSize); 68 SkMatrix matrix; 69 SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize); 70 matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit); 71 72 SkBitmap opaqueDiffuseMap = sk_tool_utils::create_checkerboard_bitmap( 73 kTexSize, kTexSize, 74 sk_tool_utils::color_to_565(0x0), 75 sk_tool_utils::color_to_565(0xFF804020), 76 8); 77 fOpaqueDiffuse = SkShader::MakeBitmapShader(opaqueDiffuseMap, SkShader::kClamp_TileMode, 78 SkShader::kClamp_TileMode, &matrix); 79 80 SkBitmap translucentDiffuseMap = sk_tool_utils::create_checkerboard_bitmap( 81 kTexSize, kTexSize, 82 SkColorSetARGB(0x55, 0x00, 0x00, 0x00), 83 SkColorSetARGB(0x55, 0x80, 0x40, 0x20), 84 8); 85 fTranslucentDiffuse = SkShader::MakeBitmapShader(translucentDiffuseMap, 86 SkShader::kClamp_TileMode, 87 SkShader::kClamp_TileMode, &matrix); 88 89 SkBitmap normalMap = make_frustum_normalmap(kTexSize); 90 fNormalMapShader = SkShader::MakeBitmapShader(normalMap, SkShader::kClamp_TileMode, 91 SkShader::kClamp_TileMode, &matrix); 92 93 } 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 103 static constexpr int NUM_BOOLEAN_PARAMS = 4; 104 void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY, 105 SkScalar rotate, bool useNormalSource, bool useDiffuseShader, 106 bool useTranslucentPaint, bool useTranslucentShader, sk_sp<SkLights> lights) { 107 canvas->save(); 108 109 this->positionCTM(canvas, scaleX, scaleY, rotate); 110 111 const SkMatrix& ctm = canvas->getTotalMatrix(); 112 113 SkPaint paint; 114 sk_sp<SkNormalSource> normalSource = nullptr; 115 sk_sp<SkShader> diffuseShader = nullptr; 116 117 if (useNormalSource) { 118 normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm); 119 } 120 121 if (useDiffuseShader) { 122 diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse; 123 } else { 124 paint.setColor(0xFF00FF00); 125 } 126 127 if (useTranslucentPaint) { 128 paint.setAlpha(0x99); 129 } 130 131 paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource), 132 std::move(lights))); 133 canvas->drawRect(fRect, paint); 134 135 canvas->restore(); 136 } 137 138 void onDraw(SkCanvas* canvas) override { 139 140 constexpr SkScalar LABEL_SIZE = 10.0f; 141 SkPaint labelPaint; 142 labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif", 143 SkFontStyle())); 144 labelPaint.setAntiAlias(true); 145 labelPaint.setTextSize(LABEL_SIZE); 146 147 constexpr int GRID_COLUMN_NUM = 4; 148 constexpr SkScalar GRID_CELL_WIDTH = kTexSize + 20.0f + NUM_BOOLEAN_PARAMS * LABEL_SIZE; 149 150 int gridNum = 0; 151 152 // Running through all possible bool parameter combinations 153 for (bool useNormalSource : {true, false}) { 154 for (bool useDiffuseShader : {true, false}) { 155 for (bool useTranslucentPaint : {true, false}) { 156 for (bool useTranslucentShader : {true, false}) { 157 158 // Determining position 159 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 160 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 161 162 canvas->save(); 163 164 canvas->translate(xPos, yPos); 165 this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader, 166 useTranslucentPaint, useTranslucentShader, fLights); 167 // Drawing labels 168 canvas->translate(0.0f, SkIntToScalar(kTexSize)); 169 { 170 canvas->translate(0.0f, LABEL_SIZE); 171 SkString label; 172 label.appendf("useNormalSource: %d", useNormalSource); 173 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 174 } 175 { 176 canvas->translate(0.0f, LABEL_SIZE); 177 SkString label; 178 label.appendf("useDiffuseShader: %d", useDiffuseShader); 179 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 180 } 181 { 182 canvas->translate(0.0f, LABEL_SIZE); 183 SkString label; 184 label.appendf("useTranslucentPaint: %d", useTranslucentPaint); 185 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 186 } 187 { 188 canvas->translate(0.0f, LABEL_SIZE); 189 SkString label; 190 label.appendf("useTranslucentShader: %d", useTranslucentShader); 191 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 192 } 193 194 canvas->restore(); 195 196 gridNum++; 197 } 198 } 199 } 200 } 201 202 203 // Rotation/scale test 204 { 205 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 206 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 207 208 canvas->save(); 209 canvas->translate(xPos, yPos); 210 this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true, fLights); 211 canvas->restore(); 212 213 gridNum++; 214 } 215 216 // Anisotropic scale test 217 { 218 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 219 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 220 221 canvas->save(); 222 canvas->translate(xPos, yPos); 223 this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true, fLights); 224 canvas->restore(); 225 226 gridNum++; 227 } 228 229 // No directional lights test 230 { 231 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 232 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 233 234 canvas->save(); 235 canvas->translate(xPos, yPos); 236 this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsNoDir); 237 canvas->restore(); 238 239 gridNum++; 240 } 241 242 // Two directional lights test 243 { 244 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 245 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 246 247 canvas->save(); 248 canvas->translate(xPos, yPos); 249 this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsTwoDir); 250 canvas->restore(); 251 252 gridNum++; 253 } 254 } 255 256private: 257 static const int kTexSize = 96; 258 259 sk_sp<SkShader> fOpaqueDiffuse; 260 sk_sp<SkShader> fTranslucentDiffuse; 261 sk_sp<SkShader> fNormalMapShader; 262 263 SkRect fRect; 264 sk_sp<SkLights> fLights; 265 sk_sp<SkLights> fLightsNoDir; 266 sk_sp<SkLights> fLightsTwoDir; 267 268 typedef GM INHERITED; 269}; 270 271////////////////////////////////////////////////////////////////////////////// 272 273DEF_GM(return new LightingShader2GM;) 274} 275