OLD | NEW |
---|---|
(Empty) | |
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 "SkLights.h" | |
9 #include "SkPoint3.h" | |
10 #include "SkRadialShadowMapShader.h" | |
11 | |
12 //////////////////////////////////////////////////////////////////////////// | |
13 #ifdef SK_EXPERIMENTAL_SHADOWING | |
14 | |
15 | |
16 /** \class SkRadialShadowMapShaderImpl | |
17 This subclass of shader applies shadowing radially around a light | |
18 */ | |
19 class SkRadialShadowMapShaderImpl : public SkShader { | |
20 public: | |
21 /** Create a new shadowing shader that shadows radially around a light | |
22 */ | |
23 SkRadialShadowMapShaderImpl(sk_sp<SkShader> occluderShader, | |
24 sk_sp<SkLights> lights, | |
25 int diffuseWidth, int diffuseHeight) | |
26 : fOccluderShader(std::move(occluderShader)) | |
27 , fLight(std::move(lights)) | |
28 , fWidth(diffuseWidth) | |
29 , fHeight(diffuseHeight) { } | |
30 | |
31 bool isOpaque() const override; | |
32 | |
33 #if SK_SUPPORT_GPU | |
34 sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const overri de; | |
35 #endif | |
36 | |
37 class ShadowMapRadialShaderContext : public SkShader::Context { | |
38 public: | |
39 // The context takes ownership of the states. It will call their destruc tors | |
40 // but will NOT free the memory. | |
41 ShadowMapRadialShaderContext(const SkRadialShadowMapShaderImpl&, const C ontextRec&, | |
42 SkShader::Context* occluderContext, | |
43 void* heapAllocated); | |
44 | |
45 ~ShadowMapRadialShaderContext() override; | |
46 | |
47 void shadeSpan(int x, int y, SkPMColor[], int count) override; | |
48 | |
49 uint32_t getFlags() const override { return fFlags; } | |
50 | |
51 private: | |
52 SkShader::Context* fOccluderContext; | |
53 uint32_t fFlags; | |
54 | |
55 void* fHeapAllocated; | |
56 | |
57 typedef SkShader::Context INHERITED; | |
58 }; | |
59 | |
60 SK_TO_STRING_OVERRIDE() | |
61 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRadialShadowMapShaderI mpl) | |
62 | |
63 protected: | |
64 void flatten(SkWriteBuffer&) const override; | |
65 size_t onContextSize(const ContextRec&) const override; | |
66 Context* onCreateContext(const ContextRec&, void*) const override; | |
67 | |
68 private: | |
69 sk_sp<SkShader> fOccluderShader; | |
70 sk_sp<SkLights> fLight; | |
71 | |
72 int fWidth; | |
73 int fHeight; | |
74 | |
75 friend class SkRadialShadowMapShader; | |
76 | |
77 typedef SkShader INHERITED; | |
78 }; | |
79 | |
80 //////////////////////////////////////////////////////////////////////////// | |
81 | |
82 #if SK_SUPPORT_GPU | |
83 | |
84 #include "GrContext.h" | |
85 #include "GrCoordTransform.h" | |
86 #include "GrFragmentProcessor.h" | |
87 #include "glsl/GrGLSLFragmentProcessor.h" | |
88 #include "glsl/GrGLSLFragmentShaderBuilder.h" | |
89 #include "SkGr.h" | |
90 #include "SkGrPriv.h" | |
91 #include "SkImage_Base.h" | |
92 #include "GrInvariantOutput.h" | |
93 #include "SkSpecialImage.h" | |
94 | |
95 class RadialShadowMapFP : public GrFragmentProcessor { | |
96 public: | |
97 RadialShadowMapFP(sk_sp<GrFragmentProcessor> occluder, | |
98 sk_sp<SkLights> light, | |
99 int diffuseWidth, int diffuseHeight, | |
100 GrContext* context) { | |
101 fLightPos = light->light(0).pos(); | |
102 | |
103 fWidth = diffuseWidth; | |
104 fHeight = diffuseHeight; | |
105 | |
106 this->registerChildProcessor(std::move(occluder)); | |
107 this->initClassID<RadialShadowMapFP>(); | |
108 } | |
109 | |
110 class GLSLRadialShadowMapFP : public GrGLSLFragmentProcessor { | |
111 public: | |
112 GLSLRadialShadowMapFP() { } | |
113 | |
114 void emitCode(EmitArgs& args) override { | |
115 | |
116 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; | |
117 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | |
118 | |
119 const char* lightPosUniName = nullptr; | |
120 | |
121 fLightPosUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | |
122 kVec3f_GrSLType, | |
123 kDefault_GrSLPrecision, | |
124 "lightPos", | |
125 &lightPosUniName); | |
126 | |
127 const char* widthUniName = nullptr; | |
128 const char* heightUniName = nullptr; | |
129 | |
130 fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | |
131 kInt_GrSLType, | |
132 kDefault_GrSLPrecision, | |
133 "width", &widthUniName); | |
134 fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | |
135 kInt_GrSLType, | |
136 kDefault_GrSLPrecision, | |
137 "height", &heightUniName); | |
138 | |
139 | |
140 SkString occluder("occluder"); | |
141 this->emitChild(0, nullptr, &occluder, args); | |
142 | |
143 // the above isn't good enough. so we need to modify the indexing co ordinate as below | |
jvanverth1
2016/09/08 20:30:56
How about:
// Modify the input texture coordinates
| |
144 fragBuilder->codeAppendf("float distHere;"); | |
145 fragBuilder->codeAppendf("float closestDistHere = 0;"); | |
146 fragBuilder->codeAppendf("vec2 coords = vMatrixCoord_0_0_Stage0;"); | |
147 fragBuilder->codeAppendf("coords.y = 0;"); | |
148 fragBuilder->codeAppendf("vec2 destCoords = vec2(0,0);"); | |
149 fragBuilder->codeAppendf("float step = 1.0 / %s;", heightUniName); | |
150 | |
151 // assume that we are at 0, 0 light pos | |
152 // TODO use correct light positions | |
153 | |
154 // this goes through each depth value in the final output buffer, | |
155 // basically raycasting outwards, and finding the first collision. | |
156 fragBuilder->codeAppendf("for (coords.y = 0; coords.y <= 1; coords.y += step) {"); | |
157 | |
158 fragBuilder->codeAppendf("float theta = (coords.x * 2.0 - 1.0) * 3.1415;"); | |
159 fragBuilder->codeAppendf("float r = coords.y;"); | |
160 fragBuilder->codeAppendf("destCoords = " | |
161 "vec2(r * cos(theta), - r * sin(theta)) /2.0 + 0.5;"); | |
162 fragBuilder->codeAppendf("distHere = texture(uTextureSampler0_St age1, " | |
163 "destCoords).b;"); | |
164 fragBuilder->codeAppendf("if (distHere > 0.0) {" | |
165 "closestDistHere = 1-coords.y;" | |
166 "break;}"); | |
167 fragBuilder->codeAppendf("}"); | |
168 | |
169 fragBuilder->codeAppendf("%s = vec4(vec3(closestDistHere),1);", args .fOutputColor); | |
170 } | |
171 | |
172 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, | |
173 GrProcessorKeyBuilder* b) { | |
174 b->add32(0); // nothing to add here | |
175 } | |
176 | |
177 protected: | |
178 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { | |
179 const RadialShadowMapFP &radialShadowMapFP = proc.cast<RadialShadowM apFP>(); | |
180 | |
181 const SkVector3& lightPos = radialShadowMapFP.lightPos(); | |
182 if (lightPos != fLightPos) { | |
183 pdman.set3fv(fLightPosUni, 1, &lightPos.fX); | |
184 fLightPos = lightPos; | |
185 } | |
186 | |
187 int width = radialShadowMapFP.width(); | |
188 if (width != fWidth) { | |
189 pdman.set1i(fWidthUni, width); | |
190 fWidth = width; | |
191 } | |
192 int height = radialShadowMapFP.height(); | |
193 if (height != fHeight) { | |
194 pdman.set1i(fHeightUni, height); | |
195 fHeight = height; | |
196 } | |
197 } | |
198 | |
199 private: | |
200 SkVector3 fLightPos; | |
201 GrGLSLProgramDataManager::UniformHandle fLightPosUni; | |
202 | |
203 int fWidth; | |
204 GrGLSLProgramDataManager::UniformHandle fWidthUni; | |
205 int fHeight; | |
206 GrGLSLProgramDataManager::UniformHandle fHeightUni; | |
207 }; | |
208 | |
209 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { | |
210 GLSLRadialShadowMapFP::GenKey(*this, caps, b); | |
211 } | |
212 | |
213 const char* name() const override { return "RadialShadowMapFP"; } | |
214 | |
215 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { | |
216 inout->mulByUnknownFourComponents(); | |
217 } | |
218 const SkVector3& lightPos() const { | |
219 return fLightPos; | |
220 } | |
221 | |
222 int width() const { return fWidth; } | |
223 int height() const { return fHeight; } | |
224 | |
225 private: | |
226 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { | |
227 return new GLSLRadialShadowMapFP; | |
228 } | |
229 | |
230 bool onIsEqual(const GrFragmentProcessor& proc) const override { | |
231 const RadialShadowMapFP& radialShadowMapFP = proc.cast<RadialShadowMapFP >(); | |
232 | |
233 if (fWidth != radialShadowMapFP.fWidth || fHeight != radialShadowMapFP.f Height) { | |
234 return false; | |
235 } | |
236 | |
237 if (fLightPos != radialShadowMapFP.fLightPos) { | |
238 return false; | |
239 } | |
240 | |
241 return true; | |
242 } | |
243 | |
244 SkVector3 fLightPos; | |
245 | |
246 int fHeight; | |
247 int fWidth; | |
248 }; | |
249 | |
250 //////////////////////////////////////////////////////////////////////////// | |
251 | |
252 sk_sp<GrFragmentProcessor> SkRadialShadowMapShaderImpl::asFragmentProcessor | |
253 (const AsFPArgs& fpargs) const { | |
254 | |
255 sk_sp<GrFragmentProcessor> occluderFP = fOccluderShader->asFragmentProcessor (fpargs); | |
256 | |
257 sk_sp<GrFragmentProcessor> shadowFP = sk_make_sp<RadialShadowMapFP>(std::mov e(occluderFP), | |
258 fLight, fWidth, fHeight, | |
259 fpargs.f Context); | |
260 return shadowFP; | |
261 } | |
262 | |
263 #endif | |
264 | |
265 //////////////////////////////////////////////////////////////////////////// | |
266 | |
267 bool SkRadialShadowMapShaderImpl::isOpaque() const { | |
268 return fOccluderShader->isOpaque(); | |
269 } | |
270 | |
271 SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::ShadowMapRadialShader Context( | |
272 const SkRadialShadowMapShaderImpl& shader, const ContextRec& rec, | |
273 SkShader::Context* occluderContext, | |
274 void* heapAllocated) | |
275 : INHERITED(shader, rec) | |
276 , fOccluderContext(occluderContext) | |
277 , fHeapAllocated(heapAllocated) { | |
278 bool isOpaque = shader.isOpaque(); | |
279 | |
280 // update fFlags | |
281 uint32_t flags = 0; | |
282 if (isOpaque && (255 == this->getPaintAlpha())) { | |
283 flags |= kOpaqueAlpha_Flag; | |
284 } | |
285 | |
286 fFlags = flags; | |
287 } | |
288 | |
289 SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::~ShadowMapRadialShade rContext() { | |
290 // The dependencies have been created outside of the context on memory that was allocated by | |
291 // the onCreateContext() method. Call the destructors and free the memory. | |
292 fOccluderContext->~Context(); | |
293 | |
294 sk_free(fHeapAllocated); | |
295 } | |
296 | |
297 static inline SkPMColor convert(SkColor3f color, U8CPU a) { | |
298 if (color.fX <= 0.0f) { | |
299 color.fX = 0.0f; | |
300 } else if (color.fX >= 255.0f) { | |
301 color.fX = 255.0f; | |
302 } | |
303 | |
304 if (color.fY <= 0.0f) { | |
305 color.fY = 0.0f; | |
306 } else if (color.fY >= 255.0f) { | |
307 color.fY = 255.0f; | |
308 } | |
309 | |
310 if (color.fZ <= 0.0f) { | |
311 color.fZ = 0.0f; | |
312 } else if (color.fZ >= 255.0f) { | |
313 color.fZ = 255.0f; | |
314 } | |
315 | |
316 return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ) ; | |
317 } | |
318 | |
319 // larger is better (fewer times we have to loop), but we shouldn't | |
320 // take up too much stack-space (each one here costs 16 bytes) | |
321 #define BUFFER_MAX 16 | |
322 void SkRadialShadowMapShaderImpl::ShadowMapRadialShaderContext::shadeSpan | |
323 (int x, int y, SkPMColor result[], int count) { | |
324 do { | |
325 int n = SkTMin(count, BUFFER_MAX); | |
326 | |
327 // just fill with white for now | |
328 SkPMColor accum = convert(SkColor3f::Make(1.0f, 1.0f, 1.0f), 0xFF); | |
329 | |
330 for (int i = 0; i < n; ++i) { | |
331 result[i] = accum; | |
332 } | |
333 | |
334 result += n; | |
335 x += n; | |
336 count -= n; | |
337 } while (count > 0); | |
338 } | |
339 | |
340 //////////////////////////////////////////////////////////////////////////// | |
341 | |
342 #ifndef SK_IGNORE_TO_STRING | |
343 void SkRadialShadowMapShaderImpl::toString(SkString* str) const { | |
344 str->appendf("RadialShadowMapShader: ()"); | |
345 } | |
346 #endif | |
347 | |
348 sk_sp<SkFlattenable> SkRadialShadowMapShaderImpl::CreateProc(SkReadBuffer& buf) { | |
349 | |
350 // Discarding SkShader flattenable params | |
351 bool hasLocalMatrix = buf.readBool(); | |
352 SkAssertResult(!hasLocalMatrix); | |
353 | |
354 sk_sp<SkLights> light = SkLights::MakeFromBuffer(buf); | |
355 | |
356 int diffuseWidth = buf.readInt(); | |
357 int diffuseHeight = buf.readInt(); | |
358 | |
359 sk_sp<SkShader> occluderShader(buf.readFlattenable<SkShader>()); | |
360 | |
361 return sk_make_sp<SkRadialShadowMapShaderImpl>(std::move(occluderShader), | |
362 std::move(light), | |
363 diffuseWidth, diffuseHeight); | |
364 } | |
365 | |
366 void SkRadialShadowMapShaderImpl::flatten(SkWriteBuffer& buf) const { | |
367 this->INHERITED::flatten(buf); | |
368 | |
369 fLight->flatten(buf); | |
370 | |
371 buf.writeInt(fWidth); | |
372 buf.writeInt(fHeight); | |
373 | |
374 buf.writeFlattenable(fOccluderShader.get()); | |
375 } | |
376 | |
377 size_t SkRadialShadowMapShaderImpl::onContextSize(const ContextRec& rec) const { | |
378 return sizeof(ShadowMapRadialShaderContext); | |
379 } | |
380 | |
381 SkShader::Context* SkRadialShadowMapShaderImpl::onCreateContext(const ContextRec & rec, | |
382 void* storage) c onst { | |
383 size_t heapRequired = fOccluderShader->contextSize(rec); | |
384 | |
385 void* heapAllocated = sk_malloc_throw(heapRequired); | |
386 | |
387 void* occluderContextStorage = heapAllocated; | |
388 | |
389 SkShader::Context* occluderContext = | |
390 fOccluderShader->createContext(rec, occluderContextStorage); | |
391 | |
392 if (!occluderContext) { | |
393 sk_free(heapAllocated); | |
394 return nullptr; | |
395 } | |
396 | |
397 return new (storage) ShadowMapRadialShaderContext(*this, rec, occluderContex t, heapAllocated); | |
398 } | |
399 | |
400 /////////////////////////////////////////////////////////////////////////////// | |
401 | |
402 sk_sp<SkShader> SkRadialShadowMapShader::Make(sk_sp<SkShader> occluderShader, | |
403 sk_sp<SkLights> light, | |
404 int diffuseWidth, int diffuseHeigh t) { | |
405 if (!occluderShader) { | |
406 // TODO: Use paint's color in absence of a diffuseShader | |
407 // TODO: Use a default implementation of normalSource instead | |
408 return nullptr; | |
409 } | |
410 | |
411 return sk_make_sp<SkRadialShadowMapShaderImpl>(std::move(occluderShader), | |
412 std::move(light), | |
413 diffuseWidth, diffuseHeight); | |
414 } | |
415 | |
416 /////////////////////////////////////////////////////////////////////////////// | |
417 | |
418 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRadialShadowMapShader) | |
419 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialShadowMapShaderImpl) | |
420 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | |
421 | |
422 /////////////////////////////////////////////////////////////////////////////// | |
423 | |
424 #endif | |
OLD | NEW |