blob: 8d1e8e771420fa20075aea2db7781fdec12d5ee8 [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000011#include "GrProgramStageFactory.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000012#include "effects/GrSingleTextureEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000013#include "gl/GrGLProgramStage.h"
14#include "gl/GrGLSL.h"
15#include "gl/GrGLTexture.h"
16#include "GrCustomStage.h"
17
18class GrGLDiffuseLightingEffect;
19class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000020
21// FIXME: Eventually, this should be implemented properly, and put in
22// SkScalar.h.
23#define SkScalarPow(x, y) SkFloatToScalar(powf(SkScalarToFloat(x), SkScalarToFloat(y)))
24namespace {
25
26const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
27const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
28const SkScalar gOneHalf = SkFloatToScalar(0.5f);
29const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
30
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000031void setUniformPoint3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
32 float x = SkScalarToFloat(point.fX);
33 float y = SkScalarToFloat(point.fY);
34 float z = SkScalarToFloat(point.fZ);
35 GR_GL_CALL(gl, Uniform3f(location, x, y, z));
36}
37
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000038// Shift matrix components to the left, as we advance pixels to the right.
39inline void shiftMatrixLeft(int m[9]) {
40 m[0] = m[1];
41 m[3] = m[4];
42 m[6] = m[7];
43 m[1] = m[2];
44 m[4] = m[5];
45 m[7] = m[8];
46}
47
48class DiffuseLightingType {
49public:
50 DiffuseLightingType(SkScalar kd)
51 : fKD(kd) {}
52 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
53 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
54 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
55 SkPoint3 color(lightColor * colorScale);
56 return SkPackARGB32(255,
57 SkScalarFloorToInt(color.fX),
58 SkScalarFloorToInt(color.fY),
59 SkScalarFloorToInt(color.fZ));
60 }
61private:
62 SkScalar fKD;
63};
64
65class SpecularLightingType {
66public:
67 SpecularLightingType(SkScalar ks, SkScalar shininess)
68 : fKS(ks), fShininess(shininess) {}
69 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
70 SkPoint3 halfDir(surfaceTolight);
71 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
72 halfDir.normalize();
73 SkScalar colorScale = SkScalarMul(fKS,
74 SkScalarPow(normal.dot(halfDir), fShininess));
75 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
76 SkPoint3 color(lightColor * colorScale);
77 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
78 SkScalarFloorToInt(color.fX),
79 SkScalarFloorToInt(color.fY),
80 SkScalarFloorToInt(color.fZ));
81 }
82private:
83 SkScalar fKS;
84 SkScalar fShininess;
85};
86
87inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
88 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
89}
90
91inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
92 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
93 SkScalarMul(-y, surfaceScale),
94 SK_Scalar1);
95 vector.normalize();
96 return vector;
97}
98
99inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
100 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
101 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
102 surfaceScale);
103}
104
105inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
106 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
107 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
108 surfaceScale);
109}
110
111inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
112 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
113 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
114 surfaceScale);
115}
116
117inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
118 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
119 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
120 surfaceScale);
121}
122
123
124inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
125 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
126 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
127 surfaceScale);
128}
129
130inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
131 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
132 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
133 surfaceScale);
134}
135
136inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
137 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
138 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
139 surfaceScale);
140}
141
142inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
143 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
144 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
145 surfaceScale);
146}
147
148inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
149 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
150 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
151 surfaceScale);
152}
153
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000154template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000155 const LightType* l = static_cast<const LightType*>(light);
156 int y = 0;
157 {
158 const SkPMColor* row1 = src.getAddr32(0, 0);
159 const SkPMColor* row2 = src.getAddr32(0, 1);
160 SkPMColor* dptr = dst->getAddr32(0, 0);
161 int m[9];
162 int x = 0;
163 m[4] = SkGetPackedA32(*row1++);
164 m[5] = SkGetPackedA32(*row1++);
165 m[7] = SkGetPackedA32(*row2++);
166 m[8] = SkGetPackedA32(*row2++);
167 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000168 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000169 for (x = 1; x < src.width() - 1; ++x)
170 {
171 shiftMatrixLeft(m);
172 m[5] = SkGetPackedA32(*row1++);
173 m[8] = SkGetPackedA32(*row2++);
174 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000175 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000176 }
177 shiftMatrixLeft(m);
178 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000179 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000180 }
181
182 for (++y; y < src.height() - 1; ++y) {
183 const SkPMColor* row0 = src.getAddr32(0, y - 1);
184 const SkPMColor* row1 = src.getAddr32(0, y);
185 const SkPMColor* row2 = src.getAddr32(0, y + 1);
186 SkPMColor* dptr = dst->getAddr32(0, y);
187 int m[9];
188 int x = 0;
189 m[1] = SkGetPackedA32(*row0++);
190 m[2] = SkGetPackedA32(*row0++);
191 m[4] = SkGetPackedA32(*row1++);
192 m[5] = SkGetPackedA32(*row1++);
193 m[7] = SkGetPackedA32(*row2++);
194 m[8] = SkGetPackedA32(*row2++);
195 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000196 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000197 for (x = 1; x < src.width() - 1; ++x) {
198 shiftMatrixLeft(m);
199 m[2] = SkGetPackedA32(*row0++);
200 m[5] = SkGetPackedA32(*row1++);
201 m[8] = SkGetPackedA32(*row2++);
202 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000203 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 }
205 shiftMatrixLeft(m);
206 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000207 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000208 }
209
210 {
211 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
212 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
213 int x = 0;
214 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
215 int m[9];
216 m[1] = SkGetPackedA32(*row0++);
217 m[2] = SkGetPackedA32(*row0++);
218 m[4] = SkGetPackedA32(*row1++);
219 m[5] = SkGetPackedA32(*row1++);
220 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000221 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000222 for (x = 1; x < src.width() - 1; ++x)
223 {
224 shiftMatrixLeft(m);
225 m[2] = SkGetPackedA32(*row0++);
226 m[5] = SkGetPackedA32(*row1++);
227 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000228 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000229 }
230 shiftMatrixLeft(m);
231 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000232 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 }
234}
235
236SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
237 SkPoint3 point;
238 point.fX = buffer.readScalar();
239 point.fY = buffer.readScalar();
240 point.fZ = buffer.readScalar();
241 return point;
242};
243
244void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
245 buffer.writeScalar(point.fX);
246 buffer.writeScalar(point.fY);
247 buffer.writeScalar(point.fZ);
248};
249
250class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
251public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000252 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000253 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
254
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000255 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000256 SkScalar kd() const { return fKD; }
257
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000258protected:
259 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
260 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
261 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
262 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
263
264
265private:
266 typedef SkLightingImageFilter INHERITED;
267 SkScalar fKD;
268};
269
270class SkSpecularLightingImageFilter : public SkLightingImageFilter {
271public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000272 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000273 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
274
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000275 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000276 SkScalar ks() const { return fKS; }
277 SkScalar shininess() const { return fShininess; }
278
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000279protected:
280 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
281 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
282 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
283 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
284
285private:
286 typedef SkLightingImageFilter INHERITED;
287 SkScalar fKS;
288 SkScalar fShininess;
289};
290
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000291
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000292class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000293public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000294 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000295 virtual ~GrLightingEffect();
296
297 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
298
299 const SkLight* light() const { return fLight; }
300 SkScalar surfaceScale() const { return fSurfaceScale; }
301private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000302 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000303 const SkLight* fLight;
304 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000305};
306
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000307class GrDiffuseLightingEffect : public GrLightingEffect {
308public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000309 GrDiffuseLightingEffect(GrTexture* texture,
310 const SkLight* light,
311 SkScalar surfaceScale,
312 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000313
314 static const char* Name() { return "DiffuseLighting"; }
315
316 typedef GrGLDiffuseLightingEffect GLProgramStage;
317
318 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
319 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
320 SkScalar kd() const { return fKD; }
321private:
322 typedef GrLightingEffect INHERITED;
323 SkScalar fKD;
324};
325
326class GrSpecularLightingEffect : public GrLightingEffect {
327public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000328 GrSpecularLightingEffect(GrTexture* texture,
329 const SkLight* light,
330 SkScalar surfaceScale,
331 SkScalar ks,
332 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000333
334 static const char* Name() { return "SpecularLighting"; }
335
336 typedef GrGLSpecularLightingEffect GLProgramStage;
337
338 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
339 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
340 SkScalar ks() const { return fKS; }
341 SkScalar shininess() const { return fShininess; }
342
343private:
344 typedef GrLightingEffect INHERITED;
345 SkScalar fKS;
346 SkScalar fShininess;
347};
348
349///////////////////////////////////////////////////////////////////////////////
350
351class GrGLLight {
352public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000353 virtual ~GrGLLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000354 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
355 virtual void emitVS(SkString* builder) const {}
356 virtual void emitFuncs(SkString* builder) const {}
357 virtual void emitSurfaceToLight(SkString* builder, const char* z) const = 0;
358 virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
359 virtual void initUniforms(const GrGLInterface* gl, int programID);
360 virtual void setData(const GrGLInterface*, const SkLight* light) const;
361
362private:
363 typedef SkRefCnt INHERITED;
364
365protected:
366 const GrGLShaderVar* fColorVar;
367 int fColorVarLocation;
368};
369
370///////////////////////////////////////////////////////////////////////////////
371
372class GrGLDistantLight : public GrGLLight {
373public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000374 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000375 virtual void setupVariables(GrGLShaderBuilder* state, int stage) SK_OVERRIDE;
376 virtual void initUniforms(const GrGLInterface* gl, int programID) SK_OVERRIDE;
377 virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
378 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
379
380private:
381 typedef GrGLLight INHERITED;
382 const GrGLShaderVar* fDirectionVar;
383 int fDirectionLocation;
384};
385
386///////////////////////////////////////////////////////////////////////////////
387
388class GrGLPointLight : public GrGLLight {
389public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000390 virtual ~GrGLPointLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000391 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
392 virtual void initUniforms(const GrGLInterface* gl, int programID);
393 virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
394 virtual void emitVS(SkString* builder) const;
395 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
396
397private:
398 typedef GrGLLight INHERITED;
399 SkPoint3 fLocation;
400 const GrGLShaderVar* fLocationVar;
401 int fLocationLocation;
402 const char* fHeightVaryingName;
403};
404
405///////////////////////////////////////////////////////////////////////////////
406
407class GrGLSpotLight : public GrGLLight {
408public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000409 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000410 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
411 virtual void initUniforms(const GrGLInterface* gl, int programID);
412 virtual void setData(const GrGLInterface* gl, const SkLight* light) const SK_OVERRIDE;
413 virtual void emitVS(SkString* builder) const;
414 virtual void emitFuncs(SkString* builder) const;
415 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
416 virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
417
418private:
419 typedef GrGLLight INHERITED;
420
421 const GrGLShaderVar* fLocationVar;
422 int fLocationLocation;
423 const GrGLShaderVar* fExponentVar;
424 int fExponentLocation;
425 const GrGLShaderVar* fCosOuterConeAngleVar;
426 int fCosOuterConeAngleLocation;
427 const GrGLShaderVar* fCosInnerConeAngleVar;
428 int fCosInnerConeAngleLocation;
429 const GrGLShaderVar* fConeScaleVar;
430 int fConeScaleLocation;
431 const GrGLShaderVar* fSVar;
432 int fSLocation;
433 const char* fHeightVaryingName;
434};
435
436};
437
438///////////////////////////////////////////////////////////////////////////////
439
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000440class SkLight : public SkFlattenable {
441public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000442 SK_DECLARE_INST_COUNT(SkLight)
443
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000444 enum LightType {
445 kDistant_LightType,
446 kPoint_LightType,
447 kSpot_LightType,
448 };
449 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000450 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000451 virtual GrGLLight* createGLLight() const = 0;
452 virtual bool isEqual(const SkLight& other) const {
453 return fColor == other.fColor;
454 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000455
djsollen@google.com08337772012-06-26 14:33:13 +0000456protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000457 SkLight(SkColor color)
458 : fColor(SkIntToScalar(SkColorGetR(color)),
459 SkIntToScalar(SkColorGetG(color)),
460 SkIntToScalar(SkColorGetB(color))) {}
461 SkLight(SkFlattenableReadBuffer& buffer)
462 : INHERITED(buffer) {
463 fColor = readPoint3(buffer);
464 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000465 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000466 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000467 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000468 }
djsollen@google.com08337772012-06-26 14:33:13 +0000469
470private:
471 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000472 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000473};
474
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000475SK_DEFINE_INST_COUNT(SkLight)
476
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000477///////////////////////////////////////////////////////////////////////////////
478
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479class SkDistantLight : public SkLight {
480public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000481 SkDistantLight(const SkPoint3& direction, SkColor color)
482 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483 }
djsollen@google.com08337772012-06-26 14:33:13 +0000484
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
486 return fDirection;
487 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000488 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000489 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490 const SkPoint3& direction() const { return fDirection; }
491 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000492 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
493 if (other.type() != kDistant_LightType) {
494 return false;
495 }
496
497 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
498 return INHERITED::isEqual(other) &&
499 fDirection == o.fDirection;
500 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501
502 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
503
djsollen@google.com08337772012-06-26 14:33:13 +0000504protected:
505 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
506 fDirection = readPoint3(buffer);
507 }
508 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
509 INHERITED::flatten(buffer);
510 writePoint3(fDirection, buffer);
511 }
512
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000513private:
djsollen@google.com08337772012-06-26 14:33:13 +0000514 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515 SkPoint3 fDirection;
516};
517
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518///////////////////////////////////////////////////////////////////////////////
519
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000520class SkPointLight : public SkLight {
521public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000522 SkPointLight(const SkPoint3& location, SkColor color)
523 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000524
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
526 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
527 fLocation.fY - SkIntToScalar(y),
528 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
529 direction.normalize();
530 return direction;
531 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000532 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000533 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534 const SkPoint3& location() const { return fLocation; }
535 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
536 return new GrGLPointLight();
537 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000538 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000539 if (other.type() != kPoint_LightType) {
540 return false;
541 }
542 const SkPointLight& o = static_cast<const SkPointLight&>(other);
543 return INHERITED::isEqual(other) &&
544 fLocation == o.fLocation;
545 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000546
547 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
548
djsollen@google.com08337772012-06-26 14:33:13 +0000549protected:
550 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
551 fLocation = readPoint3(buffer);
552 }
553 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
554 INHERITED::flatten(buffer);
555 writePoint3(fLocation, buffer);
556 }
557
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000558private:
djsollen@google.com08337772012-06-26 14:33:13 +0000559 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560 SkPoint3 fLocation;
561};
562
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000563///////////////////////////////////////////////////////////////////////////////
564
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000565class SkSpotLight : public SkLight {
566public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000567 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
568 : INHERITED(color),
569 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000570 fTarget(target),
571 fSpecularExponent(specularExponent)
572 {
573 fS = target - location;
574 fS.normalize();
575 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
576 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
577 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
578 fConeScale = SkScalarInvert(antiAliasThreshold);
579 }
djsollen@google.com08337772012-06-26 14:33:13 +0000580
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000581 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
582 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
583 fLocation.fY - SkIntToScalar(y),
584 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
585 direction.normalize();
586 return direction;
587 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000588 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589 SkScalar cosAngle = -surfaceToLight.dot(fS);
590 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000591 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000592 }
593 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
594 if (cosAngle < fCosInnerConeAngle) {
595 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000596 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000597 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000598 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000599 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000600 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
601 return new GrGLSpotLight();
602 }
djsollen@google.com08337772012-06-26 14:33:13 +0000603 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000604 const SkPoint3& location() const { return fLocation; }
605 const SkPoint3& target() const { return fTarget; }
606 SkScalar specularExponent() const { return fSpecularExponent; }
607 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
608 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
609 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000610 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000611
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000612 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
613
djsollen@google.com08337772012-06-26 14:33:13 +0000614protected:
615 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
616 fLocation = readPoint3(buffer);
617 fTarget = readPoint3(buffer);
618 fSpecularExponent = buffer.readScalar();
619 fCosOuterConeAngle = buffer.readScalar();
620 fCosInnerConeAngle = buffer.readScalar();
621 fConeScale = buffer.readScalar();
622 fS = readPoint3(buffer);
623 }
624 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
625 INHERITED::flatten(buffer);
626 writePoint3(fLocation, buffer);
627 writePoint3(fTarget, buffer);
628 buffer.writeScalar(fSpecularExponent);
629 buffer.writeScalar(fCosOuterConeAngle);
630 buffer.writeScalar(fCosInnerConeAngle);
631 buffer.writeScalar(fConeScale);
632 writePoint3(fS, buffer);
633 }
634
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000635 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000636 if (other.type() != kSpot_LightType) {
637 return false;
638 }
639
640 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
641 return INHERITED::isEqual(other) &&
642 fLocation == o.fLocation &&
643 fTarget == o.fTarget &&
644 fSpecularExponent == o.fSpecularExponent &&
645 fCosOuterConeAngle == o.fCosOuterConeAngle;
646 }
647
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000648private:
djsollen@google.com08337772012-06-26 14:33:13 +0000649 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000650 SkPoint3 fLocation;
651 SkPoint3 fTarget;
652 SkScalar fSpecularExponent;
653 SkScalar fCosOuterConeAngle;
654 SkScalar fCosInnerConeAngle;
655 SkScalar fConeScale;
656 SkPoint3 fS;
657};
658
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000659///////////////////////////////////////////////////////////////////////////////
660
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000661SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000662 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000663 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
664{
665 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000666 // our caller knows that we take ownership of the light, so we don't
667 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000668}
669
670SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000671 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000672 SkScalar kd) {
673 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000674 new SkDistantLight(direction, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000675}
676
677SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000678 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000679 SkScalar kd) {
680 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000681 new SkPointLight(location, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000682}
683
684SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000685 const SkPoint3& location, const SkPoint3& target,
686 SkScalar specularExponent, SkScalar cutoffAngle,
687 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000688 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000689 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
690 surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691}
692
693SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000694 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 SkScalar ks, SkScalar shininess) {
696 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000697 new SkDistantLight(direction, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698}
699
700SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000701 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
702 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000704 new SkPointLight(location, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000705}
706
707SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000708 const SkPoint3& location, const SkPoint3& target,
709 SkScalar specularExponent, SkScalar cutoffAngle,
710 SkColor lightColor, SkScalar surfaceScale,
711 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000713 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
714 surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000715}
716
717SkLightingImageFilter::~SkLightingImageFilter() {
718 fLight->unref();
719}
720
721SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
722 : INHERITED(buffer)
723{
djsollen@google.com08337772012-06-26 14:33:13 +0000724 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000725 fSurfaceScale = buffer.readScalar();
726}
727
728void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
729 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000730 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 buffer.writeScalar(fSurfaceScale);
732}
733
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000734///////////////////////////////////////////////////////////////////////////////
735
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000736SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
737 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738 fKD(kd)
739{
740}
741
742SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
743 : INHERITED(buffer)
744{
745 fKD = buffer.readScalar();
746}
747
748void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
749 this->INHERITED::flatten(buffer);
750 buffer.writeScalar(fKD);
751}
752
753bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
754 const SkBitmap& src,
755 const SkMatrix&,
756 SkBitmap* dst,
757 SkIPoint*) {
758 if (src.config() != SkBitmap::kARGB_8888_Config) {
759 return false;
760 }
761 SkAutoLockPixels alp(src);
762 if (!src.getPixels()) {
763 return false;
764 }
765 if (src.width() < 2 || src.height() < 2) {
766 return false;
767 }
768 dst->setConfig(src.config(), src.width(), src.height());
769 dst->allocPixels();
770
771 DiffuseLightingType lightingType(fKD);
772 switch (light()->type()) {
773 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000774 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000775 break;
776 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000777 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000778 break;
779 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000780 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000781 break;
782 }
783 return true;
784}
785
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000786bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
787 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000788 if (stage) {
789 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000790 *stage = new GrDiffuseLightingEffect(texture, light(), scale, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000791 }
792 return true;
793}
794
795///////////////////////////////////////////////////////////////////////////////
796
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000797SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
798 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000799 fKS(ks),
800 fShininess(shininess)
801{
802}
803
804SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
805 : INHERITED(buffer)
806{
807 fKS = buffer.readScalar();
808 fShininess = buffer.readScalar();
809}
810
811void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
812 this->INHERITED::flatten(buffer);
813 buffer.writeScalar(fKS);
814 buffer.writeScalar(fShininess);
815}
816
817bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
818 const SkBitmap& src,
819 const SkMatrix&,
820 SkBitmap* dst,
821 SkIPoint*) {
822 if (src.config() != SkBitmap::kARGB_8888_Config) {
823 return false;
824 }
825 SkAutoLockPixels alp(src);
826 if (!src.getPixels()) {
827 return false;
828 }
829 if (src.width() < 2 || src.height() < 2) {
830 return false;
831 }
832 dst->setConfig(src.config(), src.width(), src.height());
833 dst->allocPixels();
834
835 SpecularLightingType lightingType(fKS, fShininess);
836 switch (light()->type()) {
837 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000838 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000839 break;
840 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000841 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000842 break;
843 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000844 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000845 break;
846 }
847 return true;
848}
849
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000850bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
851 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000852 if (stage) {
853 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000854 *stage = new GrSpecularLightingEffect(texture, light(), scale, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000855 }
856 return true;
857}
858
859///////////////////////////////////////////////////////////////////////////////
860
861class GrGLLightingEffect : public GrGLProgramStage {
862public:
863 GrGLLightingEffect(const GrProgramStageFactory& factory,
864 const GrCustomStage& stage);
865 virtual ~GrGLLightingEffect();
866
867 virtual void setupVariables(GrGLShaderBuilder* state,
868 int stage) SK_OVERRIDE;
869 virtual void emitVS(GrGLShaderBuilder* state,
870 const char* vertexCoords) SK_OVERRIDE;
871 virtual void emitFS(GrGLShaderBuilder* state,
872 const char* outputColor,
873 const char* inputColor,
874 const char* samplerName) SK_OVERRIDE;
875
876 virtual void emitLightFunc(SkString* funcs) = 0;
877
878 static inline StageKey GenKey(const GrCustomStage& s);
879
880 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
881 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000882 const GrCustomStage&,
883 int stageNum) SK_OVERRIDE;
884
885private:
886 typedef GrGLProgramStage INHERITED;
887
888 const GrGLShaderVar* fImageIncrementVar;
889 GrGLint fImageIncrementLocation;
890 const GrGLShaderVar* fSurfaceScaleVar;
891 GrGLint fSurfaceScaleLocation;
892 GrGLLight* fLight;
893};
894
895///////////////////////////////////////////////////////////////////////////////
896
897class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
898public:
899 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
900 const GrCustomStage& stage);
901 virtual void setupVariables(GrGLShaderBuilder* state,
902 int stage) SK_OVERRIDE;
903 virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
904 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
905 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000906 const GrCustomStage&,
907 int stageNum) SK_OVERRIDE;
908
909private:
910 typedef GrGLLightingEffect INHERITED;
911
912 const GrGLShaderVar* fKDVar;
913 GrGLint fKDLocation;
914};
915
916///////////////////////////////////////////////////////////////////////////////
917
918class GrGLSpecularLightingEffect : public GrGLLightingEffect {
919public:
920 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
921 const GrCustomStage& stage);
922 virtual void setupVariables(GrGLShaderBuilder* state,
923 int stage) SK_OVERRIDE;
924 virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
925 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
926 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000927 const GrCustomStage&,
928 int stageNum) SK_OVERRIDE;
929
930private:
931 typedef GrGLLightingEffect INHERITED;
932
933 const GrGLShaderVar* fKSVar;
934 GrGLint fKSLocation;
935 const GrGLShaderVar* fShininessVar;
936 GrGLint fShininessLocation;
937};
938
939///////////////////////////////////////////////////////////////////////////////
940
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000941GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
942 : GrSingleTextureEffect(texture)
943 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000944 , fSurfaceScale(surfaceScale) {
945 fLight->ref();
946}
947
948GrLightingEffect::~GrLightingEffect() {
949 fLight->unref();
950}
951
952bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
953 const GrLightingEffect& s =
954 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000955 return INHERITED::isEqual(sBase) &&
956 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000957 fSurfaceScale == s.fSurfaceScale;
958}
959
960///////////////////////////////////////////////////////////////////////////////
961
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000962GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
963 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000964}
965
966const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
967 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
968}
969
970bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
971 const GrDiffuseLightingEffect& s =
972 static_cast<const GrDiffuseLightingEffect&>(sBase);
973 return INHERITED::isEqual(sBase) &&
974 this->kd() == s.kd();
975}
976
977///////////////////////////////////////////////////////////////////////////////
978
979GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
980 const GrCustomStage& stage)
981 : GrGLProgramStage(factory)
982 , fImageIncrementVar(NULL)
983 , fImageIncrementLocation(0)
984 , fSurfaceScaleVar(NULL)
985 , fSurfaceScaleLocation(0) {
986 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
987 fLight = m.light()->createGLLight();
988}
989
990GrGLLightingEffect::~GrGLLightingEffect() {
991 delete fLight;
992}
993
994void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
995 fImageIncrementVar = &state->addUniform(
996 GrGLShaderBuilder::kFragment_ShaderType,
997 kVec2f_GrSLType, "uImageIncrement", stage);
998 fSurfaceScaleVar = &state->addUniform(
999 GrGLShaderBuilder::kFragment_ShaderType,
1000 kFloat_GrSLType, "uSurfaceScale", stage);
1001 fLight->setupVariables(state, stage);
1002}
1003
1004void GrGLLightingEffect::emitVS(GrGLShaderBuilder* state,
1005 const char* vertexCoords) {
1006 fLight->emitVS(&state->fVSCode);
1007}
1008
1009void GrGLLightingEffect::initUniforms(const GrGLInterface* gl,
1010 int programID) {
1011 GR_GL_CALL_RET(gl, fSurfaceScaleLocation,
1012 GetUniformLocation(programID,
1013 fSurfaceScaleVar->getName().c_str()));
1014 GR_GL_CALL_RET(gl, fImageIncrementLocation,
1015 GetUniformLocation(programID,
1016 fImageIncrementVar->getName().c_str()));
1017 fLight->initUniforms(gl, programID);
1018}
1019
1020void GrGLLightingEffect::emitFS(GrGLShaderBuilder* state,
1021 const char* outputColor,
1022 const char* inputColor,
1023 const char* samplerName) {
1024 SkString* code = &state->fFSCode;
1025 SkString* funcs = &state->fFSFunctions;
1026 fLight->emitFuncs(funcs);
1027 emitLightFunc(funcs);
1028 funcs->appendf("float sobel(float a, float b, float c, float d, float e, float f, float scale) {\n");
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001029 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001030 funcs->appendf("}\n");
1031 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1032 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1033 funcs->appendf("}\n");
1034 funcs->append("\n\
1035vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1036 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1037 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1038 surfaceScale);\n}\n");
1039
1040 code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
1041 code->appendf("\t\tfloat m[9];\n");
1042 int index = 0;
1043 for (int dy = -1; dy <= 1; dy++) {
1044 for (int dx = -1; dx <= 1; dx++) {
1045 SkString texCoords;
1046 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, fImageIncrementVar->getName().c_str());
1047 code->appendf("\t\tm[%d] = ", index++);
1048 state->emitTextureLookup(samplerName, texCoords.c_str());
1049 code->appendf(".a;\n");
1050 }
1051 }
1052 code->appendf("\t\tvec3 surfaceToLight = ");
1053 SkString arg;
1054 arg.appendf("%s * m[4]", fSurfaceScaleVar->getName().c_str());
1055 fLight->emitSurfaceToLight(code, arg.c_str());
1056 code->appendf(";\n");
1057 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, fSurfaceScaleVar->getName().c_str());
1058 fLight->emitLightColor(code, "surfaceToLight");
1059 code->appendf(")%s;\n", state->fModulate.c_str());
1060}
1061
1062GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1063 const GrCustomStage& s) {
1064 return static_cast<const GrLightingEffect&>(s).light()->type();
1065}
1066
1067void GrGLLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001068 const GrCustomStage& data,
1069 int stageNum) {
1070 const GrLightingEffect& effect =
1071 static_cast<const GrLightingEffect&>(data);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001072 GrTexture& texture = *data.texture(0);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001073 GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture.width(), 1.0f / texture.height()));
1074 GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
1075 fLight->setData(gl, effect.light());
1076}
1077
1078///////////////////////////////////////////////////////////////////////////////
1079
1080///////////////////////////////////////////////////////////////////////////////
1081
1082GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1083 const GrCustomStage& stage)
1084 : INHERITED(factory, stage)
1085 , fKDVar(NULL)
1086 , fKDLocation(0) {
1087}
1088
1089void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1090 INHERITED::setupVariables(state, stage);
1091 fKDVar = &state->addUniform(
1092 GrGLShaderBuilder::kFragment_ShaderType,
1093 kFloat_GrSLType, "uKD", stage);
1094}
1095
1096void GrGLDiffuseLightingEffect::initUniforms(const GrGLInterface* gl,
1097 int programID) {
1098 INHERITED::initUniforms(gl, programID);
1099 GR_GL_CALL_RET(gl, fKDLocation,
1100 GetUniformLocation(programID,
1101 fKDVar->getName().c_str()));
1102}
1103
1104void GrGLDiffuseLightingEffect::emitLightFunc(SkString* funcs) {
1105 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1106 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", fKDVar->getName().c_str());
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001107 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001108 funcs->appendf("}\n");
1109}
1110
1111void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001112 const GrCustomStage& data,
1113 int stageNum) {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001114 INHERITED::setData(gl, data, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001115 const GrDiffuseLightingEffect& effect =
1116 static_cast<const GrDiffuseLightingEffect&>(data);
1117 GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
1118}
1119
1120///////////////////////////////////////////////////////////////////////////////
1121
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001122GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1123 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001124 fKS(ks),
1125 fShininess(shininess) {
1126}
1127
1128const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1129 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1130}
1131
1132bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1133 const GrSpecularLightingEffect& s =
1134 static_cast<const GrSpecularLightingEffect&>(sBase);
1135 return INHERITED::isEqual(sBase) &&
1136 this->ks() == s.ks() &&
1137 this->shininess() == s.shininess();
1138}
1139
1140///////////////////////////////////////////////////////////////////////////////
1141
1142GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1143 const GrCustomStage& stage)
1144 : GrGLLightingEffect(factory, stage)
1145 , fKSVar(NULL)
1146 , fKSLocation(0)
1147 , fShininessVar(NULL)
1148 , fShininessLocation(0) {
1149}
1150
1151void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1152 INHERITED::setupVariables(state, stage);
1153 fKSVar = &state->addUniform(
1154 GrGLShaderBuilder::kFragment_ShaderType,
1155 kFloat_GrSLType, "uKS", stage);
1156 fShininessVar = &state->addUniform(
1157 GrGLShaderBuilder::kFragment_ShaderType,
1158 kFloat_GrSLType, "uShininess", stage);
1159}
1160
1161void GrGLSpecularLightingEffect::initUniforms(const GrGLInterface* gl,
1162 int programID) {
1163 INHERITED::initUniforms(gl, programID);
1164 GR_GL_CALL_RET(gl, fKSLocation,
1165 GetUniformLocation(programID, fKSVar->getName().c_str()));
1166 GR_GL_CALL_RET(gl, fShininessLocation,
1167 GetUniformLocation(programID, fShininessVar->getName().c_str()));
1168}
1169
1170void GrGLSpecularLightingEffect::emitLightFunc(SkString* funcs) {
1171 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1172 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1173
1174 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n",
1175 fKSVar->getName().c_str(), fShininessVar->getName().c_str());
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001176 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001177 funcs->appendf("}\n");
1178}
1179
1180void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001181 const GrCustomStage& data,
1182 int stageNum) {
1183 INHERITED::setData(gl, data, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001184 const GrSpecularLightingEffect& effect =
1185 static_cast<const GrSpecularLightingEffect&>(data);
1186 GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
1187 GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
1188}
1189
1190///////////////////////////////////////////////////////////////////////////////
1191
1192void GrGLLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
1193 builder->append(fColorVar->getName().c_str());
1194}
1195
1196void GrGLLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1197 fColorVar = &state->addUniform(
1198 GrGLShaderBuilder::kFragment_ShaderType,
1199 kVec3f_GrSLType, "uLightColor", stage);
1200}
1201
1202void GrGLLight::initUniforms(const GrGLInterface* gl, int programID) {
1203 GR_GL_CALL_RET(gl, fColorVarLocation,
1204 GetUniformLocation(programID, fColorVar->getName().c_str()));
1205}
1206
1207void GrGLLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1208 setUniformPoint3(gl, fColorVarLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
1209}
1210
1211GrGLLight* SkDistantLight::createGLLight() const {
1212 return new GrGLDistantLight();
1213}
1214
1215///////////////////////////////////////////////////////////////////////////////
1216
1217void GrGLDistantLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1218 INHERITED::setupVariables(state, stage);
1219 fDirectionVar = &state->addUniform(
1220 GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1221 "uLightDirection", stage);
1222}
1223
1224void GrGLDistantLight::initUniforms(const GrGLInterface* gl, int programID) {
1225 INHERITED::initUniforms(gl, programID);
1226 GR_GL_CALL_RET(gl, fDirectionLocation,
1227 GetUniformLocation(programID, fDirectionVar->getName().c_str()));
1228}
1229
1230void GrGLDistantLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1231 INHERITED::setData(gl, light);
1232 SkASSERT(light->type() == SkLight::kDistant_LightType);
1233 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
1234 setUniformPoint3(gl, fDirectionLocation, distantLight->direction());
1235}
1236
1237void GrGLDistantLight::emitSurfaceToLight(SkString* builder,
1238 const char* z) const {
1239 builder->append(fDirectionVar->getName().c_str());
1240}
1241
1242///////////////////////////////////////////////////////////////////////////////
1243
1244void GrGLPointLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1245 INHERITED::setupVariables(state, stage);
1246 fLocationVar = &state->addUniform(
1247 GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1248 "uLightLocation", stage);
1249 state->addVarying(kFloat_GrSLType, "Height", stage, &fHeightVaryingName);
1250}
1251
1252void GrGLPointLight::initUniforms(const GrGLInterface* gl, int programID) {
1253 INHERITED::initUniforms(gl, programID);
1254 GR_GL_CALL_RET(gl, fLocationLocation,
1255 GetUniformLocation(programID, fLocationVar->getName().c_str()));
1256}
1257
1258void GrGLPointLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1259 INHERITED::setData(gl, light);
1260 SkASSERT(light->type() == SkLight::kPoint_LightType);
1261 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
1262 setUniformPoint3(gl, fLocationLocation, pointLight->location());
1263}
1264
1265void GrGLPointLight::emitVS(SkString* builder) const {
1266 // Compute viewport height from the Y scale of the matrix.
1267 builder->appendf("\t\t%s = -2.0 / uViewM[1][1];\n", fHeightVaryingName);
1268}
1269
1270void GrGLPointLight::emitSurfaceToLight(SkString* builder,
1271 const char* z) const {
1272 builder->appendf(
1273 "normalize(%s - vec3(gl_FragCoord.x, %s - gl_FragCoord.y, %s))",
1274 fLocationVar->getName().c_str(), fHeightVaryingName, z);
1275}
1276
1277///////////////////////////////////////////////////////////////////////////////
1278
1279void GrGLSpotLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1280 INHERITED::setupVariables(state, stage);
1281 fLocationVar = &state->addUniform(
1282 GrGLShaderBuilder::kFragment_ShaderType,
1283 kVec3f_GrSLType, "uLightLocation", stage);
1284 fExponentVar = &state->addUniform(
1285 GrGLShaderBuilder::kFragment_ShaderType,
1286 kFloat_GrSLType, "uExponent", stage);
1287 fCosInnerConeAngleVar = &state->addUniform(
1288 GrGLShaderBuilder::kFragment_ShaderType,
1289 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1290 fCosOuterConeAngleVar = &state->addUniform(
1291 GrGLShaderBuilder::kFragment_ShaderType,
1292 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1293 fConeScaleVar = &state->addUniform(
1294 GrGLShaderBuilder::kFragment_ShaderType,
1295 kFloat_GrSLType, "uConeScale", stage);
1296 fSVar = &state->addUniform(
1297 GrGLShaderBuilder::kFragment_ShaderType,
1298 kVec3f_GrSLType, "uS", stage);
1299 state->addVarying(kFloat_GrSLType, "Height", stage, &fHeightVaryingName);
1300}
1301
1302void GrGLSpotLight::initUniforms(const GrGLInterface* gl, int programID) {
1303 INHERITED::initUniforms(gl, programID);
1304 GR_GL_CALL_RET(gl, fLocationLocation,
1305 GetUniformLocation(programID, fLocationVar->getName().c_str()));
1306 GR_GL_CALL_RET(gl, fExponentLocation,
1307 GetUniformLocation(programID, fExponentVar->getName().c_str()));
1308 GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation,
1309 GetUniformLocation(programID, fCosInnerConeAngleVar->getName().c_str()));
1310 GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation,
1311 GetUniformLocation(programID, fCosOuterConeAngleVar->getName().c_str()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001312 GR_GL_CALL_RET(gl, fConeScaleLocation,
1313 GetUniformLocation(programID, fConeScaleVar->getName().c_str()));
1314 GR_GL_CALL_RET(gl, fSLocation,
1315 GetUniformLocation(programID, fSVar->getName().c_str()));
1316}
1317
1318void GrGLSpotLight::setData(const GrGLInterface* gl, const SkLight* light) const {
1319 INHERITED::setData(gl, light);
1320 SkASSERT(light->type() == SkLight::kSpot_LightType);
1321 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
1322 setUniformPoint3(gl, fLocationLocation, spotLight->location());
1323 GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
1324 GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
1325 GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
1326 GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
1327 setUniformPoint3(gl, fSLocation, spotLight->s());
1328}
1329
1330void GrGLSpotLight::emitVS(SkString* builder) const {
1331 // Compute viewport height from the Y scale of the matrix.
1332 builder->appendf("\t\t%s = -2.0 / uViewM[1][1];\n", fHeightVaryingName);
1333}
1334
1335void GrGLSpotLight::emitFuncs(SkString* builder) const {
1336 builder->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1337 builder->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", fSVar->getName().c_str());
1338 builder->appendf("\tif (cosAngle < %s) {\n", fCosOuterConeAngleVar->getName().c_str());
1339 builder->appendf("\t\treturn vec3(0);\n");
1340 builder->appendf("\t}\n");
1341 builder->appendf("\tfloat scale = pow(cosAngle, %s);\n", fExponentVar->getName().c_str());
1342 builder->appendf("\tif (cosAngle < %s) {\n", fCosInnerConeAngleVar->getName().c_str());
1343 builder->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", fColorVar->getName().c_str(), fCosOuterConeAngleVar->getName().c_str(), fConeScaleVar->getName().c_str());
1344 builder->appendf("\t}\n");
1345 builder->appendf("\treturn %s;\n", fColorVar->getName().c_str());
1346 builder->appendf("}\n");
1347}
1348
1349void GrGLSpotLight::emitSurfaceToLight(SkString* builder, const char* z) const {
1350 builder->appendf("normalize(%s - vec3(gl_FragCoord.x, %s - gl_FragCoord.y, %s))", fLocationVar->getName().c_str(), fHeightVaryingName, z);
1351}
1352
1353void GrGLSpotLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
1354 builder->appendf("lightColor(%s)", surfaceToLight);
1355}
1356
djsollen@google.com08337772012-06-26 14:33:13 +00001357SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1358 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1359 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1360 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1361 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1362 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1363SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END