• 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 "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 
16 class ShadowingView : public SampleView {
17 public:
ShadowingView()18     ShadowingView()
19         : fSceneChanged(true)
20         , fLightsChanged(true)
21         , fMoveLight(false)
22         , fClearShadowMaps(false)
23         , fSelectedRectID(-1)
24         , fSelectedSliderID(-1)
25         , fLightDepth(400.0f)  {
26         this->setBGColor(0xFFCCCCCC);
27 
28         this->updateLights(100, 100);
29 
30         fTestRects[0].fColor = 0xFFEE8888;
31         fTestRects[0].fDepth = 80;
32         fTestRects[0].fGeometry = SkRect::MakeLTRB(300,200,350,250);
33 
34         fTestRects[1].fColor = 0xFF88EE88;
35         fTestRects[1].fDepth = 160;
36         fTestRects[1].fGeometry = SkRect::MakeLTRB(200,300,250,350);
37 
38         fTestRects[2].fColor = 0xFF8888EE;
39         fTestRects[2].fDepth = 240;
40         fTestRects[2].fGeometry = SkRect::MakeLTRB(100,100,150,150);
41 
42         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 
54         fShadowParams.fShadowRadius = 4.0f;
55         fShadowParams.fBiasingConstant = 0.3f;
56         fShadowParams.fMinVariance = 2048; // we need a higher min variance for point lights
57         fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
58     }
59 
60 protected:
onQuery(SkEvent * evt)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;
73                 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;
80                 case 'q':
81                     fLightDepth += 5.0f;
82                     fMoveLight = true;
83                     break;
84                 case 'B':
85                     if (SkShadowParams::kVariance_ShadowType == fShadowParams.fType) {
86                         fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
87                     } else if (SkShadowParams::kNoBlur_ShadowType ==
88                                fShadowParams.fType) {
89                         fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
90                     }
91                     fLightsChanged = true;
92                     break;
93                 case 'w':
94                     fLightDepth -= 5.0f;
95                     fMoveLight = true;
96                     break;
97                 default:
98                     break;
99             }
100         }
101         return this->INHERITED::onQuery(evt);
102     }
103 
makeTestPicture(int width,int height)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 
onDrawContent(SkCanvas * canvas)134     void onDrawContent(SkCanvas *canvas) override {
135         if (fSceneChanged) {
136             fPicture = this->makeTestPicture(kWidth, kHeight);
137         }
138 
139         if (fSceneChanged || fLightsChanged || fClearShadowMaps) {
140             for (int i = 0; i < fLights->numLights(); i++) {
141                 fLights->light(i).setShadowMap(nullptr);
142             }
143 
144             fSceneChanged = false;
145             fLightsChanged = false;
146             fClearShadowMaps = false;
147         }
148 
149         canvas->setLights(fLights);
150         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         }
157     }
158 
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)159     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
160         return new SkView::Click(this);
161     }
162 
updateLights(int x,int y)163     void updateLights(int x, int y) {
164         SkLights::Builder builder;
165         builder.add(SkLights::Light::MakePoint(SkColor3f::Make(1.0f, 1.0f, 1.0f),
166                                                SkVector3::Make(x,
167                                                                kHeight - y,
168                                                                fLightDepth),
169                                                400, true));
170         fLights = builder.finish();
171     }
172 
updateFromSelectedSlider()173     void updateFromSelectedSlider() {
174         SkScalar newValue = fSliders[fSelectedSliderID].fGeometry.fLeft *
175                             fSliders[fSelectedSliderID].fScale +
176                             fSliders[fSelectedSliderID].fOffset;
177 
178         switch (fSelectedSliderID) {
179             case 0:
180                 fShadowParams.fShadowRadius = newValue;
181                 break;
182             case 1:
183                 fShadowParams.fMinVariance = newValue;
184                 break;
185             case 2:
186                 fShadowParams.fBiasingConstant = newValue;
187                 break;
188             default:
189                 break;
190         }
191     }
192 
onClick(Click * click)193     bool onClick(Click *click) override {
194         SkScalar x = click->fCurr.fX;
195         SkScalar y = click->fCurr.fY;
196 
197         SkScalar dx = x - click->fPrev.fX;
198         SkScalar dy = y - click->fPrev.fY;
199 
200         if (fMoveLight) {
201             if (dx != 0 || dy != 0) {
202                 this->updateLights(x, y);
203                 fLightsChanged = true;
204                 this->inval(nullptr);
205             }
206             return true;
207         }
208 
209         if (click->fState == Click::State::kUp_State) {
210             fSelectedRectID = -1;
211             fSelectedSliderID = -1;
212             return true;
213         }
214 
215         if (fSelectedRectID > -1) {
216             fTestRects[fSelectedRectID].fGeometry.offset(dx, dy);
217 
218             fSceneChanged = true;
219             this->inval(nullptr);
220             return true;
221         }
222 
223         if (fSelectedSliderID > -1) {
224             fSliders[fSelectedSliderID].fGeometry.offset(dx, 0);
225 
226             this->updateFromSelectedSlider();
227 
228             fLightsChanged = true;
229             this->inval(nullptr);
230             return true;
231         }
232 
233         // assume last elements are highest
234         for (int i = kNumTestRects - 1; i >= 0; i--) {
235             if (fTestRects[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
236                 fSelectedRectID = i;
237                 fTestRects[i].fGeometry.offset(dx, dy);
238 
239                 fSceneChanged = true;
240                 this->inval(nullptr);
241                 break;
242             }
243         }
244 
245         for (int i = 0; i <= kNumSliders; i++) {
246             if (fSliders[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
247                 fSelectedSliderID = i;
248                 fSliders[i].fGeometry.offset(dx, 0);
249 
250                 this->updateFromSelectedSlider();
251 
252                 fLightsChanged = true;
253 
254                 this->inval(nullptr);
255                 break;
256             }
257         }
258 
259         return true;
260     }
261 
262 private:
263     static constexpr int kNumTestRects = 3;
264     static constexpr int kNumSliders = 3;
265 
266     static const int kWidth = 400;
267     static const int kHeight = 400;
268 
269     bool fSceneChanged;
270     bool fLightsChanged;
271     bool fMoveLight;
272     bool fClearShadowMaps;
273 
274     struct {
275         SkRect  fGeometry;
276         int     fDepth;
277         SkColor fColor;
278     } fTestRects[kNumTestRects];
279     int fSelectedRectID;
280 
281     struct {
282         SkRect   fGeometry;
283         SkScalar fOffset;
284         SkScalar fScale;
285     } fSliders[kNumSliders];
286     int fSelectedSliderID;
287 
288     SkScalar fLightDepth;
289 
290     sk_sp<SkPicture> fPicture;
291     SkShadowParams fShadowParams;
292     sk_sp<SkLights> fLights;
293 
294     typedef SampleView INHERITED;
295 };
296 
297 //////////////////////////////////////////////////////////////////////////////
MyFactory()298 static SkView* MyFactory() { return new ShadowingView; }
299 static SkViewRegister reg(MyFactory);
300 
301 #endif
302