lightingshader2.cpp revision 1ec04d9553af68b458c8dd6bd18d8c25ebd41d7a
195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu/* 295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * Copyright 2016 Google Inc. 395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * 495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * Use of this source code is governed by a BSD-style license that can be 595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * found in the LICENSE file. 695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu */ 795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "gm.h" 995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkLightingShader.h" 1095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkNormalSource.h" 1195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkPoint3.h" 1295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkShader.h" 1395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 1495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu// Create a truncated pyramid normal map 1595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsustatic SkBitmap make_frustum_normalmap(int texSize) { 1695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkBitmap frustum; 17584bf6606b53bda8bf0810e7c0ad57e24cacb4f1arthurhsu frustum.allocN32Pixels(texSize, texSize); 18584bf6606b53bda8bf0810e7c0ad57e24cacb4f1arthurhsu 1995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize)); 20158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu return frustum; 21158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu} 2295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 2395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsunamespace skiagm { 24de776d4ef06ca29c240de3444348894f032b03ffLei Zhang 2595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu// This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using 2695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu// normal maps, and paint transparency. 2795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsuclass LightingShader2GM : public GM { 2895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsupublic: 29007bac39b5a613b17384f72d96457ab91638bab6arthurhsu LightingShader2GM() { 30007bac39b5a613b17384f72d96457ab91638bab6arthurhsu this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); 31007bac39b5a613b17384f72d96457ab91638bab6arthurhsu } 32007bac39b5a613b17384f72d96457ab91638bab6arthurhsu 33007bac39b5a613b17384f72d96457ab91638bab6arthurhsuprotected: 34007bac39b5a613b17384f72d96457ab91638bab6arthurhsu SkString onShortName() override { 35007bac39b5a613b17384f72d96457ab91638bab6arthurhsu return SkString("lightingshader2"); 36007bac39b5a613b17384f72d96457ab91638bab6arthurhsu } 37007bac39b5a613b17384f72d96457ab91638bab6arthurhsu 38007bac39b5a613b17384f72d96457ab91638bab6arthurhsu SkISize onISize() override { 39007bac39b5a613b17384f72d96457ab91638bab6arthurhsu return SkISize::Make(600, 740); 40007bac39b5a613b17384f72d96457ab91638bab6arthurhsu } 41007bac39b5a613b17384f72d96457ab91638bab6arthurhsu 42007bac39b5a613b17384f72d96457ab91638bab6arthurhsu void onOnceBeforeDraw() override { 43007bac39b5a613b17384f72d96457ab91638bab6arthurhsu SkLights::Builder builder; 44007bac39b5a613b17384f72d96457ab91638bab6arthurhsu const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f); 45007bac39b5a613b17384f72d96457ab91638bab6arthurhsu 46007bac39b5a613b17384f72d96457ab91638bab6arthurhsu builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f), 4795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu kLightFromUpperRight)); 4895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f))); 4995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu fLights = builder.finish(); 5095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 5153e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu fRect = SkRect::MakeIWH(kTexSize, kTexSize); 5295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkMatrix matrix; 5395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize); 5453e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit); 55c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu 5695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkBitmap opaqueDiffuseMap = sk_tool_utils::create_checkerboard_bitmap( 5753e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu kTexSize, kTexSize, 5853e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu sk_tool_utils::color_to_565(0x0), 5995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu sk_tool_utils::color_to_565(0xFF804020), 6095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 8); 61de776d4ef06ca29c240de3444348894f032b03ffLei Zhang fOpaqueDiffuse = SkShader::MakeBitmapShader(opaqueDiffuseMap, SkShader::kClamp_TileMode, 6295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkShader::kClamp_TileMode, &matrix); 6395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 6453e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu SkBitmap translucentDiffuseMap = sk_tool_utils::create_checkerboard_bitmap( 6595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu kTexSize, kTexSize, 6695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkColorSetARGB(0x55, 0x00, 0x00, 0x00), 6795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkColorSetARGB(0x55, 0x80, 0x40, 0x20), 68c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu 8); 6995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu fTranslucentDiffuse = SkShader::MakeBitmapShader(translucentDiffuseMap, 7095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkShader::kClamp_TileMode, 7153e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu SkShader::kClamp_TileMode, &matrix); 7295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 7395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkBitmap normalMap = make_frustum_normalmap(kTexSize); 74c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu fNormalMapShader = SkShader::MakeBitmapShader(normalMap, SkShader::kClamp_TileMode, 7595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkShader::kClamp_TileMode, &matrix); 7653e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu 77c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu } 7895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 7995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu // Scales shape around origin, rotates shape around origin, then translates shape to origin 8095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const { 8195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->translate(kTexSize/2.0f, kTexSize/2.0f); 8295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->scale(scaleX, scaleY); 8395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->rotate(rotate); 8495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f); 8595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu } 8695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 8795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu static constexpr int NUM_BOOLEAN_PARAMS = 4; 8895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY, 8995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu SkScalar rotate, bool useNormalSource, bool useDiffuseShader, 9095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu bool useTranslucentPaint, bool useTranslucentShader) { 9195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->save(); 9295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 9395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu this->positionCTM(canvas, scaleX, scaleY, rotate); 94c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu 9595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu const SkMatrix& ctm = canvas->getTotalMatrix(); 96c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu 9753e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu SkPaint paint; 9853e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu sk_sp<SkNormalSource> normalSource = nullptr; 9953e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu sk_sp<SkShader> diffuseShader = nullptr; 10053e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu 10153e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu if (useNormalSource) { 102c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm); 10353e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu } 104158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu 105158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu if (useDiffuseShader) { 10653e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse; 10753e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu } else { 10853e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu paint.setColor(0xFF00FF00); 109c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu } 11095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 111158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu if (useTranslucentPaint) { 112158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu paint.setAlpha(0x99); 113c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu } 11495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 11595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource), 11695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu fLights)); 11795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->drawRect(fRect, paint); 11895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 11995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu canvas->restore(); 12095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu } 12195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 12295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu void onDraw(SkCanvas* canvas) override { 12395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu 124584bf6606b53bda8bf0810e7c0ad57e24cacb4f1arthurhsu constexpr SkScalar LABEL_SIZE = 10.0f; 125 SkPaint labelPaint; 126 labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif", 127 SkFontStyle())); 128 labelPaint.setAntiAlias(true); 129 labelPaint.setTextSize(LABEL_SIZE); 130 131 constexpr int GRID_COLUMN_NUM = 4; 132 constexpr SkScalar GRID_CELL_WIDTH = kTexSize + 20.0f + NUM_BOOLEAN_PARAMS * LABEL_SIZE; 133 134 int gridNum = 0; 135 136 // Running through all possible bool parameter combinations 137 for (bool useNormalSource : {true, false}) { 138 for (bool useDiffuseShader : {true, false}) { 139 for (bool useTranslucentPaint : {true, false}) { 140 for (bool useTranslucentShader : {true, false}) { 141 142 // Determining position 143 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 144 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 145 146 canvas->save(); 147 148 canvas->translate(xPos, yPos); 149 this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader, 150 useTranslucentPaint, useTranslucentShader); 151 // Drawing labels 152 canvas->translate(0.0f, SkIntToScalar(kTexSize)); 153 { 154 canvas->translate(0.0f, LABEL_SIZE); 155 SkString label; 156 label.appendf("useNormalSource: %d", useNormalSource); 157 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 158 } 159 { 160 canvas->translate(0.0f, LABEL_SIZE); 161 SkString label; 162 label.appendf("useDiffuseShader: %d", useDiffuseShader); 163 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 164 } 165 { 166 canvas->translate(0.0f, LABEL_SIZE); 167 SkString label; 168 label.appendf("useTranslucentPaint: %d", useTranslucentPaint); 169 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 170 } 171 { 172 canvas->translate(0.0f, LABEL_SIZE); 173 SkString label; 174 label.appendf("useTranslucentShader: %d", useTranslucentShader); 175 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 176 } 177 178 canvas->restore(); 179 180 gridNum++; 181 } 182 } 183 } 184 } 185 186 187 // Rotation/scale test 188 { 189 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 190 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 191 192 canvas->save(); 193 canvas->translate(xPos, yPos); 194 this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true); 195 canvas->restore(); 196 197 gridNum++; 198 } 199 200 // Anisotropic scale test 201 { 202 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 203 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; 204 205 canvas->save(); 206 canvas->translate(xPos, yPos); 207 this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true); 208 canvas->restore(); 209 210 gridNum++; 211 } 212 } 213 214private: 215 static const int kTexSize = 96; 216 217 sk_sp<SkShader> fOpaqueDiffuse; 218 sk_sp<SkShader> fTranslucentDiffuse; 219 sk_sp<SkShader> fNormalMapShader; 220 221 SkRect fRect; 222 sk_sp<SkLights> fLights; 223 224 typedef GM INHERITED; 225}; 226 227////////////////////////////////////////////////////////////////////////////// 228 229DEF_GM(return new LightingShader2GM;) 230} 231