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