blob: e27b4cff328d1a1b0059d5c3e610849c56f8bdd7 [file] [log] [blame]
vjiaoblack955e8792016-08-05 07:55:01 -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 "SampleCode.h"
9#include "SkPictureRecorder.h"
10#include "SkShadowPaintFilterCanvas.h"
11#include "SkShadowShader.h"
12#include "SkSurface.h"
13
14#ifdef SK_EXPERIMENTAL_SHADOWING
15
vjiaoblack955e8792016-08-05 07:55:01 -070016class ShadowingView : public SampleView {
17public:
18 ShadowingView() {
19
20 this->setBGColor(0xFFCCCCCC);
21 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -070022 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.2f, 0.3f, 0.4f),
23 SkVector3::Make(0.2f, 0.05f, 1.0f)));
24 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.4f, 0.3f, 0.2f),
25 SkVector3::Make(0.05f, 0.2f, 1.0f)));
26 builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
vjiaoblack955e8792016-08-05 07:55:01 -070027 fLights = builder.finish();
28
29 fTestRects[0].fColor = 0xFFEE8888;
30 fTestRects[0].fDepth = 80;
31 fTestRects[0].fGeometry = SkRect::MakeLTRB(200,150,350,300);
32
33 fTestRects[1].fColor = 0xFF88EE88;
34 fTestRects[1].fDepth = 160;
35 fTestRects[1].fGeometry = SkRect::MakeLTRB(150,200,300,350);
36
37 fTestRects[2].fColor = 0xFF8888EE;
38 fTestRects[2].fDepth = 240;
39 fTestRects[2].fGeometry = SkRect::MakeLTRB(100,100,250,250);
40
vjiaoblacke6f5d562016-08-25 06:30:23 -070041 fSliders[0].fGeometry = SkRect::MakeLTRB(20, 400, 30, 420);
42 fSliders[0].fOffset = 0.0f;
43 fSliders[0].fScale = 0.1f;
44
45 fSliders[1].fGeometry = SkRect::MakeLTRB(100, 420, 110, 440);
46 fSliders[1].fOffset = 0.0f;
47 fSliders[1].fScale = 10.0f;
48
49 fSliders[2].fGeometry = SkRect::MakeLTRB(0, 440, 10, 460);
50 fSliders[2].fOffset = 0.0f;
51 fSliders[2].fScale = 0.0025f;
52
vjiaoblack955e8792016-08-05 07:55:01 -070053 fSceneChanged = true;
54 fLightsChanged = true;
55
56 fSelectedRect = -1;
vjiaoblacke6f5d562016-08-25 06:30:23 -070057 fSelectedSlider = -1;
vjiaoblack955e8792016-08-05 07:55:01 -070058 fMoveLight = false;
vjiaoblack904527d2016-08-09 09:32:09 -070059
60 fClearShadowMaps = false;
vjiaoblacke6f5d562016-08-25 06:30:23 -070061
62 fShadowParams.fShadowRadius = 2.0f;
63 fShadowParams.fBiasingConstant = 0.3f;
64 fShadowParams.fMinVariance = 1024;
65 fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
vjiaoblack955e8792016-08-05 07:55:01 -070066 }
67
68protected:
69 bool onQuery(SkEvent *evt) override {
70 if (SampleCode::TitleQ(*evt)) {
71 SampleCode::TitleR(evt, "shadowing");
72 return true;
73 }
74
75 SkUnichar uni;
76 if (SampleCode::CharQ(*evt, &uni)) {
77 switch (uni) {
78 case 'L':
79 fMoveLight = !fMoveLight;
80 break;
vjiaoblack904527d2016-08-09 09:32:09 -070081 case 'd':
82 // Raster generated shadow maps have their origin in the UL corner
83 // GPU shadow maps can have an arbitrary origin.
84 // We override the 'd' keypress so that when the device is cycled,
85 // the shadow maps will be re-generated according to the new backend.
86 fClearShadowMaps = true;
87 break;
vjiaoblacke6f5d562016-08-25 06:30:23 -070088 case 'B':
89 if (SkShadowParams::kVariance_ShadowType == fShadowParams.fType) {
90 fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
91 } else if (SkShadowParams::kNoBlur_ShadowType ==
92 fShadowParams.fType) {
93 fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
94 }
95 fLightsChanged = true;
96 break;
vjiaoblack955e8792016-08-05 07:55:01 -070097 default:
98 break;
99 }
100 }
101 return this->INHERITED::onQuery(evt);
102 }
103
104 sk_sp<SkPicture> makeTestPicture(int width, int height) {
105 SkPictureRecorder recorder;
106
107 // LONG RANGE TODO: eventually add SkBBHFactory (bounding box factory)
108 SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(width, height));
109
110 SkASSERT(canvas->getTotalMatrix().isIdentity());
111 SkPaint paint;
112 paint.setColor(SK_ColorGRAY);
113
114 // LONG RANGE TODO: tag occluders
115 // LONG RANGE TODO: track number of IDs we need (hopefully less than 256)
116 // and determinate the mapping from z to id
117
118 // universal receiver, "ground"
119 canvas->drawRect(SkRect::MakeIWH(width, height), paint);
120
121 for (int i = 0; i < kNumTestRects; i++) {
122 paint.setColor(fTestRects[i].fColor);
123 if (i == 0) {
124 canvas->translateZ(fTestRects[0].fDepth);
125 } else {
126 canvas->translateZ(fTestRects[i].fDepth - fTestRects[i-1].fDepth);
127 }
128 canvas->drawRect(fTestRects[i].fGeometry, paint);
129 }
130
131 return recorder.finishRecordingAsPicture();
132 }
133
vjiaoblack955e8792016-08-05 07:55:01 -0700134 void onDrawContent(SkCanvas *canvas) override {
vjiaoblack904527d2016-08-09 09:32:09 -0700135 if (fSceneChanged) {
vjiaoblack955e8792016-08-05 07:55:01 -0700136 fPicture = this->makeTestPicture(kWidth, kHeight);
vjiaoblack955e8792016-08-05 07:55:01 -0700137 }
138
vjiaoblack904527d2016-08-09 09:32:09 -0700139 if (fSceneChanged || fLightsChanged || fClearShadowMaps) {
140 for (int i = 0; i < fLights->numLights(); i++) {
141 fLights->light(i).setShadowMap(nullptr);
142 }
vjiaoblacke6f5d562016-08-25 06:30:23 -0700143
vjiaoblack904527d2016-08-09 09:32:09 -0700144 fSceneChanged = false;
145 fLightsChanged = false;
146 fClearShadowMaps = false;
vjiaoblack955e8792016-08-05 07:55:01 -0700147 }
vjiaoblackd707f2d2016-08-16 05:38:45 -0700148
149 canvas->setLights(fLights);
vjiaoblacke6f5d562016-08-25 06:30:23 -0700150 canvas->drawShadowedPicture(fPicture, nullptr, nullptr, fShadowParams);
151
152 for (int i = 0; i < kNumSliders; i++) {
153 SkPaint paint;
154 paint.setColor(SK_ColorBLACK);
155 canvas->drawRect(fSliders[i].fGeometry, paint);
156 }
vjiaoblack955e8792016-08-05 07:55:01 -0700157 }
158
159 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
160 return new SkView::Click(this);
161 }
162
vjiaoblacke6f5d562016-08-25 06:30:23 -0700163 void updateFromSelectedSlider() {
164 SkScalar newValue = fSliders[fSelectedSlider].fGeometry.fLeft *
165 fSliders[fSelectedSlider].fScale +
166 fSliders[fSelectedSlider].fOffset;
167
168 switch (fSelectedSlider) {
169 case 0:
170 fShadowParams.fShadowRadius = newValue;
171 break;
172 case 1:
173 fShadowParams.fMinVariance = newValue;
174 break;
175 case 2:
176 fShadowParams.fBiasingConstant = newValue;
177 break;
178 default:
179 break;
180 }
181 }
182
vjiaoblack955e8792016-08-05 07:55:01 -0700183 bool onClick(Click *click) override {
184 SkScalar x = click->fCurr.fX;
185 SkScalar y = click->fCurr.fY;
186
187 SkScalar dx = x - click->fPrev.fX;
188 SkScalar dy = y - click->fPrev.fY;
189
190 if (fMoveLight) {
191 if (dx != 0 || dy != 0) {
192 float recipX = 1.0f / kWidth;
193 float recipY = 1.0f / kHeight;
194
195 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -0700196 builder.add(SkLights::Light::MakeDirectional(
197 SkColor3f::Make(0.2f, 0.3f, 0.4f),
198 SkVector3::Make(0.2f + (200.0f - x) * recipX,
199 0.05f + (200.0f - y) * recipY,
200 1.0f)));
201 builder.add(SkLights::Light::MakeDirectional(
202 SkColor3f::Make(0.4f, 0.3f, 0.2f),
203 SkVector3::Make(0.05f + (200.0f - x) * recipX,
204 0.2f + (200.0f - y) * recipY,
205 1.0f)));
206 builder.add(SkLights::Light::MakeAmbient(
207 SkColor3f::Make(0.4f, 0.4f, 0.4f)));
vjiaoblack955e8792016-08-05 07:55:01 -0700208 fLights = builder.finish();
209
210 fLightsChanged = true;
211 this->inval(nullptr);
212 }
213 return true;
214 }
215
216 if (click->fState == Click::State::kUp_State) {
217 fSelectedRect = -1;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700218 fSelectedSlider = -1;
vjiaoblack955e8792016-08-05 07:55:01 -0700219 return true;
220 }
221
222 if (fSelectedRect > -1) {
223 fTestRects[fSelectedRect].fGeometry.offset(dx, dy);
224
225 fSceneChanged = true;
226 this->inval(nullptr);
227 return true;
228 }
229
vjiaoblacke6f5d562016-08-25 06:30:23 -0700230 if (fSelectedSlider > -1) {
231 fSliders[fSelectedSlider].fGeometry.offset(dx, 0);
232
233 this->updateFromSelectedSlider();
234
235 fLightsChanged = true;
236 this->inval(nullptr);
237 return true;
238 }
239
vjiaoblack955e8792016-08-05 07:55:01 -0700240 // assume last elements are highest
241 for (int i = kNumTestRects - 1; i >= 0; i--) {
242 if (fTestRects[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
243 fSelectedRect = i;
244 fTestRects[i].fGeometry.offset(dx, dy);
245
246 fSceneChanged = true;
247 this->inval(nullptr);
248 break;
249 }
250 }
251
vjiaoblacke6f5d562016-08-25 06:30:23 -0700252 for (int i = 0; i <= kNumSliders; i++) {
253 if (fSliders[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
254 fSelectedSlider = i;
255 fSliders[i].fGeometry.offset(dx, 0);
256
257 this->updateFromSelectedSlider();
258
259 fLightsChanged = true;
260
261 this->inval(nullptr);
262 break;
263 }
264 }
265
vjiaoblack955e8792016-08-05 07:55:01 -0700266 return true;
267 }
268
269private:
270 static constexpr int kNumTestRects = 3;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700271 static constexpr int kNumSliders = 3;
vjiaoblack955e8792016-08-05 07:55:01 -0700272
273 static const int kWidth = 400;
274 static const int kHeight = 400;
275
276 struct {
277 SkRect fGeometry;
278 int fDepth;
279 SkColor fColor;
280 } fTestRects[kNumTestRects];
vjiaoblack955e8792016-08-05 07:55:01 -0700281 int fSelectedRect;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700282
283 struct {
284 SkRect fGeometry;
285 SkScalar fOffset;
286 SkScalar fScale;
287 } fSliders[kNumSliders];
288 int fSelectedSlider;
289
290 bool fClearShadowMaps;
vjiaoblack955e8792016-08-05 07:55:01 -0700291 bool fMoveLight;
vjiaoblack955e8792016-08-05 07:55:01 -0700292 bool fSceneChanged;
293 bool fLightsChanged;
294
vjiaoblacke6f5d562016-08-25 06:30:23 -0700295 sk_sp<SkPicture> fPicture;
296 SkShadowParams fShadowParams;
vjiaoblack955e8792016-08-05 07:55:01 -0700297 sk_sp<SkLights> fLights;
298
299 typedef SampleView INHERITED;
300};
301
302//////////////////////////////////////////////////////////////////////////////
303static SkView* MyFactory() { return new ShadowingView; }
304static SkViewRegister reg(MyFactory);
305
306#endif