blob: 6d4c345354977abf229fca068aa508e0fe4d3990 [file] [log] [blame]
Robert Phillipsa8cdbd72018-07-17 12:30:40 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkFont.h"
13#include "include/core/SkFontStyle.h"
14#include "include/core/SkMatrix.h"
15#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkPoint3.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040017#include "include/core/SkRect.h"
18#include "include/core/SkRefCnt.h"
19#include "include/core/SkScalar.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/core/SkShader.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040021#include "include/core/SkSize.h"
22#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/core/SkTypeface.h"
24#include "src/core/SkNormalSource.h"
25#include "src/shaders/SkLightingShader.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040026#include "src/shaders/SkLights.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "tools/ToolUtils.h"
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040028
Ben Wagner7fde8e12019-05-01 17:28:53 -040029#include <initializer_list>
30#include <utility>
31
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040032// Create a truncated pyramid normal map
33static SkBitmap make_frustum_normalmap(int texSize) {
34 SkBitmap frustum;
35 frustum.allocN32Pixels(texSize, texSize);
36
Mike Kleinea3f0142019-03-20 11:12:10 -050037 ToolUtils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040038 return frustum;
39}
40
41namespace skiagm {
42
43// This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using
44// normal maps, paint transparency, zero directional lights, multiple directional lights.
45class LightingShader2GM : public GM {
46public:
47 LightingShader2GM() : fRect(SkRect::MakeIWH(kTexSize, kTexSize)) {
Mike Kleinea3f0142019-03-20 11:12:10 -050048 this->setBGColor(ToolUtils::color_to_565(0xFF0000CC));
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040049 }
50
51protected:
52 SkString onShortName() override {
53 return SkString("lightingshader2");
54 }
55
56 SkISize onISize() override {
57 return SkISize::Make(600, 740);
58 }
59
60 void onOnceBeforeDraw() override {
61 // The light direction is towards the light with +Z coming out of the screen
62 const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f);
63 const SkVector3 kLightFromUpperLeft = SkVector3::Make(-0.788f, 0.394f, 0.473f);
64
65 // Standard set of lights
66 {
67 SkLights::Builder builder;
68 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
69 kLightFromUpperRight));
70 builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
71 fLights = builder.finish();
72 }
73
74 // No directional lights
75 {
76 SkLights::Builder builder;
77 builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
78 fLightsNoDir = builder.finish();
79 }
80
81 // Two directional lights
82 {
83 SkLights::Builder builder;
84 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 0.0f, 0.0f),
85 kLightFromUpperRight));
86 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.0f, 1.0f, 0.0f),
87 kLightFromUpperLeft));
88 builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
89 fLightsTwoDir = builder.finish();
90 }
91
92 SkMatrix matrix;
93 SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize);
94 matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit);
95
Mike Kleinea3f0142019-03-20 11:12:10 -050096 SkBitmap opaqueDiffuseMap = ToolUtils::create_checkerboard_bitmap(
97 kTexSize, kTexSize, SK_ColorBLACK, 0xFF808080, 8);
Mike Reed50acf8f2019-04-08 13:20:23 -040098 fOpaqueDiffuse = opaqueDiffuseMap.makeShader(&matrix);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040099
Mike Kleinea3f0142019-03-20 11:12:10 -0500100 SkBitmap translucentDiffuseMap =
101 ToolUtils::create_checkerboard_bitmap(kTexSize,
102 kTexSize,
103 SkColorSetARGB(0x55, 0x00, 0x00, 0x00),
104 SkColorSetARGB(0x55, 0x80, 0x80, 0x80),
105 8);
Mike Reed50acf8f2019-04-08 13:20:23 -0400106 fTranslucentDiffuse = translucentDiffuseMap.makeShader(&matrix);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400107
108 SkBitmap normalMap = make_frustum_normalmap(kTexSize);
Mike Reed50acf8f2019-04-08 13:20:23 -0400109 fNormalMapShader = normalMap.makeShader(&matrix);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400110
111 }
112
113 // Scales shape around origin, rotates shape around origin, then translates shape to origin
114 void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const {
115 canvas->translate(kTexSize/2.0f, kTexSize/2.0f);
116 canvas->scale(scaleX, scaleY);
117 canvas->rotate(rotate);
118 canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f);
119 }
120
121 void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY,
122 SkScalar rotate, bool useNormalSource, bool useDiffuseShader,
123 bool useTranslucentPaint, bool useTranslucentShader, sk_sp<SkLights> lights) {
124 canvas->save();
125
126 this->positionCTM(canvas, scaleX, scaleY, rotate);
127
128 const SkMatrix& ctm = canvas->getTotalMatrix();
129
130 SkPaint paint;
131 sk_sp<SkNormalSource> normalSource = nullptr;
132 sk_sp<SkShader> diffuseShader = nullptr;
133
134 if (useNormalSource) {
135 normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm);
136 }
137
138 if (useDiffuseShader) {
139 diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse;
140 } else {
141 paint.setColor(SK_ColorGREEN);
142 }
143
144 if (useTranslucentPaint) {
145 paint.setAlpha(0x99);
146 }
147
148 paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
149 std::move(lights)));
150 canvas->drawRect(fRect, paint);
151
152 canvas->restore();
153 }
154
155 void onDraw(SkCanvas* canvas) override {
156 SkPaint labelPaint;
Mike Kleinea3f0142019-03-20 11:12:10 -0500157 SkFont font(ToolUtils::create_portable_typeface("sans-serif", SkFontStyle()), kLabelSize);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400158
159 int gridNum = 0;
160
161 // Running through all possible bool parameter combinations
162 for (bool useNormalSource : {true, false}) {
163 for (bool useDiffuseShader : {true, false}) {
164 for (bool useTranslucentPaint : {true, false}) {
165 for (bool useTranslucentShader : {true, false}) {
166
167 // Determining position
168 SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
169 SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
170
171 canvas->save();
172
173 canvas->translate(xPos, yPos);
174 this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader,
175 useTranslucentPaint, useTranslucentShader, fLights);
176 // Drawing labels
177 canvas->translate(0.0f, SkIntToScalar(kTexSize));
178 {
179 canvas->translate(0.0f, kLabelSize);
180 SkString label;
181 label.appendf("useNormalSource: %d", useNormalSource);
Hal Canary6ac0df82019-01-07 16:01:22 -0500182 canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400183 }
184 {
185 canvas->translate(0.0f, kLabelSize);
186 SkString label;
187 label.appendf("useDiffuseShader: %d", useDiffuseShader);
Hal Canary6ac0df82019-01-07 16:01:22 -0500188 canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400189 }
190 {
191 canvas->translate(0.0f, kLabelSize);
192 SkString label;
193 label.appendf("useTranslucentPaint: %d", useTranslucentPaint);
Hal Canary6ac0df82019-01-07 16:01:22 -0500194 canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400195 }
196 {
197 canvas->translate(0.0f, kLabelSize);
198 SkString label;
199 label.appendf("useTranslucentShader: %d", useTranslucentShader);
Hal Canary6ac0df82019-01-07 16:01:22 -0500200 canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400201 }
202
203 canvas->restore();
204
205 gridNum++;
206 }
207 }
208 }
209 }
210
211
212 // Rotation/scale test
213 {
214 SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
215 SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
216
217 canvas->save();
218 canvas->translate(xPos, yPos);
219 this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true, fLights);
220 canvas->restore();
221
222 gridNum++;
223 }
224
225 // Anisotropic scale test
226 {
227 SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
228 SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
229
230 canvas->save();
231 canvas->translate(xPos, yPos);
232 this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true, fLights);
233 canvas->restore();
234
235 gridNum++;
236 }
237
238 // No directional lights test
239 {
240 SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
241 SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
242
243 canvas->save();
244 canvas->translate(xPos, yPos);
245 this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsNoDir);
246 canvas->restore();
247
248 gridNum++;
249 }
250
251 // Two directional lights test
252 {
253 SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
254 SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
255
256 canvas->save();
257 canvas->translate(xPos, yPos);
258 this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsTwoDir);
259 canvas->restore();
260
261 gridNum++;
262 }
263 }
264
265private:
266 static constexpr int kTexSize = 96;
267 static constexpr int kNumBooleanParams = 4;
268 static constexpr SkScalar kLabelSize = 10.0f;
269 static constexpr int kGridColumnNum = 4;
270 static constexpr SkScalar kGridCellWidth = kTexSize + 20.0f + kNumBooleanParams * kLabelSize;
271
272 sk_sp<SkShader> fOpaqueDiffuse;
273 sk_sp<SkShader> fTranslucentDiffuse;
274 sk_sp<SkShader> fNormalMapShader;
275
276 const SkRect fRect;
277 sk_sp<SkLights> fLights;
278 sk_sp<SkLights> fLightsNoDir;
279 sk_sp<SkLights> fLightsTwoDir;
280
281 typedef GM INHERITED;
282};
283
284//////////////////////////////////////////////////////////////////////////////
285
286DEF_GM(return new LightingShader2GM;)
287}