blob: ef45968f5a8b4aab3c8d4aeb7095fa99c3bf56b8 [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
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 "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000011#include "GrProgramStageFactory.h"
12#include "gl/GrGLProgramStage.h"
13#include "gl/GrGLSL.h"
14#include "gl/GrGLTexture.h"
15#include "GrCustomStage.h"
16
17class GrGLDiffuseLightingEffect;
18class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000019
20// FIXME: Eventually, this should be implemented properly, and put in
21// SkScalar.h.
22#define SkScalarPow(x, y) SkFloatToScalar(powf(SkScalarToFloat(x), SkScalarToFloat(y)))
23namespace {
24
25const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
26const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
27const SkScalar gOneHalf = SkFloatToScalar(0.5f);
28const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
29
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000030void setUniformPoint3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
31 float x = SkScalarToFloat(point.fX);
32 float y = SkScalarToFloat(point.fY);
33 float z = SkScalarToFloat(point.fZ);
34 GR_GL_CALL(gl, Uniform3f(location, x, y, z));
35}
36
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037// Shift matrix components to the left, as we advance pixels to the right.
38inline void shiftMatrixLeft(int m[9]) {
39 m[0] = m[1];
40 m[3] = m[4];
41 m[6] = m[7];
42 m[1] = m[2];
43 m[4] = m[5];
44 m[7] = m[8];
45}
46
47class DiffuseLightingType {
48public:
49 DiffuseLightingType(SkScalar kd)
50 : fKD(kd) {}
51 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
52 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
53 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
54 SkPoint3 color(lightColor * colorScale);
55 return SkPackARGB32(255,
56 SkScalarFloorToInt(color.fX),
57 SkScalarFloorToInt(color.fY),
58 SkScalarFloorToInt(color.fZ));
59 }
60private:
61 SkScalar fKD;
62};
63
64class SpecularLightingType {
65public:
66 SpecularLightingType(SkScalar ks, SkScalar shininess)
67 : fKS(ks), fShininess(shininess) {}
68 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
69 SkPoint3 halfDir(surfaceTolight);
70 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
71 halfDir.normalize();
72 SkScalar colorScale = SkScalarMul(fKS,
73 SkScalarPow(normal.dot(halfDir), fShininess));
74 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
75 SkPoint3 color(lightColor * colorScale);
76 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
77 SkScalarFloorToInt(color.fX),
78 SkScalarFloorToInt(color.fY),
79 SkScalarFloorToInt(color.fZ));
80 }
81private:
82 SkScalar fKS;
83 SkScalar fShininess;
84};
85
86inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
87 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
88}
89
90inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
91 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
92 SkScalarMul(-y, surfaceScale),
93 SK_Scalar1);
94 vector.normalize();
95 return vector;
96}
97
98inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
99 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
100 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
101 surfaceScale);
102}
103
104inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
105 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
106 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
107 surfaceScale);
108}
109
110inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
111 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
112 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
113 surfaceScale);
114}
115
116inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
117 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
118 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
119 surfaceScale);
120}
121
122
123inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
124 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
125 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
126 surfaceScale);
127}
128
129inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
130 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
131 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
132 surfaceScale);
133}
134
135inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
137 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
138 surfaceScale);
139}
140
141inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
142 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
143 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
144 surfaceScale);
145}
146
147inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
148 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
149 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
150 surfaceScale);
151}
152
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000153template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000154 const LightType* l = static_cast<const LightType*>(light);
155 int y = 0;
156 {
157 const SkPMColor* row1 = src.getAddr32(0, 0);
158 const SkPMColor* row2 = src.getAddr32(0, 1);
159 SkPMColor* dptr = dst->getAddr32(0, 0);
160 int m[9];
161 int x = 0;
162 m[4] = SkGetPackedA32(*row1++);
163 m[5] = SkGetPackedA32(*row1++);
164 m[7] = SkGetPackedA32(*row2++);
165 m[8] = SkGetPackedA32(*row2++);
166 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000167 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000168 for (x = 1; x < src.width() - 1; ++x)
169 {
170 shiftMatrixLeft(m);
171 m[5] = SkGetPackedA32(*row1++);
172 m[8] = SkGetPackedA32(*row2++);
173 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000174 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000175 }
176 shiftMatrixLeft(m);
177 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000178 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000179 }
180
181 for (++y; y < src.height() - 1; ++y) {
182 const SkPMColor* row0 = src.getAddr32(0, y - 1);
183 const SkPMColor* row1 = src.getAddr32(0, y);
184 const SkPMColor* row2 = src.getAddr32(0, y + 1);
185 SkPMColor* dptr = dst->getAddr32(0, y);
186 int m[9];
187 int x = 0;
188 m[1] = SkGetPackedA32(*row0++);
189 m[2] = SkGetPackedA32(*row0++);
190 m[4] = SkGetPackedA32(*row1++);
191 m[5] = SkGetPackedA32(*row1++);
192 m[7] = SkGetPackedA32(*row2++);
193 m[8] = SkGetPackedA32(*row2++);
194 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000195 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000196 for (x = 1; x < src.width() - 1; ++x) {
197 shiftMatrixLeft(m);
198 m[2] = SkGetPackedA32(*row0++);
199 m[5] = SkGetPackedA32(*row1++);
200 m[8] = SkGetPackedA32(*row2++);
201 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000202 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000203 }
204 shiftMatrixLeft(m);
205 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000206 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000207 }
208
209 {
210 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
211 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
212 int x = 0;
213 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
214 int m[9];
215 m[1] = SkGetPackedA32(*row0++);
216 m[2] = SkGetPackedA32(*row0++);
217 m[4] = SkGetPackedA32(*row1++);
218 m[5] = SkGetPackedA32(*row1++);
219 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000220 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 for (x = 1; x < src.width() - 1; ++x)
222 {
223 shiftMatrixLeft(m);
224 m[2] = SkGetPackedA32(*row0++);
225 m[5] = SkGetPackedA32(*row1++);
226 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000227 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000228 }
229 shiftMatrixLeft(m);
230 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000231 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000232 }
233}
234
235SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
236 SkPoint3 point;
237 point.fX = buffer.readScalar();
238 point.fY = buffer.readScalar();
239 point.fZ = buffer.readScalar();
240 return point;
241};
242
243void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
244 buffer.writeScalar(point.fX);
245 buffer.writeScalar(point.fY);
246 buffer.writeScalar(point.fZ);
247};
248
249class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
250public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000251 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000252 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
253
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000254 virtual bool asNewCustomStage(GrCustomStage** stage) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000255 SkScalar kd() const { return fKD; }
256
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000257protected:
258 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
259 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
260 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
261 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
262
263
264private:
265 typedef SkLightingImageFilter INHERITED;
266 SkScalar fKD;
267};
268
269class SkSpecularLightingImageFilter : public SkLightingImageFilter {
270public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000271 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000272 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
273
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000274 virtual bool asNewCustomStage(GrCustomStage** stage) const SK_OVERRIDE;
275 SkScalar ks() const { return fKS; }
276 SkScalar shininess() const { return fShininess; }
277
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000278protected:
279 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
280 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
281 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
282 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
283
284private:
285 typedef SkLightingImageFilter INHERITED;
286 SkScalar fKS;
287 SkScalar fShininess;
288};
289
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000290
291class GrLightingEffect : public GrCustomStage {
292public:
293 GrLightingEffect(const SkLight* light, SkScalar surfaceScale);
294 virtual ~GrLightingEffect();
295
296 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
297
298 const SkLight* light() const { return fLight; }
299 SkScalar surfaceScale() const { return fSurfaceScale; }
300private:
301 typedef GrCustomStage INHERITED;
302 const SkLight* fLight;
303 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000304};
305
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000306class GrDiffuseLightingEffect : public GrLightingEffect {
307public:
308 GrDiffuseLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar kd);
309
310 static const char* Name() { return "DiffuseLighting"; }
311
312 typedef GrGLDiffuseLightingEffect GLProgramStage;
313
314 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
315 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
316 SkScalar kd() const { return fKD; }
317private:
318 typedef GrLightingEffect INHERITED;
319 SkScalar fKD;
320};
321
322class GrSpecularLightingEffect : public GrLightingEffect {
323public:
324 GrSpecularLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
325
326 static const char* Name() { return "SpecularLighting"; }
327
328 typedef GrGLSpecularLightingEffect GLProgramStage;
329
330 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
331 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
332 SkScalar ks() const { return fKS; }
333 SkScalar shininess() const { return fShininess; }
334
335private:
336 typedef GrLightingEffect INHERITED;
337 SkScalar fKS;
338 SkScalar fShininess;
339};
340
341///////////////////////////////////////////////////////////////////////////////
342
343class GrGLLight {
344public:
345 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
346 virtual void emitVS(SkString* builder) const {}
347 virtual void emitFuncs(SkString* builder) const {}
348 virtual void emitSurfaceToLight(SkString* builder, const char* z) const = 0;
349 virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
350 virtual void initUniforms(const GrGLInterface* gl, int programID);
351 virtual void setData(const GrGLInterface*, const SkLight* light) const;
352
353private:
354 typedef SkRefCnt INHERITED;
355
356protected:
357 const GrGLShaderVar* fColorVar;
358 int fColorVarLocation;
359};
360
361///////////////////////////////////////////////////////////////////////////////
362
363class GrGLDistantLight : public GrGLLight {
364public:
365 virtual void setupVariables(GrGLShaderBuilder* state, int stage) SK_OVERRIDE;
366 virtual void initUniforms(const GrGLInterface* gl, int programID) SK_OVERRIDE;
367 virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
368 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
369
370private:
371 typedef GrGLLight INHERITED;
372 const GrGLShaderVar* fDirectionVar;
373 int fDirectionLocation;
374};
375
376///////////////////////////////////////////////////////////////////////////////
377
378class GrGLPointLight : public GrGLLight {
379public:
380 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
381 virtual void initUniforms(const GrGLInterface* gl, int programID);
382 virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
383 virtual void emitVS(SkString* builder) const;
384 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
385
386private:
387 typedef GrGLLight INHERITED;
388 SkPoint3 fLocation;
389 const GrGLShaderVar* fLocationVar;
390 int fLocationLocation;
391 const char* fHeightVaryingName;
392};
393
394///////////////////////////////////////////////////////////////////////////////
395
396class GrGLSpotLight : public GrGLLight {
397public:
398 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
399 virtual void initUniforms(const GrGLInterface* gl, int programID);
400 virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
401 virtual void emitVS(SkString* builder) const;
402 virtual void emitFuncs(SkString* builder) const;
403 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
404 virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
405
406private:
407 typedef GrGLLight INHERITED;
408
409 const GrGLShaderVar* fLocationVar;
410 int fLocationLocation;
411 const GrGLShaderVar* fExponentVar;
412 int fExponentLocation;
413 const GrGLShaderVar* fCosOuterConeAngleVar;
414 int fCosOuterConeAngleLocation;
415 const GrGLShaderVar* fCosInnerConeAngleVar;
416 int fCosInnerConeAngleLocation;
417 const GrGLShaderVar* fConeScaleVar;
418 int fConeScaleLocation;
419 const GrGLShaderVar* fSVar;
420 int fSLocation;
421 const char* fHeightVaryingName;
422};
423
424};
425
426///////////////////////////////////////////////////////////////////////////////
427
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000428class SkLight : public SkFlattenable {
429public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000430 SK_DECLARE_INST_COUNT(SkLight)
431
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000432 enum LightType {
433 kDistant_LightType,
434 kPoint_LightType,
435 kSpot_LightType,
436 };
437 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000438 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000439 virtual GrGLLight* createGLLight() const = 0;
440 virtual bool isEqual(const SkLight& other) const {
441 return fColor == other.fColor;
442 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000443
djsollen@google.com08337772012-06-26 14:33:13 +0000444protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000445 SkLight(SkColor color)
446 : fColor(SkIntToScalar(SkColorGetR(color)),
447 SkIntToScalar(SkColorGetG(color)),
448 SkIntToScalar(SkColorGetB(color))) {}
449 SkLight(SkFlattenableReadBuffer& buffer)
450 : INHERITED(buffer) {
451 fColor = readPoint3(buffer);
452 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000453 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000454 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000455 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456 }
djsollen@google.com08337772012-06-26 14:33:13 +0000457
458private:
459 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000460 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461};
462
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000463SK_DEFINE_INST_COUNT(SkLight)
464
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000465///////////////////////////////////////////////////////////////////////////////
466
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000467class SkDistantLight : public SkLight {
468public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000469 SkDistantLight(const SkPoint3& direction, SkColor color)
470 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471 }
djsollen@google.com08337772012-06-26 14:33:13 +0000472
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000473 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
474 return fDirection;
475 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000476 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000477 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000478 const SkPoint3& direction() const { return fDirection; }
479 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000480
481 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
482
djsollen@google.com08337772012-06-26 14:33:13 +0000483protected:
484 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
485 fDirection = readPoint3(buffer);
486 }
487 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
488 INHERITED::flatten(buffer);
489 writePoint3(fDirection, buffer);
490 }
491
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000492private:
djsollen@google.com08337772012-06-26 14:33:13 +0000493 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000494 SkPoint3 fDirection;
495};
496
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000497///////////////////////////////////////////////////////////////////////////////
498
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000499class SkPointLight : public SkLight {
500public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000501 SkPointLight(const SkPoint3& location, SkColor color)
502 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000503
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000504 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
505 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
506 fLocation.fY - SkIntToScalar(y),
507 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
508 direction.normalize();
509 return direction;
510 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000511 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000513 const SkPoint3& location() const { return fLocation; }
514 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
515 return new GrGLPointLight();
516 }
517 bool isEqual(const SkLight& other) SK_OVERRIDE {
518 if (other.type() != kPoint_LightType) {
519 return false;
520 }
521 const SkPointLight& o = static_cast<const SkPointLight&>(other);
522 return INHERITED::isEqual(other) &&
523 fLocation == o.fLocation;
524 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525
526 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
527
djsollen@google.com08337772012-06-26 14:33:13 +0000528protected:
529 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
530 fLocation = readPoint3(buffer);
531 }
532 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
533 INHERITED::flatten(buffer);
534 writePoint3(fLocation, buffer);
535 }
536
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000537private:
djsollen@google.com08337772012-06-26 14:33:13 +0000538 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539 SkPoint3 fLocation;
540};
541
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000542///////////////////////////////////////////////////////////////////////////////
543
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000544class SkSpotLight : public SkLight {
545public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000546 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
547 : INHERITED(color),
548 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000549 fTarget(target),
550 fSpecularExponent(specularExponent)
551 {
552 fS = target - location;
553 fS.normalize();
554 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
555 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
556 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
557 fConeScale = SkScalarInvert(antiAliasThreshold);
558 }
djsollen@google.com08337772012-06-26 14:33:13 +0000559
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
561 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
562 fLocation.fY - SkIntToScalar(y),
563 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
564 direction.normalize();
565 return direction;
566 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000567 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000568 SkScalar cosAngle = -surfaceToLight.dot(fS);
569 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000570 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000571 }
572 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
573 if (cosAngle < fCosInnerConeAngle) {
574 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000575 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000576 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000577 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000578 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000579 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
580 return new GrGLSpotLight();
581 }
djsollen@google.com08337772012-06-26 14:33:13 +0000582 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000583 const SkPoint3& location() const { return fLocation; }
584 const SkPoint3& target() const { return fTarget; }
585 SkScalar specularExponent() const { return fSpecularExponent; }
586 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
587 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
588 SkScalar coneScale() const { return fConeScale; }
589 SkPoint3 s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000590
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
592
djsollen@google.com08337772012-06-26 14:33:13 +0000593protected:
594 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
595 fLocation = readPoint3(buffer);
596 fTarget = readPoint3(buffer);
597 fSpecularExponent = buffer.readScalar();
598 fCosOuterConeAngle = buffer.readScalar();
599 fCosInnerConeAngle = buffer.readScalar();
600 fConeScale = buffer.readScalar();
601 fS = readPoint3(buffer);
602 }
603 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
604 INHERITED::flatten(buffer);
605 writePoint3(fLocation, buffer);
606 writePoint3(fTarget, buffer);
607 buffer.writeScalar(fSpecularExponent);
608 buffer.writeScalar(fCosOuterConeAngle);
609 buffer.writeScalar(fCosInnerConeAngle);
610 buffer.writeScalar(fConeScale);
611 writePoint3(fS, buffer);
612 }
613
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000614 virtual bool isEqual(const SkLight& other) SK_OVERRIDE {
615 if (other.type() != kSpot_LightType) {
616 return false;
617 }
618
619 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
620 return INHERITED::isEqual(other) &&
621 fLocation == o.fLocation &&
622 fTarget == o.fTarget &&
623 fSpecularExponent == o.fSpecularExponent &&
624 fCosOuterConeAngle == o.fCosOuterConeAngle;
625 }
626
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000627private:
djsollen@google.com08337772012-06-26 14:33:13 +0000628 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000629 SkPoint3 fLocation;
630 SkPoint3 fTarget;
631 SkScalar fSpecularExponent;
632 SkScalar fCosOuterConeAngle;
633 SkScalar fCosInnerConeAngle;
634 SkScalar fConeScale;
635 SkPoint3 fS;
636};
637
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638///////////////////////////////////////////////////////////////////////////////
639
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000640SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000641 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000642 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
643{
644 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000645 // our caller knows that we take ownership of the light, so we don't
646 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000647}
648
649SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000650 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000651 SkScalar kd) {
652 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000653 new SkDistantLight(direction, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000654}
655
656SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000657 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000658 SkScalar kd) {
659 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000660 new SkPointLight(location, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000661}
662
663SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000664 const SkPoint3& location, const SkPoint3& target,
665 SkScalar specularExponent, SkScalar cutoffAngle,
666 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000667 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000668 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
669 surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000670}
671
672SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000673 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000674 SkScalar ks, SkScalar shininess) {
675 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000676 new SkDistantLight(direction, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000677}
678
679SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000680 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
681 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000682 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000683 new SkPointLight(location, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000684}
685
686SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000687 const SkPoint3& location, const SkPoint3& target,
688 SkScalar specularExponent, SkScalar cutoffAngle,
689 SkColor lightColor, SkScalar surfaceScale,
690 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000692 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
693 surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000694}
695
696SkLightingImageFilter::~SkLightingImageFilter() {
697 fLight->unref();
698}
699
700SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
701 : INHERITED(buffer)
702{
djsollen@google.com08337772012-06-26 14:33:13 +0000703 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704 fSurfaceScale = buffer.readScalar();
705}
706
707void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
708 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000709 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000710 buffer.writeScalar(fSurfaceScale);
711}
712
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000713///////////////////////////////////////////////////////////////////////////////
714
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000715SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
716 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000717 fKD(kd)
718{
719}
720
721SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
722 : INHERITED(buffer)
723{
724 fKD = buffer.readScalar();
725}
726
727void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
728 this->INHERITED::flatten(buffer);
729 buffer.writeScalar(fKD);
730}
731
732bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
733 const SkBitmap& src,
734 const SkMatrix&,
735 SkBitmap* dst,
736 SkIPoint*) {
737 if (src.config() != SkBitmap::kARGB_8888_Config) {
738 return false;
739 }
740 SkAutoLockPixels alp(src);
741 if (!src.getPixels()) {
742 return false;
743 }
744 if (src.width() < 2 || src.height() < 2) {
745 return false;
746 }
747 dst->setConfig(src.config(), src.width(), src.height());
748 dst->allocPixels();
749
750 DiffuseLightingType lightingType(fKD);
751 switch (light()->type()) {
752 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000753 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000754 break;
755 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000756 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000757 break;
758 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000759 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000760 break;
761 }
762 return true;
763}
764
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000765bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage) const {
766 if (stage) {
767 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
768 *stage = new GrDiffuseLightingEffect(light(), scale, kd());
769 }
770 return true;
771}
772
773///////////////////////////////////////////////////////////////////////////////
774
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000775SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
776 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000777 fKS(ks),
778 fShininess(shininess)
779{
780}
781
782SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
783 : INHERITED(buffer)
784{
785 fKS = buffer.readScalar();
786 fShininess = buffer.readScalar();
787}
788
789void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
790 this->INHERITED::flatten(buffer);
791 buffer.writeScalar(fKS);
792 buffer.writeScalar(fShininess);
793}
794
795bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
796 const SkBitmap& src,
797 const SkMatrix&,
798 SkBitmap* dst,
799 SkIPoint*) {
800 if (src.config() != SkBitmap::kARGB_8888_Config) {
801 return false;
802 }
803 SkAutoLockPixels alp(src);
804 if (!src.getPixels()) {
805 return false;
806 }
807 if (src.width() < 2 || src.height() < 2) {
808 return false;
809 }
810 dst->setConfig(src.config(), src.width(), src.height());
811 dst->allocPixels();
812
813 SpecularLightingType lightingType(fKS, fShininess);
814 switch (light()->type()) {
815 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000816 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000817 break;
818 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000819 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000820 break;
821 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000822 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000823 break;
824 }
825 return true;
826}
827
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000828bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage) const {
829 if (stage) {
830 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
831 *stage = new GrSpecularLightingEffect(light(), scale, ks(), shininess());
832 }
833 return true;
834}
835
836///////////////////////////////////////////////////////////////////////////////
837
838class GrGLLightingEffect : public GrGLProgramStage {
839public:
840 GrGLLightingEffect(const GrProgramStageFactory& factory,
841 const GrCustomStage& stage);
842 virtual ~GrGLLightingEffect();
843
844 virtual void setupVariables(GrGLShaderBuilder* state,
845 int stage) SK_OVERRIDE;
846 virtual void emitVS(GrGLShaderBuilder* state,
847 const char* vertexCoords) SK_OVERRIDE;
848 virtual void emitFS(GrGLShaderBuilder* state,
849 const char* outputColor,
850 const char* inputColor,
851 const char* samplerName) SK_OVERRIDE;
852
853 virtual void emitLightFunc(SkString* funcs) = 0;
854
855 static inline StageKey GenKey(const GrCustomStage& s);
856
857 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
858 virtual void setData(const GrGLInterface*,
859 const GrGLTexture&,
860 const GrCustomStage&,
861 int stageNum) SK_OVERRIDE;
862
863private:
864 typedef GrGLProgramStage INHERITED;
865
866 const GrGLShaderVar* fImageIncrementVar;
867 GrGLint fImageIncrementLocation;
868 const GrGLShaderVar* fSurfaceScaleVar;
869 GrGLint fSurfaceScaleLocation;
870 GrGLLight* fLight;
871};
872
873///////////////////////////////////////////////////////////////////////////////
874
875class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
876public:
877 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
878 const GrCustomStage& stage);
879 virtual void setupVariables(GrGLShaderBuilder* state,
880 int stage) SK_OVERRIDE;
881 virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
882 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
883 virtual void setData(const GrGLInterface*,
884 const GrGLTexture&,
885 const GrCustomStage&,
886 int stageNum) SK_OVERRIDE;
887
888private:
889 typedef GrGLLightingEffect INHERITED;
890
891 const GrGLShaderVar* fKDVar;
892 GrGLint fKDLocation;
893};
894
895///////////////////////////////////////////////////////////////////////////////
896
897class GrGLSpecularLightingEffect : public GrGLLightingEffect {
898public:
899 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
900 const GrCustomStage& stage);
901 virtual void setupVariables(GrGLShaderBuilder* state,
902 int stage) SK_OVERRIDE;
903 virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
904 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
905 virtual void setData(const GrGLInterface*,
906 const GrGLTexture&,
907 const GrCustomStage&,
908 int stageNum) SK_OVERRIDE;
909
910private:
911 typedef GrGLLightingEffect INHERITED;
912
913 const GrGLShaderVar* fKSVar;
914 GrGLint fKSLocation;
915 const GrGLShaderVar* fShininessVar;
916 GrGLint fShininessLocation;
917};
918
919///////////////////////////////////////////////////////////////////////////////
920
921GrLightingEffect::GrLightingEffect(const SkLight* light, SkScalar surfaceScale)
922 : fLight(light)
923 , fSurfaceScale(surfaceScale) {
924 fLight->ref();
925}
926
927GrLightingEffect::~GrLightingEffect() {
928 fLight->unref();
929}
930
931bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
932 const GrLightingEffect& s =
933 static_cast<const GrLightingEffect&>(sBase);
934 return fLight->isEqual(*s.fLight) &&
935 fSurfaceScale == s.fSurfaceScale;
936}
937
938///////////////////////////////////////////////////////////////////////////////
939
940GrDiffuseLightingEffect::GrDiffuseLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar kd)
941 : INHERITED(light, surfaceScale), fKD(kd) {
942}
943
944const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
945 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
946}
947
948bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
949 const GrDiffuseLightingEffect& s =
950 static_cast<const GrDiffuseLightingEffect&>(sBase);
951 return INHERITED::isEqual(sBase) &&
952 this->kd() == s.kd();
953}
954
955///////////////////////////////////////////////////////////////////////////////
956
957GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
958 const GrCustomStage& stage)
959 : GrGLProgramStage(factory)
960 , fImageIncrementVar(NULL)
961 , fImageIncrementLocation(0)
962 , fSurfaceScaleVar(NULL)
963 , fSurfaceScaleLocation(0) {
964 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
965 fLight = m.light()->createGLLight();
966}
967
968GrGLLightingEffect::~GrGLLightingEffect() {
969 delete fLight;
970}
971
972void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
973 fImageIncrementVar = &state->addUniform(
974 GrGLShaderBuilder::kFragment_ShaderType,
975 kVec2f_GrSLType, "uImageIncrement", stage);
976 fSurfaceScaleVar = &state->addUniform(
977 GrGLShaderBuilder::kFragment_ShaderType,
978 kFloat_GrSLType, "uSurfaceScale", stage);
979 fLight->setupVariables(state, stage);
980}
981
982void GrGLLightingEffect::emitVS(GrGLShaderBuilder* state,
983 const char* vertexCoords) {
984 fLight->emitVS(&state->fVSCode);
985}
986
987void GrGLLightingEffect::initUniforms(const GrGLInterface* gl,
988 int programID) {
989 GR_GL_CALL_RET(gl, fSurfaceScaleLocation,
990 GetUniformLocation(programID,
991 fSurfaceScaleVar->getName().c_str()));
992 GR_GL_CALL_RET(gl, fImageIncrementLocation,
993 GetUniformLocation(programID,
994 fImageIncrementVar->getName().c_str()));
995 fLight->initUniforms(gl, programID);
996}
997
998void GrGLLightingEffect::emitFS(GrGLShaderBuilder* state,
999 const char* outputColor,
1000 const char* inputColor,
1001 const char* samplerName) {
1002 SkString* code = &state->fFSCode;
1003 SkString* funcs = &state->fFSFunctions;
1004 fLight->emitFuncs(funcs);
1005 emitLightFunc(funcs);
1006 funcs->appendf("float sobel(float a, float b, float c, float d, float e, float f, float scale) {\n");
1007 funcs->appendf("\treturn (-a + b - 2 * c + 2 * d -e + f) * scale;\n");
1008 funcs->appendf("}\n");
1009 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1010 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1011 funcs->appendf("}\n");
1012 funcs->append("\n\
1013vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1014 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1015 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1016 surfaceScale);\n}\n");
1017
1018 code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
1019 code->appendf("\t\tfloat m[9];\n");
1020 int index = 0;
1021 for (int dy = -1; dy <= 1; dy++) {
1022 for (int dx = -1; dx <= 1; dx++) {
1023 SkString texCoords;
1024 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, fImageIncrementVar->getName().c_str());
1025 code->appendf("\t\tm[%d] = ", index++);
1026 state->emitTextureLookup(samplerName, texCoords.c_str());
1027 code->appendf(".a;\n");
1028 }
1029 }
1030 code->appendf("\t\tvec3 surfaceToLight = ");
1031 SkString arg;
1032 arg.appendf("%s * m[4]", fSurfaceScaleVar->getName().c_str());
1033 fLight->emitSurfaceToLight(code, arg.c_str());
1034 code->appendf(";\n");
1035 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, fSurfaceScaleVar->getName().c_str());
1036 fLight->emitLightColor(code, "surfaceToLight");
1037 code->appendf(")%s;\n", state->fModulate.c_str());
1038}
1039
1040GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1041 const GrCustomStage& s) {
1042 return static_cast<const GrLightingEffect&>(s).light()->type();
1043}
1044
1045void GrGLLightingEffect::setData(const GrGLInterface* gl,
1046 const GrGLTexture& texture,
1047 const GrCustomStage& data,
1048 int stageNum) {
1049 const GrLightingEffect& effect =
1050 static_cast<const GrLightingEffect&>(data);
1051 GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture.width(), 1.0f / texture.height()));
1052 GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
1053 fLight->setData(gl, effect.light());
1054}
1055
1056///////////////////////////////////////////////////////////////////////////////
1057
1058///////////////////////////////////////////////////////////////////////////////
1059
1060GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1061 const GrCustomStage& stage)
1062 : INHERITED(factory, stage)
1063 , fKDVar(NULL)
1064 , fKDLocation(0) {
1065}
1066
1067void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1068 INHERITED::setupVariables(state, stage);
1069 fKDVar = &state->addUniform(
1070 GrGLShaderBuilder::kFragment_ShaderType,
1071 kFloat_GrSLType, "uKD", stage);
1072}
1073
1074void GrGLDiffuseLightingEffect::initUniforms(const GrGLInterface* gl,
1075 int programID) {
1076 INHERITED::initUniforms(gl, programID);
1077 GR_GL_CALL_RET(gl, fKDLocation,
1078 GetUniformLocation(programID,
1079 fKDVar->getName().c_str()));
1080}
1081
1082void GrGLDiffuseLightingEffect::emitLightFunc(SkString* funcs) {
1083 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1084 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", fKDVar->getName().c_str());
1085 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0, 1), 1);\n");
1086 funcs->appendf("}\n");
1087}
1088
1089void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
1090 const GrGLTexture& texture,
1091 const GrCustomStage& data,
1092 int stageNum) {
1093 INHERITED::setData(gl, texture, data, stageNum);
1094 const GrDiffuseLightingEffect& effect =
1095 static_cast<const GrDiffuseLightingEffect&>(data);
1096 GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
1097}
1098
1099///////////////////////////////////////////////////////////////////////////////
1100
1101GrSpecularLightingEffect::GrSpecularLightingEffect(const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1102 : INHERITED(light, surfaceScale),
1103 fKS(ks),
1104 fShininess(shininess) {
1105}
1106
1107const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1108 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1109}
1110
1111bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1112 const GrSpecularLightingEffect& s =
1113 static_cast<const GrSpecularLightingEffect&>(sBase);
1114 return INHERITED::isEqual(sBase) &&
1115 this->ks() == s.ks() &&
1116 this->shininess() == s.shininess();
1117}
1118
1119///////////////////////////////////////////////////////////////////////////////
1120
1121GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1122 const GrCustomStage& stage)
1123 : GrGLLightingEffect(factory, stage)
1124 , fKSVar(NULL)
1125 , fKSLocation(0)
1126 , fShininessVar(NULL)
1127 , fShininessLocation(0) {
1128}
1129
1130void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1131 INHERITED::setupVariables(state, stage);
1132 fKSVar = &state->addUniform(
1133 GrGLShaderBuilder::kFragment_ShaderType,
1134 kFloat_GrSLType, "uKS", stage);
1135 fShininessVar = &state->addUniform(
1136 GrGLShaderBuilder::kFragment_ShaderType,
1137 kFloat_GrSLType, "uShininess", stage);
1138}
1139
1140void GrGLSpecularLightingEffect::initUniforms(const GrGLInterface* gl,
1141 int programID) {
1142 INHERITED::initUniforms(gl, programID);
1143 GR_GL_CALL_RET(gl, fKSLocation,
1144 GetUniformLocation(programID, fKSVar->getName().c_str()));
1145 GR_GL_CALL_RET(gl, fShininessLocation,
1146 GetUniformLocation(programID, fShininessVar->getName().c_str()));
1147}
1148
1149void GrGLSpecularLightingEffect::emitLightFunc(SkString* funcs) {
1150 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1151 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1152
1153 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n",
1154 fKSVar->getName().c_str(), fShininessVar->getName().c_str());
1155 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0, 1), 1);\n");
1156 funcs->appendf("}\n");
1157}
1158
1159void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
1160 const GrGLTexture& texture,
1161 const GrCustomStage& data,
1162 int stageNum) {
1163 INHERITED::setData(gl, texture, data, stageNum);
1164 const GrSpecularLightingEffect& effect =
1165 static_cast<const GrSpecularLightingEffect&>(data);
1166 GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
1167 GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
1168}
1169
1170///////////////////////////////////////////////////////////////////////////////
1171
1172void GrGLLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
1173 builder->append(fColorVar->getName().c_str());
1174}
1175
1176void GrGLLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1177 fColorVar = &state->addUniform(
1178 GrGLShaderBuilder::kFragment_ShaderType,
1179 kVec3f_GrSLType, "uLightColor", stage);
1180}
1181
1182void GrGLLight::initUniforms(const GrGLInterface* gl, int programID) {
1183 GR_GL_CALL_RET(gl, fColorVarLocation,
1184 GetUniformLocation(programID, fColorVar->getName().c_str()));
1185}
1186
1187void GrGLLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1188 setUniformPoint3(gl, fColorVarLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
1189}
1190
1191GrGLLight* SkDistantLight::createGLLight() const {
1192 return new GrGLDistantLight();
1193}
1194
1195///////////////////////////////////////////////////////////////////////////////
1196
1197void GrGLDistantLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1198 INHERITED::setupVariables(state, stage);
1199 fDirectionVar = &state->addUniform(
1200 GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1201 "uLightDirection", stage);
1202}
1203
1204void GrGLDistantLight::initUniforms(const GrGLInterface* gl, int programID) {
1205 INHERITED::initUniforms(gl, programID);
1206 GR_GL_CALL_RET(gl, fDirectionLocation,
1207 GetUniformLocation(programID, fDirectionVar->getName().c_str()));
1208}
1209
1210void GrGLDistantLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1211 INHERITED::setData(gl, light);
1212 SkASSERT(light->type() == SkLight::kDistant_LightType);
1213 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
1214 setUniformPoint3(gl, fDirectionLocation, distantLight->direction());
1215}
1216
1217void GrGLDistantLight::emitSurfaceToLight(SkString* builder,
1218 const char* z) const {
1219 builder->append(fDirectionVar->getName().c_str());
1220}
1221
1222///////////////////////////////////////////////////////////////////////////////
1223
1224void GrGLPointLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1225 INHERITED::setupVariables(state, stage);
1226 fLocationVar = &state->addUniform(
1227 GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1228 "uLightLocation", stage);
1229 state->addVarying(kFloat_GrSLType, "Height", stage, &fHeightVaryingName);
1230}
1231
1232void GrGLPointLight::initUniforms(const GrGLInterface* gl, int programID) {
1233 INHERITED::initUniforms(gl, programID);
1234 GR_GL_CALL_RET(gl, fLocationLocation,
1235 GetUniformLocation(programID, fLocationVar->getName().c_str()));
1236}
1237
1238void GrGLPointLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1239 INHERITED::setData(gl, light);
1240 SkASSERT(light->type() == SkLight::kPoint_LightType);
1241 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
1242 setUniformPoint3(gl, fLocationLocation, pointLight->location());
1243}
1244
1245void GrGLPointLight::emitVS(SkString* builder) const {
1246 // Compute viewport height from the Y scale of the matrix.
1247 builder->appendf("\t\t%s = -2.0 / uViewM[1][1];\n", fHeightVaryingName);
1248}
1249
1250void GrGLPointLight::emitSurfaceToLight(SkString* builder,
1251 const char* z) const {
1252 builder->appendf(
1253 "normalize(%s - vec3(gl_FragCoord.x, %s - gl_FragCoord.y, %s))",
1254 fLocationVar->getName().c_str(), fHeightVaryingName, z);
1255}
1256
1257///////////////////////////////////////////////////////////////////////////////
1258
1259void GrGLSpotLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1260 INHERITED::setupVariables(state, stage);
1261 fLocationVar = &state->addUniform(
1262 GrGLShaderBuilder::kFragment_ShaderType,
1263 kVec3f_GrSLType, "uLightLocation", stage);
1264 fExponentVar = &state->addUniform(
1265 GrGLShaderBuilder::kFragment_ShaderType,
1266 kFloat_GrSLType, "uExponent", stage);
1267 fCosInnerConeAngleVar = &state->addUniform(
1268 GrGLShaderBuilder::kFragment_ShaderType,
1269 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1270 fCosOuterConeAngleVar = &state->addUniform(
1271 GrGLShaderBuilder::kFragment_ShaderType,
1272 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1273 fConeScaleVar = &state->addUniform(
1274 GrGLShaderBuilder::kFragment_ShaderType,
1275 kFloat_GrSLType, "uConeScale", stage);
1276 fSVar = &state->addUniform(
1277 GrGLShaderBuilder::kFragment_ShaderType,
1278 kVec3f_GrSLType, "uS", stage);
1279 state->addVarying(kFloat_GrSLType, "Height", stage, &fHeightVaryingName);
1280}
1281
1282void GrGLSpotLight::initUniforms(const GrGLInterface* gl, int programID) {
1283 INHERITED::initUniforms(gl, programID);
1284 GR_GL_CALL_RET(gl, fLocationLocation,
1285 GetUniformLocation(programID, fLocationVar->getName().c_str()));
1286 GR_GL_CALL_RET(gl, fExponentLocation,
1287 GetUniformLocation(programID, fExponentVar->getName().c_str()));
1288 GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation,
1289 GetUniformLocation(programID, fCosInnerConeAngleVar->getName().c_str()));
1290 GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation,
1291 GetUniformLocation(programID, fCosOuterConeAngleVar->getName().c_str()));
1292 GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation,
1293 GetUniformLocation(programID, fCosOuterConeAngleVar->getName().c_str()));
1294 GR_GL_CALL_RET(gl, fConeScaleLocation,
1295 GetUniformLocation(programID, fConeScaleVar->getName().c_str()));
1296 GR_GL_CALL_RET(gl, fSLocation,
1297 GetUniformLocation(programID, fSVar->getName().c_str()));
1298}
1299
1300void GrGLSpotLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1301 INHERITED::setData(gl, light);
1302 SkASSERT(light->type() == SkLight::kSpot_LightType);
1303 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
1304 setUniformPoint3(gl, fLocationLocation, spotLight->location());
1305 GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
1306 GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
1307 GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
1308 GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
1309 setUniformPoint3(gl, fSLocation, spotLight->s());
1310}
1311
1312void GrGLSpotLight::emitVS(SkString* builder) const {
1313 // Compute viewport height from the Y scale of the matrix.
1314 builder->appendf("\t\t%s = -2.0 / uViewM[1][1];\n", fHeightVaryingName);
1315}
1316
1317void GrGLSpotLight::emitFuncs(SkString* builder) const {
1318 builder->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1319 builder->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", fSVar->getName().c_str());
1320 builder->appendf("\tif (cosAngle < %s) {\n", fCosOuterConeAngleVar->getName().c_str());
1321 builder->appendf("\t\treturn vec3(0);\n");
1322 builder->appendf("\t}\n");
1323 builder->appendf("\tfloat scale = pow(cosAngle, %s);\n", fExponentVar->getName().c_str());
1324 builder->appendf("\tif (cosAngle < %s) {\n", fCosInnerConeAngleVar->getName().c_str());
1325 builder->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", fColorVar->getName().c_str(), fCosOuterConeAngleVar->getName().c_str(), fConeScaleVar->getName().c_str());
1326 builder->appendf("\t}\n");
1327 builder->appendf("\treturn %s;\n", fColorVar->getName().c_str());
1328 builder->appendf("}\n");
1329}
1330
1331void GrGLSpotLight::emitSurfaceToLight(SkString* builder, const char* z) const {
1332 builder->appendf("normalize(%s - vec3(gl_FragCoord.x, %s - gl_FragCoord.y, %s))", fLocationVar->getName().c_str(), fHeightVaryingName, z);
1333}
1334
1335void GrGLSpotLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
1336 builder->appendf("lightColor(%s)", surfaceToLight);
1337}
1338
djsollen@google.com08337772012-06-26 14:33:13 +00001339SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1340 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1341 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1342 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1343 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1344 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1345SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END