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