blob: 1ae95fb68f5cee6e96e6ed2749faa173a4692de8 [file] [log] [blame]
vjiaoblack53da5ba2016-08-01 10:02:31 -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
9#include "gm.h"
vjiaoblack53da5ba2016-08-01 10:02:31 -070010#include "SkPathEffect.h"
11#include "SkPictureRecorder.h"
vjiaoblack955e8792016-08-05 07:55:01 -070012#include "SkShadowPaintFilterCanvas.h"
vjiaoblack53da5ba2016-08-01 10:02:31 -070013#include "SkShadowShader.h"
14#include "SkSurface.h"
15
16#ifdef SK_EXPERIMENTAL_SHADOWING
17
18static sk_sp<SkShader> make_shadow_shader(sk_sp<SkImage> povDepth,
19 sk_sp<SkImage> diffuse,
20 sk_sp<SkLights> lights) {
21
22 sk_sp<SkShader> povDepthShader = povDepth->makeShader(SkShader::kClamp_TileMode,
23 SkShader::kClamp_TileMode);
24
25 sk_sp<SkShader> diffuseShader = diffuse->makeShader(SkShader::kClamp_TileMode,
26 SkShader::kClamp_TileMode);
27
28 return SkShadowShader::Make(std::move(povDepthShader),
29 std::move(diffuseShader),
30 std::move(lights),
31 diffuse->width(), diffuse->height());
32}
33
34static sk_sp<SkPicture> make_test_picture(int width, int height) {
35 SkPictureRecorder recorder;
36
37 // LONG RANGE TODO: eventually add SkBBHFactory (bounding box factory)
38 SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(width, height));
39
40 SkASSERT(canvas->getTotalMatrix().isIdentity());
41 SkPaint paint;
42 paint.setColor(SK_ColorGRAY);
43
44 // LONG RANGE TODO: tag occluders
45 // LONG RANGE TODO: track number of IDs we need (hopefully less than 256)
46 // and determinate the mapping from z to id
47
48 // universal receiver, "ground"
49 canvas->drawRect(SkRect::MakeIWH(width, height), paint);
50
51 // TODO: Maybe add the ID here along with the depth
52
53 paint.setColor(0xFFEE8888);
54
55 canvas->translateZ(80);
56 canvas->drawRect(SkRect::MakeLTRB(200,150,350,300), paint);
57
58 paint.setColor(0xFF88EE88);
59
60 canvas->translateZ(80);
61 canvas->drawRect(SkRect::MakeLTRB(150,200,300,350), paint);
62
63 paint.setColor(0xFF8888EE);
64
65 canvas->translateZ(80);
66 canvas->drawRect(SkRect::MakeLTRB(100,100,250,250), paint);
67 // TODO: Add an assert that Z order matches painter's order
68 // TODO: think about if the Z-order always matching painting order is too strict
69
70 return recorder.finishRecordingAsPicture();
71}
72
73namespace skiagm {
74
vjiaoblack53da5ba2016-08-01 10:02:31 -070075class ShadowMapsGM : public GM {
76public:
77 ShadowMapsGM() {
78 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
79 }
80
81 void onOnceBeforeDraw() override {
82 // Create a light set consisting of
83 // - bluish directional light pointing more right than down
84 // - reddish directional light pointing more down than right
85 // - soft white ambient light
86
87 SkLights::Builder builder;
88 builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.3f, 0.4f),
89 SkVector3::Make(0.2f, 0.1f, 1.0f)));
90 builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.3f, 0.2f),
91 SkVector3::Make(0.1f, 0.2f, 1.0f)));
92 builder.add(SkLights::Light(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
93 fLights = builder.finish();
94 }
95
96protected:
97 static const int kWidth = 400;
98 static const int kHeight = 400;
99
100 SkString onShortName() override {
101 return SkString("shadowmaps");
102 }
103
104 SkISize onISize() override {
105 return SkISize::Make(kWidth, kHeight);
106 }
107
108 void onDraw(SkCanvas* canvas) override {
109 // This picture stores the picture of the scene.
110 // It's used to generate the depth maps.
111 sk_sp<SkPicture> pic(make_test_picture(kWidth, kHeight));
112
113 for (int i = 0; i < fLights->numLights(); ++i) {
114 // skip over ambient lights; they don't cast shadows
115 if (SkLights::Light::kAmbient_LightType == fLights->light(i).type()) {
116 continue;
117 }
118 // TODO: compute the correct size of the depth map from the light properties
119 // TODO: maybe add a kDepth_8_SkColorType
120
vjiaoblack955e8792016-08-05 07:55:01 -0700121 // TODO: find actual max depth of picture
122 SkISize shMapSize = SkShadowPaintFilterCanvas::
123 ComputeDepthMapSize(fLights->light(i), 255, kWidth, kHeight);
124
125 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
vjiaoblack53da5ba2016-08-01 10:02:31 -0700126 kBGRA_8888_SkColorType,
127 kOpaque_SkAlphaType);
128
129 // Create a new surface (that matches the backend of canvas)
130 // for each shadow map
131 sk_sp<SkSurface> surf(canvas->makeSurface(info));
132
133 // Wrap another SPFCanvas around the surface
134 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
135 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
136
137 // set the depth map canvas to have the light we're drawing.
138 SkLights::Builder builder;
139 builder.add(fLights->light(i));
140 sk_sp<SkLights> curLight = builder.finish();
141
142 depthMapCanvas->setLights(std::move(curLight));
143 depthMapCanvas->drawPicture(pic);
144
145 fLights->light(i).setShadowMap(surf->makeImageSnapshot());
146 }
147
148 sk_sp<SkImage> povDepthMap;
149 sk_sp<SkImage> diffuseMap;
150
151 // TODO: pass the depth to the shader in vertices, or uniforms
152 // so we don't have to render depth and color separately
153
154 // povDepthMap
155 {
156 SkLights::Builder builder;
157 builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
158 SkVector3::Make(0.0f, 0.0f, 1.0f)));
159 sk_sp<SkLights> povLight = builder.finish();
160
161 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight,
162 kBGRA_8888_SkColorType,
163 kOpaque_SkAlphaType);
164
165 // Create a new surface (that matches the backend of canvas)
166 // to create the povDepthMap
167 sk_sp<SkSurface> surf(canvas->makeSurface(info));
168
169 // Wrap another SPFCanvas around the surface
170 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
171 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
172
173 // set the depth map canvas to have the light as the user's POV
174 depthMapCanvas->setLights(std::move(povLight));
175
176 depthMapCanvas->drawPicture(pic);
177
178 povDepthMap = surf->makeImageSnapshot();
179 }
180
181 // diffuseMap
182 {
183 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight,
184 kBGRA_8888_SkColorType,
185 kOpaque_SkAlphaType);
186
187 sk_sp<SkSurface> surf(canvas->makeSurface(info));
188 surf->getCanvas()->drawPicture(pic);
189
190 diffuseMap = surf->makeImageSnapshot();
191 }
192
193 SkPaint paint;
194 paint.setShader(make_shadow_shader(std::move(povDepthMap), std::move(diffuseMap), fLights));
195
196 canvas->drawRect(SkRect::MakeIWH(kWidth, kHeight), paint);
197 }
198
199private:
200 sk_sp<SkLights> fLights;
201
202 typedef GM INHERITED;
203};
204
205//////////////////////////////////////////////////////////////////////////////
206
207DEF_GM(return new ShadowMapsGM;)
208}
209
210#endif