1/*
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"
11#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
15#include "SkTypes.h"
16
17#if SK_SUPPORT_GPU
18#include "effects/GrSingleTextureEffect.h"
19#include "gl/GrGLEffect.h"
20#include "GrEffect.h"
21#include "GrTBackendEffectFactory.h"
22
23class GrGLDiffuseLightingEffect;
24class GrGLSpecularLightingEffect;
25
26// For brevity
27typedef GrGLUniformManager::UniformHandle UniformHandle;
28#endif
29
30namespace {
31
32const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
33const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
34const SkScalar gOneHalf = 0.5f;
35const SkScalar gOneQuarter = 0.25f;
36
37#if SK_SUPPORT_GPU
38void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
39    GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
40    uman.set3fv(uni, 1, &point.fX);
41}
42
43void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
44    setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
45}
46#endif
47
48// Shift matrix components to the left, as we advance pixels to the right.
49inline void shiftMatrixLeft(int m[9]) {
50    m[0] = m[1];
51    m[3] = m[4];
52    m[6] = m[7];
53    m[1] = m[2];
54    m[4] = m[5];
55    m[7] = m[8];
56}
57
58class DiffuseLightingType {
59public:
60    DiffuseLightingType(SkScalar kd)
61        : fKD(kd) {}
62    SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
63        SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
64        colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
65        SkPoint3 color(lightColor * colorScale);
66        return SkPackARGB32(255,
67                            SkClampMax(SkScalarRoundToInt(color.fX), 255),
68                            SkClampMax(SkScalarRoundToInt(color.fY), 255),
69                            SkClampMax(SkScalarRoundToInt(color.fZ), 255));
70    }
71private:
72    SkScalar fKD;
73};
74
75class SpecularLightingType {
76public:
77    SpecularLightingType(SkScalar ks, SkScalar shininess)
78        : fKS(ks), fShininess(shininess) {}
79    SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
80        SkPoint3 halfDir(surfaceTolight);
81        halfDir.fZ += SK_Scalar1;        // eye position is always (0, 0, 1)
82        halfDir.normalize();
83        SkScalar colorScale = SkScalarMul(fKS,
84            SkScalarPow(normal.dot(halfDir), fShininess));
85        colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
86        SkPoint3 color(lightColor * colorScale);
87        return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
88                            SkClampMax(SkScalarRoundToInt(color.fX), 255),
89                            SkClampMax(SkScalarRoundToInt(color.fY), 255),
90                            SkClampMax(SkScalarRoundToInt(color.fZ), 255));
91    }
92private:
93    SkScalar fKS;
94    SkScalar fShininess;
95};
96
97inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
98    return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
99}
100
101inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
102    SkPoint3 vector(SkScalarMul(-x, surfaceScale),
103                    SkScalarMul(-y, surfaceScale),
104                    SK_Scalar1);
105    vector.normalize();
106    return vector;
107}
108
109inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
110    return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
111                         sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
112                         surfaceScale);
113}
114
115inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
116    return pointToNormal(sobel(   0,    0, m[3], m[5], m[6], m[8], gOneThird),
117                         sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
118                         surfaceScale);
119}
120
121inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
122    return pointToNormal(sobel(   0,    0, m[3], m[4], m[6], m[7], gTwoThirds),
123                         sobel(m[3], m[6], m[4], m[7],    0,    0, gTwoThirds),
124                         surfaceScale);
125}
126
127inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
128    return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
129                         sobel(   0,    0, m[1], m[7], m[2], m[8], gOneThird),
130                         surfaceScale);
131}
132
133
134inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
135    return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
136                         sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
137                         surfaceScale);
138}
139
140inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
141    return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
142                         sobel(m[0], m[6], m[1], m[7],    0,    0, gOneThird),
143                         surfaceScale);
144}
145
146inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
147    return pointToNormal(sobel(m[1], m[2], m[4], m[5],    0,    0, gTwoThirds),
148                         sobel(   0,    0, m[1], m[4], m[2], m[5], gTwoThirds),
149                         surfaceScale);
150}
151
152inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
153    return pointToNormal(sobel(m[0], m[2], m[3], m[5],    0,    0, gOneThird),
154                         sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
155                         surfaceScale);
156}
157
158inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
159    return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0,  0, gTwoThirds),
160                         sobel(m[0], m[3], m[1], m[4], 0,  0, gTwoThirds),
161                         surfaceScale);
162}
163
164template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
165    SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
166    const LightType* l = static_cast<const LightType*>(light);
167    int left = bounds.left(), right = bounds.right();
168    int bottom = bounds.bottom();
169    int y = bounds.top();
170    SkPMColor* dptr = dst->getAddr32(0, 0);
171    {
172        int x = left;
173        const SkPMColor* row1 = src.getAddr32(x, y);
174        const SkPMColor* row2 = src.getAddr32(x, y + 1);
175        int m[9];
176        m[4] = SkGetPackedA32(*row1++);
177        m[5] = SkGetPackedA32(*row1++);
178        m[7] = SkGetPackedA32(*row2++);
179        m[8] = SkGetPackedA32(*row2++);
180        SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
181        *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
182        for (++x; x < right - 1; ++x)
183        {
184            shiftMatrixLeft(m);
185            m[5] = SkGetPackedA32(*row1++);
186            m[8] = SkGetPackedA32(*row2++);
187            surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
188            *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
189        }
190        shiftMatrixLeft(m);
191        surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
192        *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
193    }
194
195    for (++y; y < bottom - 1; ++y) {
196        int x = left;
197        const SkPMColor* row0 = src.getAddr32(x, y - 1);
198        const SkPMColor* row1 = src.getAddr32(x, y);
199        const SkPMColor* row2 = src.getAddr32(x, y + 1);
200        int m[9];
201        m[1] = SkGetPackedA32(*row0++);
202        m[2] = SkGetPackedA32(*row0++);
203        m[4] = SkGetPackedA32(*row1++);
204        m[5] = SkGetPackedA32(*row1++);
205        m[7] = SkGetPackedA32(*row2++);
206        m[8] = SkGetPackedA32(*row2++);
207        SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
208        *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
209        for (++x; x < right - 1; ++x) {
210            shiftMatrixLeft(m);
211            m[2] = SkGetPackedA32(*row0++);
212            m[5] = SkGetPackedA32(*row1++);
213            m[8] = SkGetPackedA32(*row2++);
214            surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
215            *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
216        }
217        shiftMatrixLeft(m);
218        surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
219        *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
220    }
221
222    {
223        int x = left;
224        const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
225        const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
226        int m[9];
227        m[1] = SkGetPackedA32(*row0++);
228        m[2] = SkGetPackedA32(*row0++);
229        m[4] = SkGetPackedA32(*row1++);
230        m[5] = SkGetPackedA32(*row1++);
231        SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
232        *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
233        for (++x; x < right - 1; ++x)
234        {
235            shiftMatrixLeft(m);
236            m[2] = SkGetPackedA32(*row0++);
237            m[5] = SkGetPackedA32(*row1++);
238            surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
239            *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
240        }
241        shiftMatrixLeft(m);
242        surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
243        *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
244    }
245}
246
247SkPoint3 readPoint3(SkReadBuffer& buffer) {
248    SkPoint3 point;
249    point.fX = buffer.readScalar();
250    point.fY = buffer.readScalar();
251    point.fZ = buffer.readScalar();
252    buffer.validate(SkScalarIsFinite(point.fX) &&
253                    SkScalarIsFinite(point.fY) &&
254                    SkScalarIsFinite(point.fZ));
255    return point;
256};
257
258void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
259    buffer.writeScalar(point.fX);
260    buffer.writeScalar(point.fY);
261    buffer.writeScalar(point.fZ);
262};
263
264class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
265public:
266    SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
267                                 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
268    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
269    SkScalar kd() const { return fKD; }
270
271protected:
272    explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
273    virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
274    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
275                               SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
276#if SK_SUPPORT_GPU
277    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix, const SkIRect& bounds) const SK_OVERRIDE;
278#endif
279
280private:
281    typedef SkLightingImageFilter INHERITED;
282    SkScalar fKD;
283};
284
285class SkSpecularLightingImageFilter : public SkLightingImageFilter {
286public:
287    SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect);
288    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
289
290    SkScalar ks() const { return fKS; }
291    SkScalar shininess() const { return fShininess; }
292
293protected:
294    explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
295    virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
296    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
297                               SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
298#if SK_SUPPORT_GPU
299    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix, const SkIRect& bounds) const SK_OVERRIDE;
300#endif
301
302private:
303    typedef SkLightingImageFilter INHERITED;
304    SkScalar fKS;
305    SkScalar fShininess;
306};
307
308#if SK_SUPPORT_GPU
309
310class GrLightingEffect : public GrSingleTextureEffect {
311public:
312    GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
313    virtual ~GrLightingEffect();
314
315    const SkLight* light() const { return fLight; }
316    SkScalar surfaceScale() const { return fSurfaceScale; }
317    const SkMatrix& filterMatrix() const { return fFilterMatrix; }
318
319    virtual void getConstantColorComponents(GrColor* color,
320                                            uint32_t* validFlags) const SK_OVERRIDE {
321        // lighting shaders are complicated. We just throw up our hands.
322        *validFlags = 0;
323    }
324
325protected:
326    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
327
328private:
329    typedef GrSingleTextureEffect INHERITED;
330    const SkLight* fLight;
331    SkScalar fSurfaceScale;
332    SkMatrix fFilterMatrix;
333};
334
335class GrDiffuseLightingEffect : public GrLightingEffect {
336public:
337    static GrEffectRef* Create(GrTexture* texture,
338                               const SkLight* light,
339                               SkScalar surfaceScale,
340                               const SkMatrix& matrix,
341                               SkScalar kd) {
342        AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
343                                                                    light,
344                                                                    surfaceScale,
345                                                                    matrix,
346                                                                    kd)));
347        return CreateEffectRef(effect);
348    }
349
350    static const char* Name() { return "DiffuseLighting"; }
351
352    typedef GrGLDiffuseLightingEffect GLEffect;
353
354    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
355    SkScalar kd() const { return fKD; }
356
357private:
358    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
359
360    GrDiffuseLightingEffect(GrTexture* texture,
361                            const SkLight* light,
362                            SkScalar surfaceScale,
363                            const SkMatrix& matrix,
364                            SkScalar kd);
365
366    GR_DECLARE_EFFECT_TEST;
367    typedef GrLightingEffect INHERITED;
368    SkScalar fKD;
369};
370
371class GrSpecularLightingEffect : public GrLightingEffect {
372public:
373    static GrEffectRef* Create(GrTexture* texture,
374                               const SkLight* light,
375                               SkScalar surfaceScale,
376                               const SkMatrix& matrix,
377                               SkScalar ks,
378                               SkScalar shininess) {
379        AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
380                                                                     light,
381                                                                     surfaceScale,
382                                                                     matrix,
383                                                                     ks,
384                                                                     shininess)));
385        return CreateEffectRef(effect);
386    }
387    static const char* Name() { return "SpecularLighting"; }
388
389    typedef GrGLSpecularLightingEffect GLEffect;
390
391    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
392    SkScalar ks() const { return fKS; }
393    SkScalar shininess() const { return fShininess; }
394
395private:
396    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
397
398    GrSpecularLightingEffect(GrTexture* texture,
399                             const SkLight* light,
400                             SkScalar surfaceScale,
401                             const SkMatrix& matrix,
402                             SkScalar ks,
403                             SkScalar shininess);
404
405    GR_DECLARE_EFFECT_TEST;
406    typedef GrLightingEffect INHERITED;
407    SkScalar fKS;
408    SkScalar fShininess;
409};
410
411///////////////////////////////////////////////////////////////////////////////
412
413class GrGLLight {
414public:
415    virtual ~GrGLLight() {}
416
417    /**
418     * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
419     * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
420     */
421    void emitLightColorUniform(GrGLShaderBuilder*);
422
423    /**
424     * These two functions are called from GrGLLightingEffect's emitCode() function.
425     * emitSurfaceToLight places an expression in param out that is the vector from the surface to
426     * the light. The expression will be used in the FS. emitLightColor writes an expression into
427     * the FS that is the color of the light. Either function may add functions and/or uniforms to
428     * the FS. The default of emitLightColor appends the name of the constant light color uniform
429     * and so this function only needs to be overridden if the light color varies spatially.
430     */
431    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
432    virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
433
434    // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
435    // INHERITED::setData().
436    virtual void setData(const GrGLUniformManager&,
437                         const SkLight* light) const;
438
439protected:
440    /**
441     * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
442     * function.
443     */
444    UniformHandle lightColorUni() const { return fColorUni; }
445
446private:
447    UniformHandle fColorUni;
448
449    typedef SkRefCnt INHERITED;
450};
451
452///////////////////////////////////////////////////////////////////////////////
453
454class GrGLDistantLight : public GrGLLight {
455public:
456    virtual ~GrGLDistantLight() {}
457    virtual void setData(const GrGLUniformManager&,
458                         const SkLight* light) const SK_OVERRIDE;
459    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
460
461private:
462    typedef GrGLLight INHERITED;
463    UniformHandle fDirectionUni;
464};
465
466///////////////////////////////////////////////////////////////////////////////
467
468class GrGLPointLight : public GrGLLight {
469public:
470    virtual ~GrGLPointLight() {}
471    virtual void setData(const GrGLUniformManager&,
472                         const SkLight* light) const SK_OVERRIDE;
473    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
474
475private:
476    typedef GrGLLight INHERITED;
477    UniformHandle fLocationUni;
478};
479
480///////////////////////////////////////////////////////////////////////////////
481
482class GrGLSpotLight : public GrGLLight {
483public:
484    virtual ~GrGLSpotLight() {}
485    virtual void setData(const GrGLUniformManager&,
486                         const SkLight* light) const SK_OVERRIDE;
487    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
488    virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
489
490private:
491    typedef GrGLLight INHERITED;
492
493    SkString        fLightColorFunc;
494    UniformHandle   fLocationUni;
495    UniformHandle   fExponentUni;
496    UniformHandle   fCosOuterConeAngleUni;
497    UniformHandle   fCosInnerConeAngleUni;
498    UniformHandle   fConeScaleUni;
499    UniformHandle   fSUni;
500};
501#else
502
503class GrGLLight;
504
505#endif
506
507};
508
509///////////////////////////////////////////////////////////////////////////////
510
511class SkLight : public SkRefCnt {
512public:
513    SK_DECLARE_INST_COUNT(SkLight)
514
515    enum LightType {
516        kDistant_LightType,
517        kPoint_LightType,
518        kSpot_LightType,
519    };
520    virtual LightType type() const = 0;
521    const SkPoint3& color() const { return fColor; }
522    virtual GrGLLight* createGLLight() const = 0;
523    virtual bool isEqual(const SkLight& other) const {
524        return fColor == other.fColor;
525    }
526    // Called to know whether the generated GrGLLight will require access to the fragment position.
527    virtual bool requiresFragmentPosition() const = 0;
528    virtual SkLight* transform(const SkMatrix& matrix) const = 0;
529
530    // Defined below SkLight's subclasses.
531    void flattenLight(SkWriteBuffer& buffer) const;
532    static SkLight* UnflattenLight(SkReadBuffer& buffer);
533
534protected:
535    SkLight(SkColor color)
536      : fColor(SkIntToScalar(SkColorGetR(color)),
537               SkIntToScalar(SkColorGetG(color)),
538               SkIntToScalar(SkColorGetB(color))) {}
539    SkLight(const SkPoint3& color)
540      : fColor(color) {}
541    SkLight(SkReadBuffer& buffer) {
542        fColor = readPoint3(buffer);
543    }
544
545    virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
546
547
548private:
549    typedef SkRefCnt INHERITED;
550    SkPoint3 fColor;
551};
552
553///////////////////////////////////////////////////////////////////////////////
554
555class SkDistantLight : public SkLight {
556public:
557    SkDistantLight(const SkPoint3& direction, SkColor color)
558      : INHERITED(color), fDirection(direction) {
559    }
560
561    SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
562        return fDirection;
563    };
564    SkPoint3 lightColor(const SkPoint3&) const { return color(); }
565    virtual LightType type() const { return kDistant_LightType; }
566    const SkPoint3& direction() const { return fDirection; }
567    virtual GrGLLight* createGLLight() const SK_OVERRIDE {
568#if SK_SUPPORT_GPU
569        return SkNEW(GrGLDistantLight);
570#else
571        SkDEBUGFAIL("Should not call in GPU-less build");
572        return NULL;
573#endif
574    }
575    virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
576
577    virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
578        if (other.type() != kDistant_LightType) {
579            return false;
580        }
581
582        const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
583        return INHERITED::isEqual(other) &&
584               fDirection == o.fDirection;
585    }
586
587    SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
588        fDirection = readPoint3(buffer);
589    }
590
591protected:
592    SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
593      : INHERITED(color), fDirection(direction) {
594    }
595    virtual SkLight* transform(const SkMatrix& matrix) const {
596        return new SkDistantLight(direction(), color());
597    }
598    virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
599        writePoint3(fDirection, buffer);
600    }
601
602private:
603    typedef SkLight INHERITED;
604    SkPoint3 fDirection;
605};
606
607///////////////////////////////////////////////////////////////////////////////
608
609class SkPointLight : public SkLight {
610public:
611    SkPointLight(const SkPoint3& location, SkColor color)
612     : INHERITED(color), fLocation(location) {}
613
614    SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
615        SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
616                           fLocation.fY - SkIntToScalar(y),
617                           fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
618        direction.normalize();
619        return direction;
620    };
621    SkPoint3 lightColor(const SkPoint3&) const { return color(); }
622    virtual LightType type() const { return kPoint_LightType; }
623    const SkPoint3& location() const { return fLocation; }
624    virtual GrGLLight* createGLLight() const SK_OVERRIDE {
625#if SK_SUPPORT_GPU
626        return SkNEW(GrGLPointLight);
627#else
628        SkDEBUGFAIL("Should not call in GPU-less build");
629        return NULL;
630#endif
631    }
632    virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
633    virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
634        if (other.type() != kPoint_LightType) {
635            return false;
636        }
637        const SkPointLight& o = static_cast<const SkPointLight&>(other);
638        return INHERITED::isEqual(other) &&
639               fLocation == o.fLocation;
640    }
641    virtual SkLight* transform(const SkMatrix& matrix) const {
642        SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
643        matrix.mapPoints(&location2, 1);
644        // Use X scale and Y scale on Z and average the result
645        SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
646        matrix.mapVectors(&locationZ, 1);
647        SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
648        return new SkPointLight(location, color());
649    }
650
651    SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
652        fLocation = readPoint3(buffer);
653    }
654
655protected:
656    SkPointLight(const SkPoint3& location, const SkPoint3& color)
657     : INHERITED(color), fLocation(location) {}
658    virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
659        writePoint3(fLocation, buffer);
660    }
661
662private:
663    typedef SkLight INHERITED;
664    SkPoint3 fLocation;
665};
666
667///////////////////////////////////////////////////////////////////////////////
668
669class SkSpotLight : public SkLight {
670public:
671    SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
672     : INHERITED(color),
673       fLocation(location),
674       fTarget(target),
675       fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
676    {
677       fS = target - location;
678       fS.normalize();
679       fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
680       const SkScalar antiAliasThreshold = 0.016f;
681       fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
682       fConeScale = SkScalarInvert(antiAliasThreshold);
683    }
684
685    virtual SkLight* transform(const SkMatrix& matrix) const {
686        SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
687        matrix.mapPoints(&location2, 1);
688        // Use X scale and Y scale on Z and average the result
689        SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
690        matrix.mapVectors(&locationZ, 1);
691        SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
692        SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
693        matrix.mapPoints(&target2, 1);
694        SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
695        matrix.mapVectors(&targetZ, 1);
696        SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
697        SkPoint3 s = target - location;
698        s.normalize();
699        return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
700    }
701
702    SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
703        SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
704                           fLocation.fY - SkIntToScalar(y),
705                           fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
706        direction.normalize();
707        return direction;
708    };
709    SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
710        SkScalar cosAngle = -surfaceToLight.dot(fS);
711        if (cosAngle < fCosOuterConeAngle) {
712            return SkPoint3(0, 0, 0);
713        }
714        SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
715        if (cosAngle < fCosInnerConeAngle) {
716            scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
717            return color() * SkScalarMul(scale, fConeScale);
718        }
719        return color() * scale;
720    }
721    virtual GrGLLight* createGLLight() const SK_OVERRIDE {
722#if SK_SUPPORT_GPU
723        return SkNEW(GrGLSpotLight);
724#else
725        SkDEBUGFAIL("Should not call in GPU-less build");
726        return NULL;
727#endif
728    }
729    virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
730    virtual LightType type() const { return kSpot_LightType; }
731    const SkPoint3& location() const { return fLocation; }
732    const SkPoint3& target() const { return fTarget; }
733    SkScalar specularExponent() const { return fSpecularExponent; }
734    SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
735    SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
736    SkScalar coneScale() const { return fConeScale; }
737    const SkPoint3& s() const { return fS; }
738
739    SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
740        fLocation = readPoint3(buffer);
741        fTarget = readPoint3(buffer);
742        fSpecularExponent = buffer.readScalar();
743        fCosOuterConeAngle = buffer.readScalar();
744        fCosInnerConeAngle = buffer.readScalar();
745        fConeScale = buffer.readScalar();
746        fS = readPoint3(buffer);
747        buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
748                        SkScalarIsFinite(fCosOuterConeAngle) &&
749                        SkScalarIsFinite(fCosInnerConeAngle) &&
750                        SkScalarIsFinite(fConeScale));
751    }
752protected:
753    SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
754     : INHERITED(color),
755       fLocation(location),
756       fTarget(target),
757       fSpecularExponent(specularExponent),
758       fCosOuterConeAngle(cosOuterConeAngle),
759       fCosInnerConeAngle(cosInnerConeAngle),
760       fConeScale(coneScale),
761       fS(s)
762    {
763    }
764    virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
765        writePoint3(fLocation, buffer);
766        writePoint3(fTarget, buffer);
767        buffer.writeScalar(fSpecularExponent);
768        buffer.writeScalar(fCosOuterConeAngle);
769        buffer.writeScalar(fCosInnerConeAngle);
770        buffer.writeScalar(fConeScale);
771        writePoint3(fS, buffer);
772    }
773
774    virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
775        if (other.type() != kSpot_LightType) {
776            return false;
777        }
778
779        const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
780        return INHERITED::isEqual(other) &&
781               fLocation == o.fLocation &&
782               fTarget == o.fTarget &&
783               fSpecularExponent == o.fSpecularExponent &&
784               fCosOuterConeAngle == o.fCosOuterConeAngle;
785    }
786
787private:
788    static const SkScalar kSpecularExponentMin;
789    static const SkScalar kSpecularExponentMax;
790
791    typedef SkLight INHERITED;
792    SkPoint3 fLocation;
793    SkPoint3 fTarget;
794    SkScalar fSpecularExponent;
795    SkScalar fCosOuterConeAngle;
796    SkScalar fCosInnerConeAngle;
797    SkScalar fConeScale;
798    SkPoint3 fS;
799};
800
801// According to the spec, the specular term should be in the range [1, 128] :
802// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
803const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
804const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
805
806///////////////////////////////////////////////////////////////////////////////
807
808void SkLight::flattenLight(SkWriteBuffer& buffer) const {
809    // Write type first, then baseclass, then subclass.
810    buffer.writeInt(this->type());
811    writePoint3(fColor, buffer);
812    this->onFlattenLight(buffer);
813}
814
815/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
816    // Read type first.
817    const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
818    switch (type) {
819        // Each of these constructors must first call SkLight's, so we'll read the baseclass
820        // then subclass, same order as flattenLight.
821        case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
822        case SkLight::kPoint_LightType:   return SkNEW_ARGS(SkPointLight, (buffer));
823        case SkLight::kSpot_LightType:    return SkNEW_ARGS(SkSpotLight, (buffer));
824        default:
825            SkDEBUGFAIL("Unknown LightType.");
826            buffer.validate(false);
827            return NULL;
828    }
829}
830///////////////////////////////////////////////////////////////////////////////
831
832SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input, const CropRect* cropRect)
833  : INHERITED(input, cropRect),
834    fLight(light),
835    fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
836{
837    SkASSERT(fLight);
838    // our caller knows that we take ownership of the light, so we don't
839    // need to call ref() here.
840}
841
842SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
843    const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
844    SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
845    return SkNEW_ARGS(SkDiffuseLightingImageFilter,
846        (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
847        input, cropRect));
848}
849
850SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
851    const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
852    SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
853    return SkNEW_ARGS(SkDiffuseLightingImageFilter,
854        (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
855        input, cropRect));
856}
857
858SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
859    const SkPoint3& location, const SkPoint3& target,
860    SkScalar specularExponent, SkScalar cutoffAngle,
861    SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
862    SkImageFilter* input, const CropRect* cropRect) {
863    return SkNEW_ARGS(SkDiffuseLightingImageFilter,
864        (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
865                                  cutoffAngle, lightColor)),
866                    surfaceScale, kd, input, cropRect));
867}
868
869SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
870    const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
871    SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
872    return SkNEW_ARGS(SkSpecularLightingImageFilter,
873        (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
874        surfaceScale, ks, shininess, input, cropRect));
875}
876
877SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
878    const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
879    SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
880    return SkNEW_ARGS(SkSpecularLightingImageFilter,
881        (SkNEW_ARGS(SkPointLight, (location, lightColor)),
882        surfaceScale, ks, shininess, input, cropRect));
883}
884
885SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
886    const SkPoint3& location, const SkPoint3& target,
887    SkScalar specularExponent, SkScalar cutoffAngle,
888    SkColor lightColor, SkScalar surfaceScale,
889    SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
890    return SkNEW_ARGS(SkSpecularLightingImageFilter,
891        (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
892        surfaceScale, ks, shininess, input, cropRect));
893}
894
895SkLightingImageFilter::~SkLightingImageFilter() {
896    SkSafeUnref(fLight);
897}
898
899SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
900  : INHERITED(1, buffer) {
901    fLight = SkLight::UnflattenLight(buffer);
902    fSurfaceScale = buffer.readScalar();
903    buffer.validate(SkScalarIsFinite(fSurfaceScale));
904}
905
906void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
907    this->INHERITED::flatten(buffer);
908    fLight->flattenLight(buffer);
909    buffer.writeScalar(fSurfaceScale);
910}
911
912///////////////////////////////////////////////////////////////////////////////
913
914SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
915  : SkLightingImageFilter(light, surfaceScale, input, cropRect),
916    // According to the spec, kd can be any non-negative number :
917    // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
918    fKD(kd < 0 ? 0 : kd)
919{
920}
921
922SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
923  : INHERITED(buffer)
924{
925    fKD = buffer.readScalar();
926    buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
927}
928
929void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
930    this->INHERITED::flatten(buffer);
931    buffer.writeScalar(fKD);
932}
933
934bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
935                                                 const SkBitmap& source,
936                                                 const Context& ctx,
937                                                 SkBitmap* dst,
938                                                 SkIPoint* offset) const {
939    SkImageFilter* input = getInput(0);
940    SkBitmap src = source;
941    SkIPoint srcOffset = SkIPoint::Make(0, 0);
942    if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
943        return false;
944    }
945
946    if (src.colorType() != kN32_SkColorType) {
947        return false;
948    }
949    SkIRect bounds;
950    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
951        return false;
952    }
953
954    if (bounds.width() < 2 || bounds.height() < 2) {
955        return false;
956    }
957
958    SkAutoLockPixels alp(src);
959    if (!src.getPixels()) {
960        return false;
961    }
962
963    if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
964        return false;
965    }
966
967    SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
968
969    DiffuseLightingType lightingType(fKD);
970    offset->fX = bounds.left();
971    offset->fY = bounds.top();
972    bounds.offset(-srcOffset);
973    switch (transformedLight->type()) {
974        case SkLight::kDistant_LightType:
975            lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
976            break;
977        case SkLight::kPoint_LightType:
978            lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
979            break;
980        case SkLight::kSpot_LightType:
981            lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
982            break;
983    }
984
985    return true;
986}
987
988#if SK_SUPPORT_GPU
989bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix, const SkIRect&) const {
990    if (effect) {
991        SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
992        *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
993    }
994    return true;
995}
996#endif
997
998///////////////////////////////////////////////////////////////////////////////
999
1000SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
1001  : SkLightingImageFilter(light, surfaceScale, input, cropRect),
1002    // According to the spec, ks can be any non-negative number :
1003    // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
1004    fKS(ks < 0 ? 0 : ks),
1005    fShininess(shininess)
1006{
1007}
1008
1009SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
1010  : INHERITED(buffer)
1011{
1012    fKS = buffer.readScalar();
1013    fShininess = buffer.readScalar();
1014    buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
1015                    SkScalarIsFinite(fShininess));
1016}
1017
1018void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
1019    this->INHERITED::flatten(buffer);
1020    buffer.writeScalar(fKS);
1021    buffer.writeScalar(fShininess);
1022}
1023
1024bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1025                                                  const SkBitmap& source,
1026                                                  const Context& ctx,
1027                                                  SkBitmap* dst,
1028                                                  SkIPoint* offset) const {
1029    SkImageFilter* input = getInput(0);
1030    SkBitmap src = source;
1031    SkIPoint srcOffset = SkIPoint::Make(0, 0);
1032    if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
1033        return false;
1034    }
1035
1036    if (src.colorType() != kN32_SkColorType) {
1037        return false;
1038    }
1039
1040    SkIRect bounds;
1041    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
1042        return false;
1043    }
1044
1045    if (bounds.width() < 2 || bounds.height() < 2) {
1046        return false;
1047    }
1048
1049    SkAutoLockPixels alp(src);
1050    if (!src.getPixels()) {
1051        return false;
1052    }
1053
1054    if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
1055        return false;
1056    }
1057
1058    SpecularLightingType lightingType(fKS, fShininess);
1059    offset->fX = bounds.left();
1060    offset->fY = bounds.top();
1061    bounds.offset(-srcOffset);
1062    SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
1063    switch (transformedLight->type()) {
1064        case SkLight::kDistant_LightType:
1065            lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1066            break;
1067        case SkLight::kPoint_LightType:
1068            lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1069            break;
1070        case SkLight::kSpot_LightType:
1071            lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1072            break;
1073    }
1074    return true;
1075}
1076
1077#if SK_SUPPORT_GPU
1078bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix, const SkIRect&) const {
1079    if (effect) {
1080        SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1081        *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
1082    }
1083    return true;
1084}
1085#endif
1086
1087///////////////////////////////////////////////////////////////////////////////
1088
1089#if SK_SUPPORT_GPU
1090
1091namespace {
1092SkPoint3 random_point3(SkRandom* random) {
1093    return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1094                    SkScalarToFloat(random->nextSScalar1()),
1095                    SkScalarToFloat(random->nextSScalar1()));
1096}
1097
1098SkLight* create_random_light(SkRandom* random) {
1099    int type = random->nextULessThan(3);
1100    switch (type) {
1101        case 0: {
1102            return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1103        }
1104        case 1: {
1105            return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1106        }
1107        case 2: {
1108            return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1109                                            random_point3(random),
1110                                            random->nextUScalar1(),
1111                                            random->nextUScalar1(),
1112                                            random->nextU()));
1113        }
1114        default:
1115            SkFAIL("Unexpected value.");
1116            return NULL;
1117    }
1118}
1119
1120}
1121
1122class GrGLLightingEffect  : public GrGLEffect {
1123public:
1124    GrGLLightingEffect(const GrBackendEffectFactory& factory,
1125                       const GrDrawEffect& effect);
1126    virtual ~GrGLLightingEffect();
1127
1128    virtual void emitCode(GrGLShaderBuilder*,
1129                          const GrDrawEffect&,
1130                          EffectKey,
1131                          const char* outputColor,
1132                          const char* inputColor,
1133                          const TransformedCoordsArray&,
1134                          const TextureSamplerArray&) SK_OVERRIDE;
1135
1136    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
1137
1138    /**
1139     * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1140     */
1141    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
1142
1143protected:
1144    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1145
1146private:
1147    typedef GrGLEffect INHERITED;
1148
1149    UniformHandle       fImageIncrementUni;
1150    UniformHandle       fSurfaceScaleUni;
1151    GrGLLight*          fLight;
1152};
1153
1154///////////////////////////////////////////////////////////////////////////////
1155
1156class GrGLDiffuseLightingEffect  : public GrGLLightingEffect {
1157public:
1158    GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
1159                              const GrDrawEffect& drawEffect);
1160    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
1161    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
1162
1163private:
1164    typedef GrGLLightingEffect INHERITED;
1165
1166    UniformHandle   fKDUni;
1167};
1168
1169///////////////////////////////////////////////////////////////////////////////
1170
1171class GrGLSpecularLightingEffect  : public GrGLLightingEffect {
1172public:
1173    GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
1174                               const GrDrawEffect& effect);
1175    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
1176    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
1177
1178private:
1179    typedef GrGLLightingEffect INHERITED;
1180
1181    UniformHandle   fKSUni;
1182    UniformHandle   fShininessUni;
1183};
1184
1185///////////////////////////////////////////////////////////////////////////////
1186
1187GrLightingEffect::GrLightingEffect(GrTexture* texture,
1188                                   const SkLight* light,
1189                                   SkScalar surfaceScale,
1190                                   const SkMatrix& matrix)
1191    : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
1192    , fLight(light)
1193    , fSurfaceScale(surfaceScale)
1194    , fFilterMatrix(matrix) {
1195    fLight->ref();
1196    if (light->requiresFragmentPosition()) {
1197        this->setWillReadFragmentPosition();
1198    }
1199}
1200
1201GrLightingEffect::~GrLightingEffect() {
1202    fLight->unref();
1203}
1204
1205bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
1206    const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
1207    return this->texture(0) == s.texture(0) &&
1208           fLight->isEqual(*s.fLight) &&
1209           fSurfaceScale == s.fSurfaceScale;
1210}
1211
1212///////////////////////////////////////////////////////////////////////////////
1213
1214GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1215                                                 const SkLight* light,
1216                                                 SkScalar surfaceScale,
1217                                                 const SkMatrix& matrix,
1218                                                 SkScalar kd)
1219    : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
1220}
1221
1222const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1223    return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
1224}
1225
1226bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
1227    const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
1228    return INHERITED::onIsEqual(sBase) &&
1229            this->kd() == s.kd();
1230}
1231
1232GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
1233
1234GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1235                                                 GrContext* context,
1236                                                 const GrDrawTargetCaps&,
1237                                                 GrTexture* textures[]) {
1238    SkScalar surfaceScale = random->nextSScalar1();
1239    SkScalar kd = random->nextUScalar1();
1240    SkAutoTUnref<SkLight> light(create_random_light(random));
1241    SkMatrix matrix;
1242    for (int i = 0; i < 9; i++) {
1243        matrix[i] = random->nextUScalar1();
1244    }
1245    return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1246                                           light, surfaceScale, matrix, kd);
1247}
1248
1249
1250///////////////////////////////////////////////////////////////////////////////
1251
1252GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
1253                                       const GrDrawEffect& drawEffect)
1254    : INHERITED(factory) {
1255    const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
1256    fLight = m.light()->createGLLight();
1257}
1258
1259GrGLLightingEffect::~GrGLLightingEffect() {
1260    delete fLight;
1261}
1262
1263void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
1264                                  const GrDrawEffect&,
1265                                  EffectKey key,
1266                                  const char* outputColor,
1267                                  const char* inputColor,
1268                                  const TransformedCoordsArray& coords,
1269                                  const TextureSamplerArray& samplers) {
1270    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
1271
1272    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1273                                              kVec2f_GrSLType,
1274                                             "ImageIncrement");
1275    fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1276                                           kFloat_GrSLType,
1277                                           "SurfaceScale");
1278    fLight->emitLightColorUniform(builder);
1279    SkString lightFunc;
1280    this->emitLightFunc(builder, &lightFunc);
1281    static const GrGLShaderVar gSobelArgs[] =  {
1282        GrGLShaderVar("a", kFloat_GrSLType),
1283        GrGLShaderVar("b", kFloat_GrSLType),
1284        GrGLShaderVar("c", kFloat_GrSLType),
1285        GrGLShaderVar("d", kFloat_GrSLType),
1286        GrGLShaderVar("e", kFloat_GrSLType),
1287        GrGLShaderVar("f", kFloat_GrSLType),
1288        GrGLShaderVar("scale", kFloat_GrSLType),
1289    };
1290    SkString sobelFuncName;
1291    builder->fsEmitFunction(kFloat_GrSLType,
1292                            "sobel",
1293                            SK_ARRAY_COUNT(gSobelArgs),
1294                            gSobelArgs,
1295                            "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1296                            &sobelFuncName);
1297    static const GrGLShaderVar gPointToNormalArgs[] =  {
1298        GrGLShaderVar("x", kFloat_GrSLType),
1299        GrGLShaderVar("y", kFloat_GrSLType),
1300        GrGLShaderVar("scale", kFloat_GrSLType),
1301    };
1302    SkString pointToNormalName;
1303    builder->fsEmitFunction(kVec3f_GrSLType,
1304                            "pointToNormal",
1305                            SK_ARRAY_COUNT(gPointToNormalArgs),
1306                            gPointToNormalArgs,
1307                            "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1308                            &pointToNormalName);
1309
1310    static const GrGLShaderVar gInteriorNormalArgs[] =  {
1311        GrGLShaderVar("m", kFloat_GrSLType, 9),
1312        GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1313    };
1314    SkString interiorNormalBody;
1315    interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1316                               "\t       %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1317                               "\t       surfaceScale);\n",
1318                                pointToNormalName.c_str(),
1319                                sobelFuncName.c_str(),
1320                                sobelFuncName.c_str());
1321    SkString interiorNormalName;
1322    builder->fsEmitFunction(kVec3f_GrSLType,
1323                            "interiorNormal",
1324                            SK_ARRAY_COUNT(gInteriorNormalArgs),
1325                            gInteriorNormalArgs,
1326                            interiorNormalBody.c_str(),
1327                            &interiorNormalName);
1328
1329    builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1330    builder->fsCodeAppend("\t\tfloat m[9];\n");
1331
1332    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1333    const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1334
1335    int index = 0;
1336    for (int dy = -1; dy <= 1; dy++) {
1337        for (int dx = -1; dx <= 1; dx++) {
1338            SkString texCoords;
1339            texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
1340            builder->fsCodeAppendf("\t\tm[%d] = ", index++);
1341            builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
1342            builder->fsCodeAppend(".a;\n");
1343        }
1344    }
1345    builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
1346    SkString arg;
1347    arg.appendf("%s * m[4]", surfScale);
1348    fLight->emitSurfaceToLight(builder, arg.c_str());
1349    builder->fsCodeAppend(";\n");
1350    builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1351                           outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
1352    fLight->emitLightColor(builder, "surfaceToLight");
1353    builder->fsCodeAppend(");\n");
1354    SkString modulate;
1355    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1356    builder->fsCodeAppend(modulate.c_str());
1357}
1358
1359GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
1360                                                 const GrGLCaps& caps) {
1361    return drawEffect.castEffect<GrLightingEffect>().light()->type();
1362}
1363
1364void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1365                                 const GrDrawEffect& drawEffect) {
1366    const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1367    GrTexture* texture = lighting.texture(0);
1368    float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
1369    uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1370    uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
1371    SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1372    fLight->setData(uman, transformedLight);
1373}
1374
1375///////////////////////////////////////////////////////////////////////////////
1376
1377///////////////////////////////////////////////////////////////////////////////
1378
1379GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
1380                                                     const GrDrawEffect& drawEffect)
1381    : INHERITED(factory, drawEffect) {
1382}
1383
1384void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
1385    const char* kd;
1386    fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1387                                 kFloat_GrSLType,
1388                                 "KD",
1389                                 &kd);
1390
1391    static const GrGLShaderVar gLightArgs[] = {
1392        GrGLShaderVar("normal", kVec3f_GrSLType),
1393        GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1394        GrGLShaderVar("lightColor", kVec3f_GrSLType)
1395    };
1396    SkString lightBody;
1397    lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1398    lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1399    builder->fsEmitFunction(kVec4f_GrSLType,
1400                            "light",
1401                            SK_ARRAY_COUNT(gLightArgs),
1402                            gLightArgs,
1403                            lightBody.c_str(),
1404                            funcName);
1405}
1406
1407void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
1408                                        const GrDrawEffect& drawEffect) {
1409    INHERITED::setData(uman, drawEffect);
1410    const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1411    uman.set1f(fKDUni, diffuse.kd());
1412}
1413
1414///////////////////////////////////////////////////////////////////////////////
1415
1416GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1417                                                   const SkLight* light,
1418                                                   SkScalar surfaceScale,
1419                                                   const SkMatrix& matrix,
1420                                                   SkScalar ks,
1421                                                   SkScalar shininess)
1422    : INHERITED(texture, light, surfaceScale, matrix),
1423      fKS(ks),
1424      fShininess(shininess) {
1425}
1426
1427const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1428    return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
1429}
1430
1431bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
1432    const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
1433    return INHERITED::onIsEqual(sBase) &&
1434           this->ks() == s.ks() &&
1435           this->shininess() == s.shininess();
1436}
1437
1438GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
1439
1440GrEffectRef* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1441                                                  GrContext* context,
1442                                                  const GrDrawTargetCaps&,
1443                                                  GrTexture* textures[]) {
1444    SkScalar surfaceScale = random->nextSScalar1();
1445    SkScalar ks = random->nextUScalar1();
1446    SkScalar shininess = random->nextUScalar1();
1447    SkAutoTUnref<SkLight> light(create_random_light(random));
1448    SkMatrix matrix;
1449    for (int i = 0; i < 9; i++) {
1450        matrix[i] = random->nextUScalar1();
1451    }
1452    return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1453                                            light, surfaceScale, matrix, ks, shininess);
1454}
1455
1456///////////////////////////////////////////////////////////////////////////////
1457
1458GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
1459                                                       const GrDrawEffect& drawEffect)
1460    : INHERITED(factory, drawEffect) {
1461}
1462
1463void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
1464    const char* ks;
1465    const char* shininess;
1466
1467    fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1468                                 kFloat_GrSLType, "KS", &ks);
1469    fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1470                                        kFloat_GrSLType, "Shininess", &shininess);
1471
1472    static const GrGLShaderVar gLightArgs[] = {
1473        GrGLShaderVar("normal", kVec3f_GrSLType),
1474        GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1475        GrGLShaderVar("lightColor", kVec3f_GrSLType)
1476    };
1477    SkString lightBody;
1478    lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1479    lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
1480    lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1481    lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
1482    builder->fsEmitFunction(kVec4f_GrSLType,
1483                            "light",
1484                            SK_ARRAY_COUNT(gLightArgs),
1485                            gLightArgs,
1486                            lightBody.c_str(),
1487                            funcName);
1488}
1489
1490void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
1491                                         const GrDrawEffect& drawEffect) {
1492    INHERITED::setData(uman, drawEffect);
1493    const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1494    uman.set1f(fKSUni, spec.ks());
1495    uman.set1f(fShininessUni, spec.shininess());
1496}
1497
1498///////////////////////////////////////////////////////////////////////////////
1499void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
1500    fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1501                                    kVec3f_GrSLType, "LightColor");
1502}
1503
1504void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1505                               const char *surfaceToLight) {
1506    builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
1507}
1508
1509void GrGLLight::setData(const GrGLUniformManager& uman,
1510                        const SkLight* light) const {
1511    setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
1512}
1513
1514///////////////////////////////////////////////////////////////////////////////
1515
1516void GrGLDistantLight::setData(const GrGLUniformManager& uman,
1517                               const SkLight* light) const {
1518    INHERITED::setData(uman, light);
1519    SkASSERT(light->type() == SkLight::kDistant_LightType);
1520    const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
1521    setUniformNormal3(uman, fDirectionUni, distantLight->direction());
1522}
1523
1524void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
1525    const char* dir;
1526    fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
1527                                        "LightDirection", &dir);
1528    builder->fsCodeAppend(dir);
1529}
1530
1531///////////////////////////////////////////////////////////////////////////////
1532
1533void GrGLPointLight::setData(const GrGLUniformManager& uman,
1534                             const SkLight* light) const {
1535    INHERITED::setData(uman, light);
1536    SkASSERT(light->type() == SkLight::kPoint_LightType);
1537    const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
1538    setUniformPoint3(uman, fLocationUni, pointLight->location());
1539}
1540
1541void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
1542    const char* loc;
1543    fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
1544                                       "LightLocation", &loc);
1545    builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
1546}
1547
1548///////////////////////////////////////////////////////////////////////////////
1549
1550void GrGLSpotLight::setData(const GrGLUniformManager& uman,
1551                            const SkLight* light) const {
1552    INHERITED::setData(uman, light);
1553    SkASSERT(light->type() == SkLight::kSpot_LightType);
1554    const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
1555    setUniformPoint3(uman, fLocationUni, spotLight->location());
1556    uman.set1f(fExponentUni, spotLight->specularExponent());
1557    uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1558    uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1559    uman.set1f(fConeScaleUni, spotLight->coneScale());
1560    setUniformNormal3(uman, fSUni, spotLight->s());
1561}
1562
1563void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
1564    const char* location;
1565    fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1566                                       kVec3f_GrSLType, "LightLocation", &location);
1567    builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1568                           location, builder->fragmentPosition(), z);
1569}
1570
1571void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1572                                   const char *surfaceToLight) {
1573
1574    const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1575
1576    const char* exponent;
1577    const char* cosInner;
1578    const char* cosOuter;
1579    const char* coneScale;
1580    const char* s;
1581    fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1582                                       kFloat_GrSLType, "Exponent", &exponent);
1583    fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1584                                                kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1585    fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1586                                                kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1587    fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1588                                        kFloat_GrSLType, "ConeScale", &coneScale);
1589    fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1590                                kVec3f_GrSLType, "S", &s);
1591
1592    static const GrGLShaderVar gLightColorArgs[] = {
1593        GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1594    };
1595    SkString lightColorBody;
1596    lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1597    lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1598    lightColorBody.appendf("\t\treturn vec3(0);\n");
1599    lightColorBody.appendf("\t}\n");
1600    lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1601    lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1602    lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1603                           color, cosOuter, coneScale);
1604    lightColorBody.appendf("\t}\n");
1605    lightColorBody.appendf("\treturn %s;\n", color);
1606    builder->fsEmitFunction(kVec3f_GrSLType,
1607                            "lightColor",
1608                            SK_ARRAY_COUNT(gLightColorArgs),
1609                            gLightColorArgs,
1610                            lightColorBody.c_str(),
1611                            &fLightColorFunc);
1612
1613    builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
1614}
1615
1616#endif
1617
1618SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1619    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1620    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1621SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1622