blob: 4892f9c27df5c97eb27bd38175a2f59ac5082aac [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:
vjiaoblack56f33ea2016-08-26 08:49:46 -070018 ShadowingView()
19 : fSceneChanged(true)
20 , fLightsChanged(true)
21 , fMoveLight(false)
22 , fClearShadowMaps(false)
23 , fSelectedRectID(-1)
24 , fSelectedSliderID(-1)
25 , fLightDepth(300.0f) {
vjiaoblack955e8792016-08-05 07:55:01 -070026 this->setBGColor(0xFFCCCCCC);
vjiaoblack56f33ea2016-08-26 08:49:46 -070027
28 this->updateLights(200, 200);
vjiaoblack955e8792016-08-05 07:55:01 -070029
30 fTestRects[0].fColor = 0xFFEE8888;
31 fTestRects[0].fDepth = 80;
32 fTestRects[0].fGeometry = SkRect::MakeLTRB(200,150,350,300);
33
34 fTestRects[1].fColor = 0xFF88EE88;
35 fTestRects[1].fDepth = 160;
36 fTestRects[1].fGeometry = SkRect::MakeLTRB(150,200,300,350);
37
38 fTestRects[2].fColor = 0xFF8888EE;
39 fTestRects[2].fDepth = 240;
40 fTestRects[2].fGeometry = SkRect::MakeLTRB(100,100,250,250);
41
vjiaoblacke6f5d562016-08-25 06:30:23 -070042 fSliders[0].fGeometry = SkRect::MakeLTRB(20, 400, 30, 420);
43 fSliders[0].fOffset = 0.0f;
44 fSliders[0].fScale = 0.1f;
45
46 fSliders[1].fGeometry = SkRect::MakeLTRB(100, 420, 110, 440);
47 fSliders[1].fOffset = 0.0f;
48 fSliders[1].fScale = 10.0f;
49
50 fSliders[2].fGeometry = SkRect::MakeLTRB(0, 440, 10, 460);
51 fSliders[2].fOffset = 0.0f;
52 fSliders[2].fScale = 0.0025f;
53
vjiaoblack56f33ea2016-08-26 08:49:46 -070054 fShadowParams.fShadowRadius = 4.0f;
vjiaoblacke6f5d562016-08-25 06:30:23 -070055 fShadowParams.fBiasingConstant = 0.3f;
56 fShadowParams.fMinVariance = 1024;
57 fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
vjiaoblack955e8792016-08-05 07:55:01 -070058 }
59
60protected:
61 bool onQuery(SkEvent *evt) override {
62 if (SampleCode::TitleQ(*evt)) {
63 SampleCode::TitleR(evt, "shadowing");
64 return true;
65 }
66
67 SkUnichar uni;
68 if (SampleCode::CharQ(*evt, &uni)) {
69 switch (uni) {
70 case 'L':
71 fMoveLight = !fMoveLight;
72 break;
vjiaoblack904527d2016-08-09 09:32:09 -070073 case 'd':
74 // Raster generated shadow maps have their origin in the UL corner
75 // GPU shadow maps can have an arbitrary origin.
76 // We override the 'd' keypress so that when the device is cycled,
77 // the shadow maps will be re-generated according to the new backend.
78 fClearShadowMaps = true;
79 break;
vjiaoblack56f33ea2016-08-26 08:49:46 -070080 case 'q':
81 fLightDepth += 5.0f;
82 fMoveLight = true;
vjiaoblacke6f5d562016-08-25 06:30:23 -070083 case 'B':
84 if (SkShadowParams::kVariance_ShadowType == fShadowParams.fType) {
85 fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
86 } else if (SkShadowParams::kNoBlur_ShadowType ==
87 fShadowParams.fType) {
88 fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
89 }
90 fLightsChanged = true;
91 break;
vjiaoblack56f33ea2016-08-26 08:49:46 -070092 case 'w':
93 fLightDepth -= 5.0f;
94 fMoveLight = true;
95 break;
vjiaoblack955e8792016-08-05 07:55:01 -070096 default:
97 break;
98 }
99 }
100 return this->INHERITED::onQuery(evt);
101 }
102
103 sk_sp<SkPicture> makeTestPicture(int width, int height) {
104 SkPictureRecorder recorder;
105
106 // LONG RANGE TODO: eventually add SkBBHFactory (bounding box factory)
107 SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(width, height));
108
109 SkASSERT(canvas->getTotalMatrix().isIdentity());
110 SkPaint paint;
111 paint.setColor(SK_ColorGRAY);
112
113 // LONG RANGE TODO: tag occluders
114 // LONG RANGE TODO: track number of IDs we need (hopefully less than 256)
115 // and determinate the mapping from z to id
116
117 // universal receiver, "ground"
118 canvas->drawRect(SkRect::MakeIWH(width, height), paint);
119
120 for (int i = 0; i < kNumTestRects; i++) {
121 paint.setColor(fTestRects[i].fColor);
122 if (i == 0) {
123 canvas->translateZ(fTestRects[0].fDepth);
124 } else {
125 canvas->translateZ(fTestRects[i].fDepth - fTestRects[i-1].fDepth);
126 }
127 canvas->drawRect(fTestRects[i].fGeometry, paint);
128 }
129
130 return recorder.finishRecordingAsPicture();
131 }
132
vjiaoblack955e8792016-08-05 07:55:01 -0700133 void onDrawContent(SkCanvas *canvas) override {
vjiaoblack904527d2016-08-09 09:32:09 -0700134 if (fSceneChanged) {
vjiaoblack955e8792016-08-05 07:55:01 -0700135 fPicture = this->makeTestPicture(kWidth, kHeight);
vjiaoblack955e8792016-08-05 07:55:01 -0700136 }
137
vjiaoblack904527d2016-08-09 09:32:09 -0700138 if (fSceneChanged || fLightsChanged || fClearShadowMaps) {
139 for (int i = 0; i < fLights->numLights(); i++) {
140 fLights->light(i).setShadowMap(nullptr);
141 }
vjiaoblacke6f5d562016-08-25 06:30:23 -0700142
vjiaoblack904527d2016-08-09 09:32:09 -0700143 fSceneChanged = false;
144 fLightsChanged = false;
145 fClearShadowMaps = false;
vjiaoblack955e8792016-08-05 07:55:01 -0700146 }
vjiaoblackd707f2d2016-08-16 05:38:45 -0700147
148 canvas->setLights(fLights);
vjiaoblacke6f5d562016-08-25 06:30:23 -0700149 canvas->drawShadowedPicture(fPicture, nullptr, nullptr, fShadowParams);
150
151 for (int i = 0; i < kNumSliders; i++) {
152 SkPaint paint;
153 paint.setColor(SK_ColorBLACK);
154 canvas->drawRect(fSliders[i].fGeometry, paint);
155 }
vjiaoblack955e8792016-08-05 07:55:01 -0700156 }
157
158 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
159 return new SkView::Click(this);
160 }
161
vjiaoblack56f33ea2016-08-26 08:49:46 -0700162 void updateLights(int x, int y) {
163 SkLights::Builder builder;
164 builder.add(SkLights::Light::MakePoint(SkColor3f::Make(0.2f, 0.4f, 0.6f),
165 SkVector3::Make(x - 50,
166 350 - y,
167 fLightDepth),
168 1024));
169 builder.add(SkLights::Light::MakePoint(SkColor3f::Make(0.6f, 0.4f, 0.2f),
170 SkVector3::Make(x + 50,
171 450 - y,
172 fLightDepth),
173 1024));
174 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.2f, 0.2f, 0.2f),
175 SkVector3::Make(0.2f, 0.2f, 1.0f)));
176 fLights = builder.finish();
177 }
vjiaoblacke6f5d562016-08-25 06:30:23 -0700178
vjiaoblack56f33ea2016-08-26 08:49:46 -0700179 void updateFromSelectedSlider() {
180 SkScalar newValue = fSliders[fSelectedSliderID].fGeometry.fLeft *
181 fSliders[fSelectedSliderID].fScale +
182 fSliders[fSelectedSliderID].fOffset;
183
184 switch (fSelectedSliderID) {
vjiaoblacke6f5d562016-08-25 06:30:23 -0700185 case 0:
186 fShadowParams.fShadowRadius = newValue;
187 break;
188 case 1:
189 fShadowParams.fMinVariance = newValue;
190 break;
191 case 2:
192 fShadowParams.fBiasingConstant = newValue;
193 break;
194 default:
195 break;
196 }
197 }
198
vjiaoblack955e8792016-08-05 07:55:01 -0700199 bool onClick(Click *click) override {
200 SkScalar x = click->fCurr.fX;
201 SkScalar y = click->fCurr.fY;
202
203 SkScalar dx = x - click->fPrev.fX;
204 SkScalar dy = y - click->fPrev.fY;
205
206 if (fMoveLight) {
207 if (dx != 0 || dy != 0) {
vjiaoblack56f33ea2016-08-26 08:49:46 -0700208 this->updateLights(x, y);
vjiaoblack955e8792016-08-05 07:55:01 -0700209 fLightsChanged = true;
210 this->inval(nullptr);
211 }
212 return true;
213 }
214
215 if (click->fState == Click::State::kUp_State) {
vjiaoblack56f33ea2016-08-26 08:49:46 -0700216 fSelectedRectID = -1;
217 fSelectedSliderID = -1;
vjiaoblack955e8792016-08-05 07:55:01 -0700218 return true;
219 }
220
vjiaoblack56f33ea2016-08-26 08:49:46 -0700221 if (fSelectedRectID > -1) {
222 fTestRects[fSelectedRectID].fGeometry.offset(dx, dy);
vjiaoblack955e8792016-08-05 07:55:01 -0700223
224 fSceneChanged = true;
225 this->inval(nullptr);
226 return true;
227 }
228
vjiaoblack56f33ea2016-08-26 08:49:46 -0700229 if (fSelectedSliderID > -1) {
230 fSliders[fSelectedSliderID].fGeometry.offset(dx, 0);
vjiaoblacke6f5d562016-08-25 06:30:23 -0700231
232 this->updateFromSelectedSlider();
233
234 fLightsChanged = true;
235 this->inval(nullptr);
236 return true;
237 }
238
vjiaoblack955e8792016-08-05 07:55:01 -0700239 // assume last elements are highest
240 for (int i = kNumTestRects - 1; i >= 0; i--) {
241 if (fTestRects[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
vjiaoblack56f33ea2016-08-26 08:49:46 -0700242 fSelectedRectID = i;
vjiaoblack955e8792016-08-05 07:55:01 -0700243 fTestRects[i].fGeometry.offset(dx, dy);
244
245 fSceneChanged = true;
246 this->inval(nullptr);
247 break;
248 }
249 }
250
vjiaoblacke6f5d562016-08-25 06:30:23 -0700251 for (int i = 0; i <= kNumSliders; i++) {
252 if (fSliders[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
vjiaoblack56f33ea2016-08-26 08:49:46 -0700253 fSelectedSliderID = i;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700254 fSliders[i].fGeometry.offset(dx, 0);
255
256 this->updateFromSelectedSlider();
257
258 fLightsChanged = true;
259
260 this->inval(nullptr);
261 break;
262 }
263 }
264
vjiaoblack955e8792016-08-05 07:55:01 -0700265 return true;
266 }
267
268private:
269 static constexpr int kNumTestRects = 3;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700270 static constexpr int kNumSliders = 3;
vjiaoblack955e8792016-08-05 07:55:01 -0700271
272 static const int kWidth = 400;
273 static const int kHeight = 400;
274
vjiaoblack56f33ea2016-08-26 08:49:46 -0700275 bool fSceneChanged;
276 bool fLightsChanged;
277 bool fMoveLight;
278 bool fClearShadowMaps;
279
vjiaoblack955e8792016-08-05 07:55:01 -0700280 struct {
281 SkRect fGeometry;
282 int fDepth;
283 SkColor fColor;
284 } fTestRects[kNumTestRects];
vjiaoblack56f33ea2016-08-26 08:49:46 -0700285 int fSelectedRectID;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700286
287 struct {
288 SkRect fGeometry;
289 SkScalar fOffset;
290 SkScalar fScale;
291 } fSliders[kNumSliders];
vjiaoblack56f33ea2016-08-26 08:49:46 -0700292 int fSelectedSliderID;
vjiaoblacke6f5d562016-08-25 06:30:23 -0700293
vjiaoblack56f33ea2016-08-26 08:49:46 -0700294 SkScalar fLightDepth;
vjiaoblack955e8792016-08-05 07:55:01 -0700295
vjiaoblacke6f5d562016-08-25 06:30:23 -0700296 sk_sp<SkPicture> fPicture;
297 SkShadowParams fShadowParams;
vjiaoblack955e8792016-08-05 07:55:01 -0700298 sk_sp<SkLights> fLights;
299
300 typedef SampleView INHERITED;
301};
302
303//////////////////////////////////////////////////////////////////////////////
304static SkView* MyFactory() { return new ShadowingView; }
305static SkViewRegister reg(MyFactory);
306
307#endif