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