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 "sk_tool_utils.h" 10 #include "SkLightingShader.h" 11 #include "SkNormalSource.h" 12 #include "SkPath.h" 13 #include "SkPoint3.h" 14 #include "SkShader.h" 15 16 17 namespace skiagm { 18 19 // This GM exercises lighting shaders when used with bevel SkNormalSource objects. 20 class LightingShaderBevelGM : public GM { 21 public: LightingShaderBevelGM()22 LightingShaderBevelGM() { 23 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); 24 } 25 26 protected: onShortName()27 SkString onShortName() override { 28 return SkString("lightingshaderbevel"); 29 } 30 onISize()31 SkISize onISize() override { 32 return SkISize::Make(SkScalarCeilToInt(GRID_NUM_COLUMNS * GRID_CELL_WIDTH), 33 SkScalarCeilToInt(GRID_NUM_ROWS * GRID_CELL_WIDTH)); 34 } 35 onOnceBeforeDraw()36 void onOnceBeforeDraw() override { 37 SkLights::Builder builder; 38 const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f); 39 40 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f), 41 kLightFromUpperRight)); 42 builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f)); 43 fLights = builder.finish(); 44 45 // fRect is assumed to be square throughout this file 46 fRect = SkRect::MakeIWH(kTexSize, kTexSize); 47 SkMatrix matrix; 48 SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize); 49 matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit); 50 51 SkBitmap diffuseMap = sk_tool_utils::create_checkerboard_bitmap( 52 kTexSize, kTexSize, 53 sk_tool_utils::color_to_565(0x0), 54 sk_tool_utils::color_to_565(0xFF804020), 55 8); 56 fDiffuse = SkShader::MakeBitmapShader(diffuseMap, SkShader::kClamp_TileMode, 57 SkShader::kClamp_TileMode, &matrix); 58 59 fConvexPath.moveTo(fRect.width() / 2.0f, 0.0f); 60 fConvexPath.lineTo(0.0f, fRect.height()); 61 fConvexPath.lineTo(fRect.width(), fRect.height()); 62 fConvexPath.close(); 63 64 // Creating concave path 65 { 66 SkScalar x = 0.0f; 67 SkScalar y = fRect.height() / 2.0f; 68 69 const int NUM_SPIKES = 8; 70 71 const SkScalar x0 = x; 72 const SkScalar dx = fRect.width() / (NUM_SPIKES * 2); 73 const SkScalar dy = SK_Scalar1 * 10; 74 75 76 fConcavePath.moveTo(x, y + dy); 77 for (int i = 0; i < NUM_SPIKES; i++) { 78 x += dx; 79 fConcavePath.lineTo(x, y - dy); 80 x += dx; 81 fConcavePath.lineTo(x, y + dy); 82 } 83 fConcavePath.lineTo(x, y + (2 * dy)); 84 fConcavePath.lineTo(x0, y + (2 * dy)); 85 fConcavePath.close(); 86 } 87 } 88 89 // Scales shape around origin, rotates shape around origin, then translates shape to origin positionCTM(SkCanvas * canvas,SkScalar scaleX,SkScalar scaleY,SkScalar rotate) const90 void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const { 91 canvas->translate(kTexSize/2.0f, kTexSize/2.0f); 92 canvas->scale(scaleX, scaleY); 93 canvas->rotate(rotate); 94 canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f); 95 } 96 97 enum Shape { 98 kCircle_Shape, 99 kRect_Shape, 100 kRRect_Shape, 101 kConvexPath_Shape, 102 kConcavePath_Shape, 103 104 kLast_Shape = kConcavePath_Shape 105 }; drawShape(enum Shape shape,SkCanvas * canvas,SkScalar scaleX,SkScalar scaleY,SkScalar rotate,SkNormalSource::BevelType bevelType,SkScalar bevelHeight)106 void drawShape(enum Shape shape, SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY, 107 SkScalar rotate, SkNormalSource::BevelType bevelType, SkScalar bevelHeight) { 108 canvas->save(); 109 110 this->positionCTM(canvas, scaleX, scaleY, rotate); 111 112 SkPaint paint; 113 114 SkScalar bevelWidth = 10.0f; 115 sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeBevel(bevelType, bevelWidth, 116 bevelHeight); 117 118 paint.setShader(SkLightingShader::Make(fDiffuse, std::move(normalSource), fLights)); 119 paint.setAntiAlias(true); 120 switch(shape) { 121 case kCircle_Shape: 122 canvas->drawCircle(fRect.centerX(), fRect.centerY(), fRect.width()/2.0f, paint); 123 break; 124 case kRect_Shape: 125 canvas->drawRect(fRect, paint); 126 break; 127 case kRRect_Shape: 128 canvas->drawRoundRect(fRect, 5.0f, 5.0f, paint); 129 break; 130 case kConvexPath_Shape: 131 canvas->drawPath(fConvexPath, paint); 132 break; 133 case kConcavePath_Shape: 134 canvas->drawPath(fConcavePath, paint); 135 break; 136 default: 137 SkDEBUGFAIL("Invalid shape enum for drawShape"); 138 } 139 140 canvas->restore(); 141 } 142 onDraw(SkCanvas * canvas)143 void onDraw(SkCanvas* canvas) override { 144 SkPaint labelPaint; 145 labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif", 146 SkFontStyle())); 147 labelPaint.setAntiAlias(true); 148 labelPaint.setTextSize(LABEL_SIZE); 149 150 int gridNum = 0; 151 152 // Running through all possible parameter combinations 153 for (auto bevelType : {SkNormalSource::BevelType::kLinear, 154 SkNormalSource::BevelType::kRoundedIn, 155 SkNormalSource::BevelType::kRoundedOut}) { 156 for (SkScalar bevelHeight: {-7.0f, 7.0f}) { 157 for (int shapeInt = 0; shapeInt < NUM_SHAPES; shapeInt++) { 158 Shape shape = (Shape)shapeInt; 159 160 // Determining position 161 SkScalar xPos = (gridNum / GRID_NUM_ROWS) * GRID_CELL_WIDTH; 162 SkScalar yPos = (gridNum % GRID_NUM_ROWS) * GRID_CELL_WIDTH; 163 164 canvas->save(); 165 166 canvas->translate(xPos, yPos); 167 this->drawShape(shape, canvas, 1.0f, 1.0f, 0.f, bevelType, bevelHeight); 168 // Drawing labels 169 canvas->translate(0.0f, SkIntToScalar(kTexSize)); 170 { 171 canvas->translate(0.0f, LABEL_SIZE); 172 SkString label; 173 label.append("bevelType: "); 174 switch (bevelType) { 175 case SkNormalSource::BevelType::kLinear: 176 label.append("linear"); 177 break; 178 case SkNormalSource::BevelType::kRoundedIn: 179 label.append("roundedIn"); 180 break; 181 case SkNormalSource::BevelType::kRoundedOut: 182 label.append("roundedOut"); 183 break; 184 } 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("bevelHeight: %.1f", bevelHeight); 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 // Testing rotation 202 for (int shapeInt = 0; shapeInt < NUM_SHAPES; shapeInt++) { 203 Shape shape = (Shape)shapeInt; 204 205 // Determining position 206 SkScalar xPos = (gridNum / GRID_NUM_ROWS) * GRID_CELL_WIDTH; 207 SkScalar yPos = (gridNum % GRID_NUM_ROWS) * GRID_CELL_WIDTH; 208 209 canvas->save(); 210 211 canvas->translate(xPos, yPos); 212 this->drawShape(shape, canvas, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2, 45.0f, 213 SkNormalSource::BevelType::kLinear, 7.0f); 214 215 // Drawing labels 216 canvas->translate(0.0f, SkIntToScalar(kTexSize)); 217 { 218 canvas->translate(0.0f, LABEL_SIZE); 219 SkString label; 220 label.appendf("bevelType: linear"); 221 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 222 } 223 { 224 canvas->translate(0.0f, LABEL_SIZE); 225 SkString label; 226 label.appendf("bevelHeight: %.1f", 7.0f); 227 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 228 } 229 { 230 canvas->translate(0.0f, LABEL_SIZE); 231 SkString label; 232 label.appendf("rotated"); 233 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint); 234 } 235 236 canvas->restore(); 237 238 gridNum++; 239 } 240 241 // Making sure NUM_COMBINATIONS_PER_SHAPE is set correctly 242 SkASSERT(gridNum == (NUM_COMBINATIONS_PER_SHAPE*NUM_SHAPES)); 243 } 244 245 private: 246 static constexpr int kTexSize = 96; 247 static constexpr int NUM_SHAPES = kLast_Shape + 1; 248 static constexpr int NUM_COMBINATIONS_PER_SHAPE = 7; 249 static constexpr int GRID_NUM_ROWS = NUM_SHAPES; 250 static constexpr int GRID_NUM_COLUMNS = NUM_COMBINATIONS_PER_SHAPE; 251 static constexpr SkScalar LABEL_SIZE = 10.0f; 252 static constexpr int NUM_LABELS_PER_CELL = 3; 253 static constexpr SkScalar GRID_CELL_WIDTH = kTexSize + 10.0f + NUM_LABELS_PER_CELL * LABEL_SIZE; 254 255 sk_sp<SkShader> fDiffuse; 256 257 SkRect fRect; 258 SkPath fConvexPath; 259 SkPath fConcavePath; 260 sk_sp<SkLights> fLights; 261 262 typedef GM INHERITED; 263 }; 264 265 ////////////////////////////////////////////////////////////////////////////// 266 267 DEF_GM(return new LightingShaderBevelGM;) 268 } 269