blob: 9283449e2ccd020c8b4bf4957761591a373f287b [file] [log] [blame]
dvonbeckc526da92016-07-20 11:20:30 -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"
9
10#include "SkBitmapProcShader.h"
11#include "SkLightingShader.h"
12#include "SkNormalSource.h"
13#include "SkPoint3.h"
14#include "SkShader.h"
15
16// Create a truncated pyramid normal map
17static 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
25namespace skiagm {
26
27// This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using
28// normal maps, and paint transparency.
29class LightingShader2GM : public GM {
30public:
31 LightingShader2GM() {
32 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
33 }
34
35protected:
36 SkString onShortName() override {
37 return SkString("lightingshader2");
38 }
39
40 SkISize onISize() override {
dvonbeck680e2e92016-07-21 12:19:54 -070041 return SkISize::Make(600, 740);
dvonbeckc526da92016-07-20 11:20:30 -070042 }
43
44 void onOnceBeforeDraw() override {
45 SkLights::Builder builder;
46 const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f);
47
48 builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
49 kLightFromUpperRight));
50 builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f)));
51 fLights = builder.finish();
52
53 fRect = SkRect::MakeIWH(kTexSize, kTexSize);
54 SkMatrix matrix;
55 SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize);
56 matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit);
57
58 SkBitmap opaqueDiffuseMap = sk_tool_utils::create_checkerboard_bitmap(
59 kTexSize, kTexSize,
60 sk_tool_utils::color_to_565(0x0),
61 sk_tool_utils::color_to_565(0xFF804020),
62 8);
63 fOpaqueDiffuse = SkMakeBitmapShader(opaqueDiffuseMap, SkShader::kClamp_TileMode,
64 SkShader::kClamp_TileMode, &matrix, nullptr);
65
66 SkBitmap translucentDiffuseMap = sk_tool_utils::create_checkerboard_bitmap(
67 kTexSize, kTexSize,
68 SkColorSetARGB(0x55, 0x00, 0x00, 0x00),
69 SkColorSetARGB(0x55, 0x80, 0x40, 0x20),
70 8);
71 fTranslucentDiffuse = SkMakeBitmapShader(translucentDiffuseMap, SkShader::kClamp_TileMode,
72 SkShader::kClamp_TileMode, &matrix, nullptr);
73
74 SkBitmap normalMap = make_frustum_normalmap(kTexSize);
75 fNormalMapShader = SkMakeBitmapShader(normalMap, SkShader::kClamp_TileMode,
76 SkShader::kClamp_TileMode, &matrix, nullptr);
77
78 }
79
80 // Scales shape around origin, rotates shape around origin, then translates shape to origin
81 void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const {
82 canvas->translate(kTexSize/2.0f, kTexSize/2.0f);
83 canvas->scale(scaleX, scaleY);
84 canvas->rotate(rotate);
85 canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f);
86 }
87
88 static constexpr int NUM_BOOLEAN_PARAMS = 4;
89 void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY,
90 SkScalar rotate, bool useNormalSource, bool useDiffuseShader,
91 bool useTranslucentPaint, bool useTranslucentShader) {
92 canvas->save();
93
94 this->positionCTM(canvas, scaleX, scaleY, rotate);
95
96 const SkMatrix& ctm = canvas->getTotalMatrix();
97
98 SkPaint paint;
99 sk_sp<SkNormalSource> normalSource = nullptr;
100 sk_sp<SkShader> diffuseShader = nullptr;
101
102 if (useNormalSource) {
103 normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm);
104 }
105
106 if (useDiffuseShader) {
107 diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse;
108 } else {
109 paint.setColor(0xFF00FF00);
110 }
111
112 if (useTranslucentPaint) {
113 paint.setAlpha(0x99);
114 }
115
116 paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
117 fLights));
118 canvas->drawRect(fRect, paint);
119
120 canvas->restore();
121 }
122
123 void onDraw(SkCanvas* canvas) override {
124
125 constexpr SkScalar LABEL_SIZE = 10.0f;
126 SkPaint labelPaint;
127 labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif",
128 SkFontStyle()));
129 labelPaint.setAntiAlias(true);
130 labelPaint.setTextSize(LABEL_SIZE);
131
132 constexpr int GRID_COLUMN_NUM = 4;
133 constexpr SkScalar GRID_CELL_WIDTH = kTexSize + 20.0f + NUM_BOOLEAN_PARAMS * LABEL_SIZE;
134
135 int gridNum = 0;
136
137 // Running through all possible bool parameter combinations
138 for (bool useNormalSource : {true, false}) {
139 for (bool useDiffuseShader : {true, false}) {
140 for (bool useTranslucentPaint : {true, false}) {
141 for (bool useTranslucentShader : {true, false}) {
142
143 // Determining position
144 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
145 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
146
147 canvas->save();
148
149 canvas->translate(xPos, yPos);
150 this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader,
151 useTranslucentPaint, useTranslucentShader);
152 // Drawing labels
153 canvas->translate(0.0f, SkIntToScalar(kTexSize));
154 {
155 canvas->translate(0.0f, LABEL_SIZE);
156 SkString label;
157 label.appendf("useNormalSource: %d", useNormalSource);
158 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
159 }
160 {
161 canvas->translate(0.0f, LABEL_SIZE);
162 SkString label;
163 label.appendf("useDiffuseShader: %d", useDiffuseShader);
164 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
165 }
166 {
167 canvas->translate(0.0f, LABEL_SIZE);
168 SkString label;
169 label.appendf("useTranslucentPaint: %d", useTranslucentPaint);
170 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
171 }
172 {
173 canvas->translate(0.0f, LABEL_SIZE);
174 SkString label;
175 label.appendf("useTranslucentShader: %d", useTranslucentShader);
176 canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
177 }
178
179 canvas->restore();
180
181 gridNum++;
182 }
183 }
184 }
185 }
186
187
188 // Rotation/scale test
189 {
190 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
191 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
192
193 canvas->save();
194 canvas->translate(xPos, yPos);
195 this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true);
196 canvas->restore();
197
198 gridNum++;
199 }
200
201 // Anisotropic scale test
202 {
203 SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
204 SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
205
206 canvas->save();
207 canvas->translate(xPos, yPos);
208 this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true);
209 canvas->restore();
210
211 gridNum++;
212 }
213 }
214
215private:
216 static const int kTexSize = 96;
dvonbeckc526da92016-07-20 11:20:30 -0700217
218 sk_sp<SkShader> fOpaqueDiffuse;
219 sk_sp<SkShader> fTranslucentDiffuse;
220 sk_sp<SkShader> fNormalMapShader;
221
222 SkRect fRect;
223 sk_sp<SkLights> fLights;
224
225 typedef GM INHERITED;
226};
227
228//////////////////////////////////////////////////////////////////////////////
229
230DEF_GM(return new LightingShader2GM;)
231}