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