blob: d4e2a3e259b7ce38b1e62e3412c7563033d8252c [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.orgf4770d72012-07-13 18:25:06 +000038void setUniformNormal3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
39 setUniformPoint3(gl, location, SkPoint3(point.fX, -point.fY, point.fZ));
40}
41
42void setUniformPoint3FlipY(const GrGLInterface* gl, GrGLint location, const SkPoint3& point, int height) {
43 setUniformPoint3(gl, location, SkPoint3(point.fX, height-point.fY, point.fZ));
44}
45
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000046// Shift matrix components to the left, as we advance pixels to the right.
47inline void shiftMatrixLeft(int m[9]) {
48 m[0] = m[1];
49 m[3] = m[4];
50 m[6] = m[7];
51 m[1] = m[2];
52 m[4] = m[5];
53 m[7] = m[8];
54}
55
56class DiffuseLightingType {
57public:
58 DiffuseLightingType(SkScalar kd)
59 : fKD(kd) {}
60 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
61 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
62 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
63 SkPoint3 color(lightColor * colorScale);
64 return SkPackARGB32(255,
65 SkScalarFloorToInt(color.fX),
66 SkScalarFloorToInt(color.fY),
67 SkScalarFloorToInt(color.fZ));
68 }
69private:
70 SkScalar fKD;
71};
72
73class SpecularLightingType {
74public:
75 SpecularLightingType(SkScalar ks, SkScalar shininess)
76 : fKS(ks), fShininess(shininess) {}
77 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
78 SkPoint3 halfDir(surfaceTolight);
79 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
80 halfDir.normalize();
81 SkScalar colorScale = SkScalarMul(fKS,
82 SkScalarPow(normal.dot(halfDir), fShininess));
83 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
84 SkPoint3 color(lightColor * colorScale);
85 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
86 SkScalarFloorToInt(color.fX),
87 SkScalarFloorToInt(color.fY),
88 SkScalarFloorToInt(color.fZ));
89 }
90private:
91 SkScalar fKS;
92 SkScalar fShininess;
93};
94
95inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
96 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
97}
98
99inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
100 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
101 SkScalarMul(-y, surfaceScale),
102 SK_Scalar1);
103 vector.normalize();
104 return vector;
105}
106
107inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
108 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
109 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
110 surfaceScale);
111}
112
113inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
114 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
115 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
116 surfaceScale);
117}
118
119inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
120 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
121 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
122 surfaceScale);
123}
124
125inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
126 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
127 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
128 surfaceScale);
129}
130
131
132inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
134 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
135 surfaceScale);
136}
137
138inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
139 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
140 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
141 surfaceScale);
142}
143
144inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
145 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
146 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
147 surfaceScale);
148}
149
150inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
151 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
152 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
153 surfaceScale);
154}
155
156inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
157 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
158 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
159 surfaceScale);
160}
161
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000162template <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 +0000163 const LightType* l = static_cast<const LightType*>(light);
164 int y = 0;
165 {
166 const SkPMColor* row1 = src.getAddr32(0, 0);
167 const SkPMColor* row2 = src.getAddr32(0, 1);
168 SkPMColor* dptr = dst->getAddr32(0, 0);
169 int m[9];
170 int x = 0;
171 m[4] = SkGetPackedA32(*row1++);
172 m[5] = SkGetPackedA32(*row1++);
173 m[7] = SkGetPackedA32(*row2++);
174 m[8] = SkGetPackedA32(*row2++);
175 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000176 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000177 for (x = 1; x < src.width() - 1; ++x)
178 {
179 shiftMatrixLeft(m);
180 m[5] = SkGetPackedA32(*row1++);
181 m[8] = SkGetPackedA32(*row2++);
182 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000183 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000184 }
185 shiftMatrixLeft(m);
186 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000187 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 }
189
190 for (++y; y < src.height() - 1; ++y) {
191 const SkPMColor* row0 = src.getAddr32(0, y - 1);
192 const SkPMColor* row1 = src.getAddr32(0, y);
193 const SkPMColor* row2 = src.getAddr32(0, y + 1);
194 SkPMColor* dptr = dst->getAddr32(0, y);
195 int m[9];
196 int x = 0;
197 m[1] = SkGetPackedA32(*row0++);
198 m[2] = SkGetPackedA32(*row0++);
199 m[4] = SkGetPackedA32(*row1++);
200 m[5] = SkGetPackedA32(*row1++);
201 m[7] = SkGetPackedA32(*row2++);
202 m[8] = SkGetPackedA32(*row2++);
203 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000204 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000205 for (x = 1; x < src.width() - 1; ++x) {
206 shiftMatrixLeft(m);
207 m[2] = SkGetPackedA32(*row0++);
208 m[5] = SkGetPackedA32(*row1++);
209 m[8] = SkGetPackedA32(*row2++);
210 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000211 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000212 }
213 shiftMatrixLeft(m);
214 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000215 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 }
217
218 {
219 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
220 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
221 int x = 0;
222 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
223 int m[9];
224 m[1] = SkGetPackedA32(*row0++);
225 m[2] = SkGetPackedA32(*row0++);
226 m[4] = SkGetPackedA32(*row1++);
227 m[5] = SkGetPackedA32(*row1++);
228 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000229 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000230 for (x = 1; x < src.width() - 1; ++x)
231 {
232 shiftMatrixLeft(m);
233 m[2] = SkGetPackedA32(*row0++);
234 m[5] = SkGetPackedA32(*row1++);
235 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000236 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000237 }
238 shiftMatrixLeft(m);
239 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000240 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000241 }
242}
243
244SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
245 SkPoint3 point;
246 point.fX = buffer.readScalar();
247 point.fY = buffer.readScalar();
248 point.fZ = buffer.readScalar();
249 return point;
250};
251
252void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
253 buffer.writeScalar(point.fX);
254 buffer.writeScalar(point.fY);
255 buffer.writeScalar(point.fZ);
256};
257
258class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
259public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000260 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000261 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
262
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000263 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000264 SkScalar kd() const { return fKD; }
265
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000266protected:
267 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
268 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
269 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
270 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
271
272
273private:
274 typedef SkLightingImageFilter INHERITED;
275 SkScalar fKD;
276};
277
278class SkSpecularLightingImageFilter : public SkLightingImageFilter {
279public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000280 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000281 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
282
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000283 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000284 SkScalar ks() const { return fKS; }
285 SkScalar shininess() const { return fShininess; }
286
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000287protected:
288 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
289 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
290 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
291 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
292
293private:
294 typedef SkLightingImageFilter INHERITED;
295 SkScalar fKS;
296 SkScalar fShininess;
297};
298
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000299
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000300class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000301public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000302 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000303 virtual ~GrLightingEffect();
304
305 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
306
307 const SkLight* light() const { return fLight; }
308 SkScalar surfaceScale() const { return fSurfaceScale; }
309private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000310 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000311 const SkLight* fLight;
312 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000313};
314
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000315class GrDiffuseLightingEffect : public GrLightingEffect {
316public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000317 GrDiffuseLightingEffect(GrTexture* texture,
318 const SkLight* light,
319 SkScalar surfaceScale,
320 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000321
322 static const char* Name() { return "DiffuseLighting"; }
323
324 typedef GrGLDiffuseLightingEffect GLProgramStage;
325
326 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
327 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
328 SkScalar kd() const { return fKD; }
329private:
330 typedef GrLightingEffect INHERITED;
331 SkScalar fKD;
332};
333
334class GrSpecularLightingEffect : public GrLightingEffect {
335public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000336 GrSpecularLightingEffect(GrTexture* texture,
337 const SkLight* light,
338 SkScalar surfaceScale,
339 SkScalar ks,
340 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000341
342 static const char* Name() { return "SpecularLighting"; }
343
344 typedef GrGLSpecularLightingEffect GLProgramStage;
345
346 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
347 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
348 SkScalar ks() const { return fKS; }
349 SkScalar shininess() const { return fShininess; }
350
351private:
352 typedef GrLightingEffect INHERITED;
353 SkScalar fKS;
354 SkScalar fShininess;
355};
356
357///////////////////////////////////////////////////////////////////////////////
358
359class GrGLLight {
360public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000361 virtual ~GrGLLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000362 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
363 virtual void emitVS(SkString* builder) const {}
364 virtual void emitFuncs(SkString* builder) const {}
365 virtual void emitSurfaceToLight(SkString* builder, const char* z) const = 0;
366 virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
367 virtual void initUniforms(const GrGLInterface* gl, int programID);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000368 virtual void setData(const GrGLInterface*, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000369
370private:
371 typedef SkRefCnt INHERITED;
372
373protected:
374 const GrGLShaderVar* fColorVar;
375 int fColorVarLocation;
376};
377
378///////////////////////////////////////////////////////////////////////////////
379
380class GrGLDistantLight : public GrGLLight {
381public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000382 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000383 virtual void setupVariables(GrGLShaderBuilder* state, int stage) SK_OVERRIDE;
384 virtual void initUniforms(const GrGLInterface* gl, int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000385 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000386 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
387
388private:
389 typedef GrGLLight INHERITED;
390 const GrGLShaderVar* fDirectionVar;
391 int fDirectionLocation;
392};
393
394///////////////////////////////////////////////////////////////////////////////
395
396class GrGLPointLight : public GrGLLight {
397public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000398 virtual ~GrGLPointLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000399 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
400 virtual void initUniforms(const GrGLInterface* gl, int programID);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000401 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000402 virtual void emitVS(SkString* builder) const;
403 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
404
405private:
406 typedef GrGLLight INHERITED;
407 SkPoint3 fLocation;
408 const GrGLShaderVar* fLocationVar;
409 int fLocationLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000410};
411
412///////////////////////////////////////////////////////////////////////////////
413
414class GrGLSpotLight : public GrGLLight {
415public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000416 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000417 virtual void setupVariables(GrGLShaderBuilder* state, int stage);
418 virtual void initUniforms(const GrGLInterface* gl, int programID);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000419 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000420 virtual void emitVS(SkString* builder) const;
421 virtual void emitFuncs(SkString* builder) const;
422 virtual void emitSurfaceToLight(SkString* builder, const char* z) const SK_OVERRIDE;
423 virtual void emitLightColor(SkString* builder, const char *surfaceToLight) const;
424
425private:
426 typedef GrGLLight INHERITED;
427
428 const GrGLShaderVar* fLocationVar;
429 int fLocationLocation;
430 const GrGLShaderVar* fExponentVar;
431 int fExponentLocation;
432 const GrGLShaderVar* fCosOuterConeAngleVar;
433 int fCosOuterConeAngleLocation;
434 const GrGLShaderVar* fCosInnerConeAngleVar;
435 int fCosInnerConeAngleLocation;
436 const GrGLShaderVar* fConeScaleVar;
437 int fConeScaleLocation;
438 const GrGLShaderVar* fSVar;
439 int fSLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000440};
441
442};
443
444///////////////////////////////////////////////////////////////////////////////
445
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000446class SkLight : public SkFlattenable {
447public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000448 SK_DECLARE_INST_COUNT(SkLight)
449
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000450 enum LightType {
451 kDistant_LightType,
452 kPoint_LightType,
453 kSpot_LightType,
454 };
455 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000456 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000457 virtual GrGLLight* createGLLight() const = 0;
458 virtual bool isEqual(const SkLight& other) const {
459 return fColor == other.fColor;
460 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461
djsollen@google.com08337772012-06-26 14:33:13 +0000462protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000463 SkLight(SkColor color)
464 : fColor(SkIntToScalar(SkColorGetR(color)),
465 SkIntToScalar(SkColorGetG(color)),
466 SkIntToScalar(SkColorGetB(color))) {}
467 SkLight(SkFlattenableReadBuffer& buffer)
468 : INHERITED(buffer) {
469 fColor = readPoint3(buffer);
470 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000472 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000473 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474 }
djsollen@google.com08337772012-06-26 14:33:13 +0000475
476private:
477 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000478 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479};
480
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000481SK_DEFINE_INST_COUNT(SkLight)
482
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000483///////////////////////////////////////////////////////////////////////////////
484
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485class SkDistantLight : public SkLight {
486public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000487 SkDistantLight(const SkPoint3& direction, SkColor color)
488 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000489 }
djsollen@google.com08337772012-06-26 14:33:13 +0000490
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000491 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
492 return fDirection;
493 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000494 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000495 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496 const SkPoint3& direction() const { return fDirection; }
497 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000498 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
499 if (other.type() != kDistant_LightType) {
500 return false;
501 }
502
503 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
504 return INHERITED::isEqual(other) &&
505 fDirection == o.fDirection;
506 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000507
508 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
509
djsollen@google.com08337772012-06-26 14:33:13 +0000510protected:
511 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
512 fDirection = readPoint3(buffer);
513 }
514 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
515 INHERITED::flatten(buffer);
516 writePoint3(fDirection, buffer);
517 }
518
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000519private:
djsollen@google.com08337772012-06-26 14:33:13 +0000520 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000521 SkPoint3 fDirection;
522};
523
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000524///////////////////////////////////////////////////////////////////////////////
525
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000526class SkPointLight : public SkLight {
527public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000528 SkPointLight(const SkPoint3& location, SkColor color)
529 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000530
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000531 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
532 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
533 fLocation.fY - SkIntToScalar(y),
534 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
535 direction.normalize();
536 return direction;
537 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000538 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000540 const SkPoint3& location() const { return fLocation; }
541 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
542 return new GrGLPointLight();
543 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000544 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000545 if (other.type() != kPoint_LightType) {
546 return false;
547 }
548 const SkPointLight& o = static_cast<const SkPointLight&>(other);
549 return INHERITED::isEqual(other) &&
550 fLocation == o.fLocation;
551 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000552
553 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
554
djsollen@google.com08337772012-06-26 14:33:13 +0000555protected:
556 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
557 fLocation = readPoint3(buffer);
558 }
559 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
560 INHERITED::flatten(buffer);
561 writePoint3(fLocation, buffer);
562 }
563
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000564private:
djsollen@google.com08337772012-06-26 14:33:13 +0000565 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000566 SkPoint3 fLocation;
567};
568
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000569///////////////////////////////////////////////////////////////////////////////
570
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000571class SkSpotLight : public SkLight {
572public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000573 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
574 : INHERITED(color),
575 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000576 fTarget(target),
577 fSpecularExponent(specularExponent)
578 {
579 fS = target - location;
580 fS.normalize();
581 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
582 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
583 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
584 fConeScale = SkScalarInvert(antiAliasThreshold);
585 }
djsollen@google.com08337772012-06-26 14:33:13 +0000586
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
588 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
589 fLocation.fY - SkIntToScalar(y),
590 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
591 direction.normalize();
592 return direction;
593 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000594 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000595 SkScalar cosAngle = -surfaceToLight.dot(fS);
596 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000597 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000598 }
599 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
600 if (cosAngle < fCosInnerConeAngle) {
601 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000602 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000603 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000604 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000605 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000606 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
607 return new GrGLSpotLight();
608 }
djsollen@google.com08337772012-06-26 14:33:13 +0000609 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000610 const SkPoint3& location() const { return fLocation; }
611 const SkPoint3& target() const { return fTarget; }
612 SkScalar specularExponent() const { return fSpecularExponent; }
613 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
614 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
615 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000616 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000617
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
619
djsollen@google.com08337772012-06-26 14:33:13 +0000620protected:
621 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
622 fLocation = readPoint3(buffer);
623 fTarget = readPoint3(buffer);
624 fSpecularExponent = buffer.readScalar();
625 fCosOuterConeAngle = buffer.readScalar();
626 fCosInnerConeAngle = buffer.readScalar();
627 fConeScale = buffer.readScalar();
628 fS = readPoint3(buffer);
629 }
630 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
631 INHERITED::flatten(buffer);
632 writePoint3(fLocation, buffer);
633 writePoint3(fTarget, buffer);
634 buffer.writeScalar(fSpecularExponent);
635 buffer.writeScalar(fCosOuterConeAngle);
636 buffer.writeScalar(fCosInnerConeAngle);
637 buffer.writeScalar(fConeScale);
638 writePoint3(fS, buffer);
639 }
640
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000641 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000642 if (other.type() != kSpot_LightType) {
643 return false;
644 }
645
646 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
647 return INHERITED::isEqual(other) &&
648 fLocation == o.fLocation &&
649 fTarget == o.fTarget &&
650 fSpecularExponent == o.fSpecularExponent &&
651 fCosOuterConeAngle == o.fCosOuterConeAngle;
652 }
653
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000654private:
djsollen@google.com08337772012-06-26 14:33:13 +0000655 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000656 SkPoint3 fLocation;
657 SkPoint3 fTarget;
658 SkScalar fSpecularExponent;
659 SkScalar fCosOuterConeAngle;
660 SkScalar fCosInnerConeAngle;
661 SkScalar fConeScale;
662 SkPoint3 fS;
663};
664
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000665///////////////////////////////////////////////////////////////////////////////
666
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000667SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000668 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000669 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
670{
671 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000672 // our caller knows that we take ownership of the light, so we don't
673 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000674}
675
676SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000677 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000678 SkScalar kd) {
679 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000680 new SkDistantLight(direction, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000681}
682
683SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000684 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000685 SkScalar kd) {
686 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000687 new SkPointLight(location, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000688}
689
690SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000691 const SkPoint3& location, const SkPoint3& target,
692 SkScalar specularExponent, SkScalar cutoffAngle,
693 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000694 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000695 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
696 surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000697}
698
699SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000700 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701 SkScalar ks, SkScalar shininess) {
702 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000703 new SkDistantLight(direction, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704}
705
706SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000707 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
708 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000709 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000710 new SkPointLight(location, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711}
712
713SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000714 const SkPoint3& location, const SkPoint3& target,
715 SkScalar specularExponent, SkScalar cutoffAngle,
716 SkColor lightColor, SkScalar surfaceScale,
717 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000718 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000719 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
720 surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000721}
722
723SkLightingImageFilter::~SkLightingImageFilter() {
724 fLight->unref();
725}
726
727SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
728 : INHERITED(buffer)
729{
djsollen@google.com08337772012-06-26 14:33:13 +0000730 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 fSurfaceScale = buffer.readScalar();
732}
733
734void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
735 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000736 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000737 buffer.writeScalar(fSurfaceScale);
738}
739
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000740///////////////////////////////////////////////////////////////////////////////
741
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000742SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
743 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000744 fKD(kd)
745{
746}
747
748SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
749 : INHERITED(buffer)
750{
751 fKD = buffer.readScalar();
752}
753
754void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
755 this->INHERITED::flatten(buffer);
756 buffer.writeScalar(fKD);
757}
758
759bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
760 const SkBitmap& src,
761 const SkMatrix&,
762 SkBitmap* dst,
763 SkIPoint*) {
764 if (src.config() != SkBitmap::kARGB_8888_Config) {
765 return false;
766 }
767 SkAutoLockPixels alp(src);
768 if (!src.getPixels()) {
769 return false;
770 }
771 if (src.width() < 2 || src.height() < 2) {
772 return false;
773 }
774 dst->setConfig(src.config(), src.width(), src.height());
775 dst->allocPixels();
776
777 DiffuseLightingType lightingType(fKD);
778 switch (light()->type()) {
779 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000780 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000781 break;
782 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000783 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784 break;
785 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000786 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000787 break;
788 }
789 return true;
790}
791
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000792bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
793 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000794 if (stage) {
795 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000796 *stage = new GrDiffuseLightingEffect(texture, light(), scale, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000797 }
798 return true;
799}
800
801///////////////////////////////////////////////////////////////////////////////
802
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000803SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
804 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000805 fKS(ks),
806 fShininess(shininess)
807{
808}
809
810SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
811 : INHERITED(buffer)
812{
813 fKS = buffer.readScalar();
814 fShininess = buffer.readScalar();
815}
816
817void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
818 this->INHERITED::flatten(buffer);
819 buffer.writeScalar(fKS);
820 buffer.writeScalar(fShininess);
821}
822
823bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
824 const SkBitmap& src,
825 const SkMatrix&,
826 SkBitmap* dst,
827 SkIPoint*) {
828 if (src.config() != SkBitmap::kARGB_8888_Config) {
829 return false;
830 }
831 SkAutoLockPixels alp(src);
832 if (!src.getPixels()) {
833 return false;
834 }
835 if (src.width() < 2 || src.height() < 2) {
836 return false;
837 }
838 dst->setConfig(src.config(), src.width(), src.height());
839 dst->allocPixels();
840
841 SpecularLightingType lightingType(fKS, fShininess);
842 switch (light()->type()) {
843 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000844 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000845 break;
846 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000847 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848 break;
849 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000850 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851 break;
852 }
853 return true;
854}
855
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000856bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
857 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000858 if (stage) {
859 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000860 *stage = new GrSpecularLightingEffect(texture, light(), scale, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000861 }
862 return true;
863}
864
865///////////////////////////////////////////////////////////////////////////////
866
867class GrGLLightingEffect : public GrGLProgramStage {
868public:
869 GrGLLightingEffect(const GrProgramStageFactory& factory,
870 const GrCustomStage& stage);
871 virtual ~GrGLLightingEffect();
872
873 virtual void setupVariables(GrGLShaderBuilder* state,
874 int stage) SK_OVERRIDE;
875 virtual void emitVS(GrGLShaderBuilder* state,
876 const char* vertexCoords) SK_OVERRIDE;
877 virtual void emitFS(GrGLShaderBuilder* state,
878 const char* outputColor,
879 const char* inputColor,
880 const char* samplerName) SK_OVERRIDE;
881
882 virtual void emitLightFunc(SkString* funcs) = 0;
883
884 static inline StageKey GenKey(const GrCustomStage& s);
885
886 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
887 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000888 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000889 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000890 int stageNum) SK_OVERRIDE;
891
892private:
893 typedef GrGLProgramStage INHERITED;
894
895 const GrGLShaderVar* fImageIncrementVar;
896 GrGLint fImageIncrementLocation;
897 const GrGLShaderVar* fSurfaceScaleVar;
898 GrGLint fSurfaceScaleLocation;
899 GrGLLight* fLight;
900};
901
902///////////////////////////////////////////////////////////////////////////////
903
904class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
905public:
906 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
907 const GrCustomStage& stage);
908 virtual void setupVariables(GrGLShaderBuilder* state,
909 int stage) SK_OVERRIDE;
910 virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
911 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
912 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000913 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000914 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000915 int stageNum) SK_OVERRIDE;
916
917private:
918 typedef GrGLLightingEffect INHERITED;
919
920 const GrGLShaderVar* fKDVar;
921 GrGLint fKDLocation;
922};
923
924///////////////////////////////////////////////////////////////////////////////
925
926class GrGLSpecularLightingEffect : public GrGLLightingEffect {
927public:
928 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
929 const GrCustomStage& stage);
930 virtual void setupVariables(GrGLShaderBuilder* state,
931 int stage) SK_OVERRIDE;
932 virtual void emitLightFunc(SkString* funcs) SK_OVERRIDE;
933 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
934 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000935 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000936 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000937 int stageNum) SK_OVERRIDE;
938
939private:
940 typedef GrGLLightingEffect INHERITED;
941
942 const GrGLShaderVar* fKSVar;
943 GrGLint fKSLocation;
944 const GrGLShaderVar* fShininessVar;
945 GrGLint fShininessLocation;
946};
947
948///////////////////////////////////////////////////////////////////////////////
949
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000950GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
951 : GrSingleTextureEffect(texture)
952 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000953 , fSurfaceScale(surfaceScale) {
954 fLight->ref();
955}
956
957GrLightingEffect::~GrLightingEffect() {
958 fLight->unref();
959}
960
961bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
962 const GrLightingEffect& s =
963 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000964 return INHERITED::isEqual(sBase) &&
965 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000966 fSurfaceScale == s.fSurfaceScale;
967}
968
969///////////////////////////////////////////////////////////////////////////////
970
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000971GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
972 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000973}
974
975const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
976 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
977}
978
979bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
980 const GrDiffuseLightingEffect& s =
981 static_cast<const GrDiffuseLightingEffect&>(sBase);
982 return INHERITED::isEqual(sBase) &&
983 this->kd() == s.kd();
984}
985
986///////////////////////////////////////////////////////////////////////////////
987
988GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
989 const GrCustomStage& stage)
990 : GrGLProgramStage(factory)
991 , fImageIncrementVar(NULL)
992 , fImageIncrementLocation(0)
993 , fSurfaceScaleVar(NULL)
994 , fSurfaceScaleLocation(0) {
995 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
996 fLight = m.light()->createGLLight();
997}
998
999GrGLLightingEffect::~GrGLLightingEffect() {
1000 delete fLight;
1001}
1002
1003void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1004 fImageIncrementVar = &state->addUniform(
1005 GrGLShaderBuilder::kFragment_ShaderType,
1006 kVec2f_GrSLType, "uImageIncrement", stage);
1007 fSurfaceScaleVar = &state->addUniform(
1008 GrGLShaderBuilder::kFragment_ShaderType,
1009 kFloat_GrSLType, "uSurfaceScale", stage);
1010 fLight->setupVariables(state, stage);
1011}
1012
1013void GrGLLightingEffect::emitVS(GrGLShaderBuilder* state,
1014 const char* vertexCoords) {
1015 fLight->emitVS(&state->fVSCode);
1016}
1017
1018void GrGLLightingEffect::initUniforms(const GrGLInterface* gl,
1019 int programID) {
1020 GR_GL_CALL_RET(gl, fSurfaceScaleLocation,
1021 GetUniformLocation(programID,
1022 fSurfaceScaleVar->getName().c_str()));
1023 GR_GL_CALL_RET(gl, fImageIncrementLocation,
1024 GetUniformLocation(programID,
1025 fImageIncrementVar->getName().c_str()));
1026 fLight->initUniforms(gl, programID);
1027}
1028
1029void GrGLLightingEffect::emitFS(GrGLShaderBuilder* state,
1030 const char* outputColor,
1031 const char* inputColor,
1032 const char* samplerName) {
1033 SkString* code = &state->fFSCode;
1034 SkString* funcs = &state->fFSFunctions;
1035 fLight->emitFuncs(funcs);
1036 emitLightFunc(funcs);
1037 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 +00001038 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001039 funcs->appendf("}\n");
1040 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1041 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1042 funcs->appendf("}\n");
1043 funcs->append("\n\
1044vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1045 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1046 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1047 surfaceScale);\n}\n");
1048
1049 code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
1050 code->appendf("\t\tfloat m[9];\n");
1051 int index = 0;
1052 for (int dy = -1; dy <= 1; dy++) {
1053 for (int dx = -1; dx <= 1; dx++) {
1054 SkString texCoords;
1055 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, fImageIncrementVar->getName().c_str());
1056 code->appendf("\t\tm[%d] = ", index++);
1057 state->emitTextureLookup(samplerName, texCoords.c_str());
1058 code->appendf(".a;\n");
1059 }
1060 }
1061 code->appendf("\t\tvec3 surfaceToLight = ");
1062 SkString arg;
1063 arg.appendf("%s * m[4]", fSurfaceScaleVar->getName().c_str());
1064 fLight->emitSurfaceToLight(code, arg.c_str());
1065 code->appendf(";\n");
1066 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, fSurfaceScaleVar->getName().c_str());
1067 fLight->emitLightColor(code, "surfaceToLight");
1068 code->appendf(")%s;\n", state->fModulate.c_str());
1069}
1070
1071GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1072 const GrCustomStage& s) {
1073 return static_cast<const GrLightingEffect&>(s).light()->type();
1074}
1075
1076void GrGLLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001077 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001078 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001079 int stageNum) {
1080 const GrLightingEffect& effect =
1081 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001082 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1083 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
1084 GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture->width(), ySign / texture->height()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001085 GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001086 fLight->setData(gl, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001087}
1088
1089///////////////////////////////////////////////////////////////////////////////
1090
1091///////////////////////////////////////////////////////////////////////////////
1092
1093GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1094 const GrCustomStage& stage)
1095 : INHERITED(factory, stage)
1096 , fKDVar(NULL)
1097 , fKDLocation(0) {
1098}
1099
1100void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1101 INHERITED::setupVariables(state, stage);
1102 fKDVar = &state->addUniform(
1103 GrGLShaderBuilder::kFragment_ShaderType,
1104 kFloat_GrSLType, "uKD", stage);
1105}
1106
1107void GrGLDiffuseLightingEffect::initUniforms(const GrGLInterface* gl,
1108 int programID) {
1109 INHERITED::initUniforms(gl, programID);
1110 GR_GL_CALL_RET(gl, fKDLocation,
1111 GetUniformLocation(programID,
1112 fKDVar->getName().c_str()));
1113}
1114
1115void GrGLDiffuseLightingEffect::emitLightFunc(SkString* funcs) {
1116 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1117 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", fKDVar->getName().c_str());
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001118 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001119 funcs->appendf("}\n");
1120}
1121
1122void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001123 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001124 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001125 int stageNum) {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001126 INHERITED::setData(gl, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001127 const GrDiffuseLightingEffect& effect =
1128 static_cast<const GrDiffuseLightingEffect&>(data);
1129 GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
1130}
1131
1132///////////////////////////////////////////////////////////////////////////////
1133
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001134GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1135 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001136 fKS(ks),
1137 fShininess(shininess) {
1138}
1139
1140const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1141 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1142}
1143
1144bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1145 const GrSpecularLightingEffect& s =
1146 static_cast<const GrSpecularLightingEffect&>(sBase);
1147 return INHERITED::isEqual(sBase) &&
1148 this->ks() == s.ks() &&
1149 this->shininess() == s.shininess();
1150}
1151
1152///////////////////////////////////////////////////////////////////////////////
1153
1154GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1155 const GrCustomStage& stage)
1156 : GrGLLightingEffect(factory, stage)
1157 , fKSVar(NULL)
1158 , fKSLocation(0)
1159 , fShininessVar(NULL)
1160 , fShininessLocation(0) {
1161}
1162
1163void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
1164 INHERITED::setupVariables(state, stage);
1165 fKSVar = &state->addUniform(
1166 GrGLShaderBuilder::kFragment_ShaderType,
1167 kFloat_GrSLType, "uKS", stage);
1168 fShininessVar = &state->addUniform(
1169 GrGLShaderBuilder::kFragment_ShaderType,
1170 kFloat_GrSLType, "uShininess", stage);
1171}
1172
1173void GrGLSpecularLightingEffect::initUniforms(const GrGLInterface* gl,
1174 int programID) {
1175 INHERITED::initUniforms(gl, programID);
1176 GR_GL_CALL_RET(gl, fKSLocation,
1177 GetUniformLocation(programID, fKSVar->getName().c_str()));
1178 GR_GL_CALL_RET(gl, fShininessLocation,
1179 GetUniformLocation(programID, fShininessVar->getName().c_str()));
1180}
1181
1182void GrGLSpecularLightingEffect::emitLightFunc(SkString* funcs) {
1183 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1184 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1185
1186 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n",
1187 fKSVar->getName().c_str(), fShininessVar->getName().c_str());
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001188 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001189 funcs->appendf("}\n");
1190}
1191
1192void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001193 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001194 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001195 int stageNum) {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001196 INHERITED::setData(gl, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001197 const GrSpecularLightingEffect& effect =
1198 static_cast<const GrSpecularLightingEffect&>(data);
1199 GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
1200 GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
1201}
1202
1203///////////////////////////////////////////////////////////////////////////////
1204
1205void GrGLLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
1206 builder->append(fColorVar->getName().c_str());
1207}
1208
1209void GrGLLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1210 fColorVar = &state->addUniform(
1211 GrGLShaderBuilder::kFragment_ShaderType,
1212 kVec3f_GrSLType, "uLightColor", stage);
1213}
1214
1215void GrGLLight::initUniforms(const GrGLInterface* gl, int programID) {
1216 GR_GL_CALL_RET(gl, fColorVarLocation,
1217 GetUniformLocation(programID, fColorVar->getName().c_str()));
1218}
1219
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001220void GrGLLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001221 setUniformPoint3(gl, fColorVarLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
1222}
1223
1224GrGLLight* SkDistantLight::createGLLight() const {
1225 return new GrGLDistantLight();
1226}
1227
1228///////////////////////////////////////////////////////////////////////////////
1229
1230void GrGLDistantLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1231 INHERITED::setupVariables(state, stage);
1232 fDirectionVar = &state->addUniform(
1233 GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1234 "uLightDirection", stage);
1235}
1236
1237void GrGLDistantLight::initUniforms(const GrGLInterface* gl, int programID) {
1238 INHERITED::initUniforms(gl, programID);
1239 GR_GL_CALL_RET(gl, fDirectionLocation,
1240 GetUniformLocation(programID, fDirectionVar->getName().c_str()));
1241}
1242
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001243void GrGLDistantLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1244 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001245 SkASSERT(light->type() == SkLight::kDistant_LightType);
1246 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001247 setUniformNormal3(gl, fDirectionLocation, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248}
1249
1250void GrGLDistantLight::emitSurfaceToLight(SkString* builder,
1251 const char* z) const {
1252 builder->append(fDirectionVar->getName().c_str());
1253}
1254
1255///////////////////////////////////////////////////////////////////////////////
1256
1257void GrGLPointLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1258 INHERITED::setupVariables(state, stage);
1259 fLocationVar = &state->addUniform(
1260 GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1261 "uLightLocation", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001262}
1263
1264void GrGLPointLight::initUniforms(const GrGLInterface* gl, int programID) {
1265 INHERITED::initUniforms(gl, programID);
1266 GR_GL_CALL_RET(gl, fLocationLocation,
1267 GetUniformLocation(programID, fLocationVar->getName().c_str()));
1268}
1269
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001270void GrGLPointLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1271 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001272 SkASSERT(light->type() == SkLight::kPoint_LightType);
1273 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001274 setUniformPoint3FlipY(gl, fLocationLocation, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001275}
1276
1277void GrGLPointLight::emitVS(SkString* builder) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001278}
1279
1280void GrGLPointLight::emitSurfaceToLight(SkString* builder,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001281 const char* z) const {
1282 const char *lName = fLocationVar->getName().c_str();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001283 builder->appendf(
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001284 "normalize(%s - vec3(gl_FragCoord.xy, %s))", lName, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001285}
1286
1287///////////////////////////////////////////////////////////////////////////////
1288
1289void GrGLSpotLight::setupVariables(GrGLShaderBuilder* state, int stage) {
1290 INHERITED::setupVariables(state, stage);
1291 fLocationVar = &state->addUniform(
1292 GrGLShaderBuilder::kFragment_ShaderType,
1293 kVec3f_GrSLType, "uLightLocation", stage);
1294 fExponentVar = &state->addUniform(
1295 GrGLShaderBuilder::kFragment_ShaderType,
1296 kFloat_GrSLType, "uExponent", stage);
1297 fCosInnerConeAngleVar = &state->addUniform(
1298 GrGLShaderBuilder::kFragment_ShaderType,
1299 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1300 fCosOuterConeAngleVar = &state->addUniform(
1301 GrGLShaderBuilder::kFragment_ShaderType,
1302 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1303 fConeScaleVar = &state->addUniform(
1304 GrGLShaderBuilder::kFragment_ShaderType,
1305 kFloat_GrSLType, "uConeScale", stage);
1306 fSVar = &state->addUniform(
1307 GrGLShaderBuilder::kFragment_ShaderType,
1308 kVec3f_GrSLType, "uS", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001309}
1310
1311void GrGLSpotLight::initUniforms(const GrGLInterface* gl, int programID) {
1312 INHERITED::initUniforms(gl, programID);
1313 GR_GL_CALL_RET(gl, fLocationLocation,
1314 GetUniformLocation(programID, fLocationVar->getName().c_str()));
1315 GR_GL_CALL_RET(gl, fExponentLocation,
1316 GetUniformLocation(programID, fExponentVar->getName().c_str()));
1317 GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation,
1318 GetUniformLocation(programID, fCosInnerConeAngleVar->getName().c_str()));
1319 GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation,
1320 GetUniformLocation(programID, fCosOuterConeAngleVar->getName().c_str()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001321 GR_GL_CALL_RET(gl, fConeScaleLocation,
1322 GetUniformLocation(programID, fConeScaleVar->getName().c_str()));
1323 GR_GL_CALL_RET(gl, fSLocation,
1324 GetUniformLocation(programID, fSVar->getName().c_str()));
1325}
1326
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001327void GrGLSpotLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1328 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001329 SkASSERT(light->type() == SkLight::kSpot_LightType);
1330 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001331 setUniformPoint3FlipY(gl, fLocationLocation, spotLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001332 GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
1333 GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
1334 GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
1335 GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001336 setUniformNormal3(gl, fSLocation, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001337}
1338
1339void GrGLSpotLight::emitVS(SkString* builder) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001340}
1341
1342void GrGLSpotLight::emitFuncs(SkString* builder) const {
1343 builder->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1344 builder->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", fSVar->getName().c_str());
1345 builder->appendf("\tif (cosAngle < %s) {\n", fCosOuterConeAngleVar->getName().c_str());
1346 builder->appendf("\t\treturn vec3(0);\n");
1347 builder->appendf("\t}\n");
1348 builder->appendf("\tfloat scale = pow(cosAngle, %s);\n", fExponentVar->getName().c_str());
1349 builder->appendf("\tif (cosAngle < %s) {\n", fCosInnerConeAngleVar->getName().c_str());
1350 builder->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", fColorVar->getName().c_str(), fCosOuterConeAngleVar->getName().c_str(), fConeScaleVar->getName().c_str());
1351 builder->appendf("\t}\n");
1352 builder->appendf("\treturn %s;\n", fColorVar->getName().c_str());
1353 builder->appendf("}\n");
1354}
1355
1356void GrGLSpotLight::emitSurfaceToLight(SkString* builder, const char* z) const {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001357 builder->appendf(
1358 "normalize(%s - vec3(gl_FragCoord.xy, %s))", fLocationVar->getName().c_str(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001359}
1360
1361void GrGLSpotLight::emitLightColor(SkString* builder, const char *surfaceToLight) const {
1362 builder->appendf("lightColor(%s)", surfaceToLight);
1363}
1364
djsollen@google.com08337772012-06-26 14:33:13 +00001365SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1366 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1367 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1368 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1369 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1370 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1371SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END