blob: 1e15155fc5339e3fc42bf93a9c2eb13cf15d5377 [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
bsalomon@google.com032b2212012-07-16 13:36:18 +000021// For brevity, and these definitions are likely to move to a different class soon.
22typedef GrGLShaderBuilder::UniformHandle UniformHandle;
23static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
24
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000025// FIXME: Eventually, this should be implemented properly, and put in
26// SkScalar.h.
27#define SkScalarPow(x, y) SkFloatToScalar(powf(SkScalarToFloat(x), SkScalarToFloat(y)))
28namespace {
29
30const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
31const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
32const SkScalar gOneHalf = SkFloatToScalar(0.5f);
33const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
34
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000035void setUniformPoint3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
36 float x = SkScalarToFloat(point.fX);
37 float y = SkScalarToFloat(point.fY);
38 float z = SkScalarToFloat(point.fZ);
39 GR_GL_CALL(gl, Uniform3f(location, x, y, z));
40}
41
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000042void setUniformNormal3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
43 setUniformPoint3(gl, location, SkPoint3(point.fX, -point.fY, point.fZ));
44}
45
46void setUniformPoint3FlipY(const GrGLInterface* gl, GrGLint location, const SkPoint3& point, int height) {
47 setUniformPoint3(gl, location, SkPoint3(point.fX, height-point.fY, point.fZ));
48}
49
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000050// Shift matrix components to the left, as we advance pixels to the right.
51inline void shiftMatrixLeft(int m[9]) {
52 m[0] = m[1];
53 m[3] = m[4];
54 m[6] = m[7];
55 m[1] = m[2];
56 m[4] = m[5];
57 m[7] = m[8];
58}
59
60class DiffuseLightingType {
61public:
62 DiffuseLightingType(SkScalar kd)
63 : fKD(kd) {}
64 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
65 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
66 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
67 SkPoint3 color(lightColor * colorScale);
68 return SkPackARGB32(255,
69 SkScalarFloorToInt(color.fX),
70 SkScalarFloorToInt(color.fY),
71 SkScalarFloorToInt(color.fZ));
72 }
73private:
74 SkScalar fKD;
75};
76
77class SpecularLightingType {
78public:
79 SpecularLightingType(SkScalar ks, SkScalar shininess)
80 : fKS(ks), fShininess(shininess) {}
81 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
82 SkPoint3 halfDir(surfaceTolight);
83 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
84 halfDir.normalize();
85 SkScalar colorScale = SkScalarMul(fKS,
86 SkScalarPow(normal.dot(halfDir), fShininess));
87 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
88 SkPoint3 color(lightColor * colorScale);
89 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
90 SkScalarFloorToInt(color.fX),
91 SkScalarFloorToInt(color.fY),
92 SkScalarFloorToInt(color.fZ));
93 }
94private:
95 SkScalar fKS;
96 SkScalar fShininess;
97};
98
99inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
100 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
101}
102
103inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
104 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
105 SkScalarMul(-y, surfaceScale),
106 SK_Scalar1);
107 vector.normalize();
108 return vector;
109}
110
111inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
112 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
113 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
114 surfaceScale);
115}
116
117inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
118 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
119 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
120 surfaceScale);
121}
122
123inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
124 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
125 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
126 surfaceScale);
127}
128
129inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
130 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
131 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
132 surfaceScale);
133}
134
135
136inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
137 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
138 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
139 surfaceScale);
140}
141
142inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
143 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
144 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
145 surfaceScale);
146}
147
148inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
149 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
150 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
151 surfaceScale);
152}
153
154inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
155 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
156 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
157 surfaceScale);
158}
159
160inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
161 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
162 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
163 surfaceScale);
164}
165
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000166template <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 +0000167 const LightType* l = static_cast<const LightType*>(light);
168 int y = 0;
169 {
170 const SkPMColor* row1 = src.getAddr32(0, 0);
171 const SkPMColor* row2 = src.getAddr32(0, 1);
172 SkPMColor* dptr = dst->getAddr32(0, 0);
173 int m[9];
174 int x = 0;
175 m[4] = SkGetPackedA32(*row1++);
176 m[5] = SkGetPackedA32(*row1++);
177 m[7] = SkGetPackedA32(*row2++);
178 m[8] = SkGetPackedA32(*row2++);
179 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000180 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000181 for (x = 1; x < src.width() - 1; ++x)
182 {
183 shiftMatrixLeft(m);
184 m[5] = SkGetPackedA32(*row1++);
185 m[8] = SkGetPackedA32(*row2++);
186 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000187 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 }
189 shiftMatrixLeft(m);
190 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000191 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000192 }
193
194 for (++y; y < src.height() - 1; ++y) {
195 const SkPMColor* row0 = src.getAddr32(0, y - 1);
196 const SkPMColor* row1 = src.getAddr32(0, y);
197 const SkPMColor* row2 = src.getAddr32(0, y + 1);
198 SkPMColor* dptr = dst->getAddr32(0, y);
199 int m[9];
200 int x = 0;
201 m[1] = SkGetPackedA32(*row0++);
202 m[2] = SkGetPackedA32(*row0++);
203 m[4] = SkGetPackedA32(*row1++);
204 m[5] = SkGetPackedA32(*row1++);
205 m[7] = SkGetPackedA32(*row2++);
206 m[8] = SkGetPackedA32(*row2++);
207 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000208 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000209 for (x = 1; x < src.width() - 1; ++x) {
210 shiftMatrixLeft(m);
211 m[2] = SkGetPackedA32(*row0++);
212 m[5] = SkGetPackedA32(*row1++);
213 m[8] = SkGetPackedA32(*row2++);
214 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000215 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 }
217 shiftMatrixLeft(m);
218 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000219 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000220 }
221
222 {
223 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
224 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
225 int x = 0;
226 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
227 int m[9];
228 m[1] = SkGetPackedA32(*row0++);
229 m[2] = SkGetPackedA32(*row0++);
230 m[4] = SkGetPackedA32(*row1++);
231 m[5] = SkGetPackedA32(*row1++);
232 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000233 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000234 for (x = 1; x < src.width() - 1; ++x)
235 {
236 shiftMatrixLeft(m);
237 m[2] = SkGetPackedA32(*row0++);
238 m[5] = SkGetPackedA32(*row1++);
239 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000240 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000241 }
242 shiftMatrixLeft(m);
243 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000244 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000245 }
246}
247
248SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
249 SkPoint3 point;
250 point.fX = buffer.readScalar();
251 point.fY = buffer.readScalar();
252 point.fZ = buffer.readScalar();
253 return point;
254};
255
256void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
257 buffer.writeScalar(point.fX);
258 buffer.writeScalar(point.fY);
259 buffer.writeScalar(point.fZ);
260};
261
262class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
263public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000264 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000265 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
266
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000267 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000268 SkScalar kd() const { return fKD; }
269
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270protected:
271 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
272 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
273 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
274 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
275
276
277private:
278 typedef SkLightingImageFilter INHERITED;
279 SkScalar fKD;
280};
281
282class SkSpecularLightingImageFilter : public SkLightingImageFilter {
283public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000284 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000285 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
286
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000287 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000288 SkScalar ks() const { return fKS; }
289 SkScalar shininess() const { return fShininess; }
290
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000291protected:
292 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
293 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
294 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
295 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
296
297private:
298 typedef SkLightingImageFilter INHERITED;
299 SkScalar fKS;
300 SkScalar fShininess;
301};
302
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000303
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000304class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000305public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000306 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000307 virtual ~GrLightingEffect();
308
309 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
310
311 const SkLight* light() const { return fLight; }
312 SkScalar surfaceScale() const { return fSurfaceScale; }
313private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000314 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000315 const SkLight* fLight;
316 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000317};
318
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000319class GrDiffuseLightingEffect : public GrLightingEffect {
320public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000321 GrDiffuseLightingEffect(GrTexture* texture,
322 const SkLight* light,
323 SkScalar surfaceScale,
324 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000325
326 static const char* Name() { return "DiffuseLighting"; }
327
328 typedef GrGLDiffuseLightingEffect GLProgramStage;
329
330 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
331 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
332 SkScalar kd() const { return fKD; }
333private:
334 typedef GrLightingEffect INHERITED;
335 SkScalar fKD;
336};
337
338class GrSpecularLightingEffect : public GrLightingEffect {
339public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000340 GrSpecularLightingEffect(GrTexture* texture,
341 const SkLight* light,
342 SkScalar surfaceScale,
343 SkScalar ks,
344 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000345
346 static const char* Name() { return "SpecularLighting"; }
347
348 typedef GrGLSpecularLightingEffect GLProgramStage;
349
350 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
351 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
352 SkScalar ks() const { return fKS; }
353 SkScalar shininess() const { return fShininess; }
354
355private:
356 typedef GrLightingEffect INHERITED;
357 SkScalar fKS;
358 SkScalar fShininess;
359};
360
361///////////////////////////////////////////////////////////////////////////////
362
363class GrGLLight {
364public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000365 virtual ~GrGLLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000366 virtual void setupVariables(GrGLShaderBuilder* builder, int stage);
367 virtual void emitVS(SkString* out) const {}
368 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
369 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
370 SkString* out,
371 const char* z) const = 0;
372 virtual void emitLightColor(const GrGLShaderBuilder*,
373 SkString* out,
374 const char *surfaceToLight) const;
375 virtual void initUniforms(const GrGLShaderBuilder*, const GrGLInterface* gl, int programID);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000376 virtual void setData(const GrGLInterface*, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000377
378private:
379 typedef SkRefCnt INHERITED;
380
381protected:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000382 UniformHandle fColorUni;
383 int fColorLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000384};
385
386///////////////////////////////////////////////////////////////////////////////
387
388class GrGLDistantLight : public GrGLLight {
389public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000390 virtual ~GrGLDistantLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000391 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
392 virtual void initUniforms(const GrGLShaderBuilder*,
393 const GrGLInterface* gl,
394 int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000395 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000396 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
397 SkString* out,
398 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000399
400private:
401 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000402 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000403 int fDirectionLocation;
404};
405
406///////////////////////////////////////////////////////////////////////////////
407
408class GrGLPointLight : public GrGLLight {
409public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000410 virtual ~GrGLPointLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000411 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
412 virtual void initUniforms(const GrGLShaderBuilder*,
413 const GrGLInterface*,
414 int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000415 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000416 virtual void emitVS(SkString* out) const SK_OVERRIDE;
417 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
418 SkString* out,
419 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000420
421private:
422 typedef GrGLLight INHERITED;
423 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000424 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000425 int fLocationLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000426};
427
428///////////////////////////////////////////////////////////////////////////////
429
430class GrGLSpotLight : public GrGLLight {
431public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000432 virtual ~GrGLSpotLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000433 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
434 virtual void initUniforms(const GrGLShaderBuilder* builder,
435 const GrGLInterface* gl,
436 int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000437 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000438 virtual void emitVS(SkString* out) const SK_OVERRIDE;
439 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
440 virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
441 SkString* out,
442 const char* z) const SK_OVERRIDE;
443 virtual void emitLightColor(const GrGLShaderBuilder*,
444 SkString* out,
445 const char *surfaceToLight) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000446
447private:
448 typedef GrGLLight INHERITED;
449
bsalomon@google.com032b2212012-07-16 13:36:18 +0000450 UniformHandle fLocationUni;
451 int fLocationLocation;
452 UniformHandle fExponentUni;
453 int fExponentLocation;
454 UniformHandle fCosOuterConeAngleUni;
455 int fCosOuterConeAngleLocation;
456 UniformHandle fCosInnerConeAngleUni;
457 int fCosInnerConeAngleLocation;
458 UniformHandle fConeScaleUni;
459 int fConeScaleLocation;
460 UniformHandle fSUni;
461 int fSLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000462};
463
464};
465
466///////////////////////////////////////////////////////////////////////////////
467
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000468class SkLight : public SkFlattenable {
469public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000470 SK_DECLARE_INST_COUNT(SkLight)
471
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000472 enum LightType {
473 kDistant_LightType,
474 kPoint_LightType,
475 kSpot_LightType,
476 };
477 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000478 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000479 virtual GrGLLight* createGLLight() const = 0;
480 virtual bool isEqual(const SkLight& other) const {
481 return fColor == other.fColor;
482 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483
djsollen@google.com08337772012-06-26 14:33:13 +0000484protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000485 SkLight(SkColor color)
486 : fColor(SkIntToScalar(SkColorGetR(color)),
487 SkIntToScalar(SkColorGetG(color)),
488 SkIntToScalar(SkColorGetB(color))) {}
489 SkLight(SkFlattenableReadBuffer& buffer)
490 : INHERITED(buffer) {
491 fColor = readPoint3(buffer);
492 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000493 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000494 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000495 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000496 }
djsollen@google.com08337772012-06-26 14:33:13 +0000497
498private:
499 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000500 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501};
502
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000503SK_DEFINE_INST_COUNT(SkLight)
504
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000505///////////////////////////////////////////////////////////////////////////////
506
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000507class SkDistantLight : public SkLight {
508public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000509 SkDistantLight(const SkPoint3& direction, SkColor color)
510 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000511 }
djsollen@google.com08337772012-06-26 14:33:13 +0000512
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000513 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
514 return fDirection;
515 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000516 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000517 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518 const SkPoint3& direction() const { return fDirection; }
519 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000520 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
521 if (other.type() != kDistant_LightType) {
522 return false;
523 }
524
525 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
526 return INHERITED::isEqual(other) &&
527 fDirection == o.fDirection;
528 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000529
530 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
531
djsollen@google.com08337772012-06-26 14:33:13 +0000532protected:
533 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
534 fDirection = readPoint3(buffer);
535 }
536 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
537 INHERITED::flatten(buffer);
538 writePoint3(fDirection, buffer);
539 }
540
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000541private:
djsollen@google.com08337772012-06-26 14:33:13 +0000542 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000543 SkPoint3 fDirection;
544};
545
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000546///////////////////////////////////////////////////////////////////////////////
547
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000548class SkPointLight : public SkLight {
549public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000550 SkPointLight(const SkPoint3& location, SkColor color)
551 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000552
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000553 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
554 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
555 fLocation.fY - SkIntToScalar(y),
556 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
557 direction.normalize();
558 return direction;
559 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000560 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000561 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000562 const SkPoint3& location() const { return fLocation; }
563 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
564 return new GrGLPointLight();
565 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000566 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567 if (other.type() != kPoint_LightType) {
568 return false;
569 }
570 const SkPointLight& o = static_cast<const SkPointLight&>(other);
571 return INHERITED::isEqual(other) &&
572 fLocation == o.fLocation;
573 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000574
575 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
576
djsollen@google.com08337772012-06-26 14:33:13 +0000577protected:
578 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
579 fLocation = readPoint3(buffer);
580 }
581 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
582 INHERITED::flatten(buffer);
583 writePoint3(fLocation, buffer);
584 }
585
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586private:
djsollen@google.com08337772012-06-26 14:33:13 +0000587 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000588 SkPoint3 fLocation;
589};
590
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000591///////////////////////////////////////////////////////////////////////////////
592
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000593class SkSpotLight : public SkLight {
594public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000595 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
596 : INHERITED(color),
597 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000598 fTarget(target),
599 fSpecularExponent(specularExponent)
600 {
601 fS = target - location;
602 fS.normalize();
603 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
604 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
605 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
606 fConeScale = SkScalarInvert(antiAliasThreshold);
607 }
djsollen@google.com08337772012-06-26 14:33:13 +0000608
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000609 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
610 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
611 fLocation.fY - SkIntToScalar(y),
612 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
613 direction.normalize();
614 return direction;
615 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000616 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000617 SkScalar cosAngle = -surfaceToLight.dot(fS);
618 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000619 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000620 }
621 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
622 if (cosAngle < fCosInnerConeAngle) {
623 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000624 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000625 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000626 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000627 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
629 return new GrGLSpotLight();
630 }
djsollen@google.com08337772012-06-26 14:33:13 +0000631 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632 const SkPoint3& location() const { return fLocation; }
633 const SkPoint3& target() const { return fTarget; }
634 SkScalar specularExponent() const { return fSpecularExponent; }
635 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
636 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
637 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000638 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000639
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000640 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
641
djsollen@google.com08337772012-06-26 14:33:13 +0000642protected:
643 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
644 fLocation = readPoint3(buffer);
645 fTarget = readPoint3(buffer);
646 fSpecularExponent = buffer.readScalar();
647 fCosOuterConeAngle = buffer.readScalar();
648 fCosInnerConeAngle = buffer.readScalar();
649 fConeScale = buffer.readScalar();
650 fS = readPoint3(buffer);
651 }
652 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
653 INHERITED::flatten(buffer);
654 writePoint3(fLocation, buffer);
655 writePoint3(fTarget, buffer);
656 buffer.writeScalar(fSpecularExponent);
657 buffer.writeScalar(fCosOuterConeAngle);
658 buffer.writeScalar(fCosInnerConeAngle);
659 buffer.writeScalar(fConeScale);
660 writePoint3(fS, buffer);
661 }
662
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000663 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000664 if (other.type() != kSpot_LightType) {
665 return false;
666 }
667
668 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
669 return INHERITED::isEqual(other) &&
670 fLocation == o.fLocation &&
671 fTarget == o.fTarget &&
672 fSpecularExponent == o.fSpecularExponent &&
673 fCosOuterConeAngle == o.fCosOuterConeAngle;
674 }
675
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000676private:
djsollen@google.com08337772012-06-26 14:33:13 +0000677 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000678 SkPoint3 fLocation;
679 SkPoint3 fTarget;
680 SkScalar fSpecularExponent;
681 SkScalar fCosOuterConeAngle;
682 SkScalar fCosInnerConeAngle;
683 SkScalar fConeScale;
684 SkPoint3 fS;
685};
686
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000687///////////////////////////////////////////////////////////////////////////////
688
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000689SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000690 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
692{
693 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000694 // our caller knows that we take ownership of the light, so we don't
695 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696}
697
698SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000699 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000700 SkScalar kd) {
701 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000702 new SkDistantLight(direction, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703}
704
705SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000706 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000707 SkScalar kd) {
708 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000709 new SkPointLight(location, lightColor), surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000710}
711
712SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000713 const SkPoint3& location, const SkPoint3& target,
714 SkScalar specularExponent, SkScalar cutoffAngle,
715 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000716 return new SkDiffuseLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000717 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
718 surfaceScale, kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000719}
720
721SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000722 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000723 SkScalar ks, SkScalar shininess) {
724 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000725 new SkDistantLight(direction, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000726}
727
728SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000729 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
730 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000732 new SkPointLight(location, lightColor), surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733}
734
735SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000736 const SkPoint3& location, const SkPoint3& target,
737 SkScalar specularExponent, SkScalar cutoffAngle,
738 SkColor lightColor, SkScalar surfaceScale,
739 SkScalar ks, SkScalar shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000740 return new SkSpecularLightingImageFilter(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor),
742 surfaceScale, ks, shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743}
744
745SkLightingImageFilter::~SkLightingImageFilter() {
746 fLight->unref();
747}
748
749SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
750 : INHERITED(buffer)
751{
djsollen@google.com08337772012-06-26 14:33:13 +0000752 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000753 fSurfaceScale = buffer.readScalar();
754}
755
756void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
757 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000758 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000759 buffer.writeScalar(fSurfaceScale);
760}
761
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000762///////////////////////////////////////////////////////////////////////////////
763
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000764SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
765 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000766 fKD(kd)
767{
768}
769
770SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
771 : INHERITED(buffer)
772{
773 fKD = buffer.readScalar();
774}
775
776void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
777 this->INHERITED::flatten(buffer);
778 buffer.writeScalar(fKD);
779}
780
781bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
782 const SkBitmap& src,
783 const SkMatrix&,
784 SkBitmap* dst,
785 SkIPoint*) {
786 if (src.config() != SkBitmap::kARGB_8888_Config) {
787 return false;
788 }
789 SkAutoLockPixels alp(src);
790 if (!src.getPixels()) {
791 return false;
792 }
793 if (src.width() < 2 || src.height() < 2) {
794 return false;
795 }
796 dst->setConfig(src.config(), src.width(), src.height());
797 dst->allocPixels();
798
799 DiffuseLightingType lightingType(fKD);
800 switch (light()->type()) {
801 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000802 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000803 break;
804 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000805 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000806 break;
807 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000808 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000809 break;
810 }
811 return true;
812}
813
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000814bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
815 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000816 if (stage) {
817 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000818 *stage = new GrDiffuseLightingEffect(texture, light(), scale, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000819 }
820 return true;
821}
822
823///////////////////////////////////////////////////////////////////////////////
824
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000825SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
826 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000827 fKS(ks),
828 fShininess(shininess)
829{
830}
831
832SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
833 : INHERITED(buffer)
834{
835 fKS = buffer.readScalar();
836 fShininess = buffer.readScalar();
837}
838
839void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
840 this->INHERITED::flatten(buffer);
841 buffer.writeScalar(fKS);
842 buffer.writeScalar(fShininess);
843}
844
845bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
846 const SkBitmap& src,
847 const SkMatrix&,
848 SkBitmap* dst,
849 SkIPoint*) {
850 if (src.config() != SkBitmap::kARGB_8888_Config) {
851 return false;
852 }
853 SkAutoLockPixels alp(src);
854 if (!src.getPixels()) {
855 return false;
856 }
857 if (src.width() < 2 || src.height() < 2) {
858 return false;
859 }
860 dst->setConfig(src.config(), src.width(), src.height());
861 dst->allocPixels();
862
863 SpecularLightingType lightingType(fKS, fShininess);
864 switch (light()->type()) {
865 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000866 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867 break;
868 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000869 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000870 break;
871 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000872 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000873 break;
874 }
875 return true;
876}
877
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000878bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
879 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000880 if (stage) {
881 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000882 *stage = new GrSpecularLightingEffect(texture, light(), scale, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000883 }
884 return true;
885}
886
887///////////////////////////////////////////////////////////////////////////////
888
889class GrGLLightingEffect : public GrGLProgramStage {
890public:
891 GrGLLightingEffect(const GrProgramStageFactory& factory,
892 const GrCustomStage& stage);
893 virtual ~GrGLLightingEffect();
894
bsalomon@google.com032b2212012-07-16 13:36:18 +0000895 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000896 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000897 virtual void emitVS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000898 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000899 virtual void emitFS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000900 const char* outputColor,
901 const char* inputColor,
902 const char* samplerName) SK_OVERRIDE;
903
bsalomon@google.com032b2212012-07-16 13:36:18 +0000904 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000905
906 static inline StageKey GenKey(const GrCustomStage& s);
907
bsalomon@google.com032b2212012-07-16 13:36:18 +0000908 virtual void initUniforms(const GrGLShaderBuilder* builder,
909 const GrGLInterface*,
910 int programID) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000911 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000912 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000913 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000914 int stageNum) SK_OVERRIDE;
915
916private:
917 typedef GrGLProgramStage INHERITED;
918
bsalomon@google.com032b2212012-07-16 13:36:18 +0000919 UniformHandle fImageIncrementUni;
920 GrGLint fImageIncrementLocation;
921 UniformHandle fSurfaceScaleUni;
922 GrGLint fSurfaceScaleLocation;
923 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000924};
925
926///////////////////////////////////////////////////////////////////////////////
927
928class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
929public:
930 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
931 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000932 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000933 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000934 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
935 virtual void initUniforms(const GrGLShaderBuilder*,
936 const GrGLInterface*,
937 int programID) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000938 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000939 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000940 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000941 int stageNum) SK_OVERRIDE;
942
943private:
944 typedef GrGLLightingEffect INHERITED;
945
bsalomon@google.com032b2212012-07-16 13:36:18 +0000946 UniformHandle fKDUni;
947 GrGLint fKDLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000948};
949
950///////////////////////////////////////////////////////////////////////////////
951
952class GrGLSpecularLightingEffect : public GrGLLightingEffect {
953public:
954 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
955 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000956 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000957 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000958 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
959 virtual void initUniforms(const GrGLShaderBuilder*,
960 const GrGLInterface*,
961 int programID) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000962 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000963 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000964 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000965 int stageNum) SK_OVERRIDE;
966
967private:
968 typedef GrGLLightingEffect INHERITED;
969
bsalomon@google.com032b2212012-07-16 13:36:18 +0000970 UniformHandle fKSUni;
971 GrGLint fKSLocation;
972 UniformHandle fShininessUni;
973 GrGLint fShininessLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000974};
975
976///////////////////////////////////////////////////////////////////////////////
977
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000978GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
979 : GrSingleTextureEffect(texture)
980 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000981 , fSurfaceScale(surfaceScale) {
982 fLight->ref();
983}
984
985GrLightingEffect::~GrLightingEffect() {
986 fLight->unref();
987}
988
989bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
990 const GrLightingEffect& s =
991 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000992 return INHERITED::isEqual(sBase) &&
993 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000994 fSurfaceScale == s.fSurfaceScale;
995}
996
997///////////////////////////////////////////////////////////////////////////////
998
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000999GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1000 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001001}
1002
1003const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
1004 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
1005}
1006
1007bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
1008 const GrDiffuseLightingEffect& s =
1009 static_cast<const GrDiffuseLightingEffect&>(sBase);
1010 return INHERITED::isEqual(sBase) &&
1011 this->kd() == s.kd();
1012}
1013
1014///////////////////////////////////////////////////////////////////////////////
1015
1016GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
1017 const GrCustomStage& stage)
1018 : GrGLProgramStage(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001019 , fImageIncrementUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001020 , fImageIncrementLocation(0)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001021 , fSurfaceScaleUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001022 , fSurfaceScaleLocation(0) {
1023 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
1024 fLight = m.light()->createGLLight();
1025}
1026
1027GrGLLightingEffect::~GrGLLightingEffect() {
1028 delete fLight;
1029}
1030
bsalomon@google.com032b2212012-07-16 13:36:18 +00001031void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1032 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1033 kVec2f_GrSLType,
1034 "uImageIncrement", stage);
1035 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1036 kFloat_GrSLType,
1037 "uSurfaceScale", stage);
1038 fLight->setupVariables(builder, stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001039}
1040
bsalomon@google.com032b2212012-07-16 13:36:18 +00001041void GrGLLightingEffect::emitVS(GrGLShaderBuilder* builder,
1042 const char* vertexCoords) {
1043 fLight->emitVS(&builder->fVSCode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001044}
1045
bsalomon@google.com032b2212012-07-16 13:36:18 +00001046void GrGLLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
1047 const GrGLInterface* gl,
1048 int programID) {
1049 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1050 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1051
1052 GR_GL_CALL_RET(gl, fSurfaceScaleLocation, GetUniformLocation(programID, surfScale));
1053 GR_GL_CALL_RET(gl, fImageIncrementLocation, GetUniformLocation(programID, imgInc));
1054 fLight->initUniforms(builder, gl, programID);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001055}
1056
bsalomon@google.com032b2212012-07-16 13:36:18 +00001057void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
1058 const char* outputColor,
1059 const char* inputColor,
1060 const char* samplerName) {
1061 SkString* code = &builder->fFSCode;
1062 SkString* funcs = &builder->fFSFunctions;
1063 fLight->emitFuncs(builder, funcs);
1064 this->emitLightFunc(builder, funcs);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001065 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 +00001066 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001067 funcs->appendf("}\n");
1068 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1069 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1070 funcs->appendf("}\n");
1071 funcs->append("\n\
1072vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1073 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1074 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1075 surfaceScale);\n}\n");
1076
bsalomon@google.com032b2212012-07-16 13:36:18 +00001077 code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001078 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001079
1080 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1081 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1082
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001083 int index = 0;
1084 for (int dy = -1; dy <= 1; dy++) {
1085 for (int dx = -1; dx <= 1; dx++) {
1086 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001087 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001088 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001089 builder->emitTextureLookup(samplerName, texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001090 code->appendf(".a;\n");
1091 }
1092 }
1093 code->appendf("\t\tvec3 surfaceToLight = ");
1094 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001095 arg.appendf("%s * m[4]", surfScale);
1096 fLight->emitSurfaceToLight(builder, code, arg.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001097 code->appendf(";\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001098 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
1099 fLight->emitLightColor(builder, code, "surfaceToLight");
1100 code->appendf(")%s;\n", builder->fModulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001101}
1102
1103GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1104 const GrCustomStage& s) {
1105 return static_cast<const GrLightingEffect&>(s).light()->type();
1106}
1107
1108void GrGLLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001109 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001110 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001111 int stageNum) {
1112 const GrLightingEffect& effect =
1113 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001114 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1115 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
1116 GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture->width(), ySign / texture->height()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001117 GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001118 fLight->setData(gl, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001119}
1120
1121///////////////////////////////////////////////////////////////////////////////
1122
1123///////////////////////////////////////////////////////////////////////////////
1124
1125GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1126 const GrCustomStage& stage)
1127 : INHERITED(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001128 , fKDUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001129 , fKDLocation(0) {
1130}
1131
bsalomon@google.com032b2212012-07-16 13:36:18 +00001132void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1133 INHERITED::setupVariables(builder, stage);
1134 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "uKD",
1135 stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001136}
1137
bsalomon@google.com032b2212012-07-16 13:36:18 +00001138void GrGLDiffuseLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
1139 const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001140 int programID) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001141 INHERITED::initUniforms(builder, gl, programID);
1142 const char* kd = builder->getUniformCStr(fKDUni);
1143 GR_GL_CALL_RET(gl, fKDLocation, GetUniformLocation(programID, kd));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001144}
1145
bsalomon@google.com032b2212012-07-16 13:36:18 +00001146void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
1147 const char* kd = builder->getUniformCStr(fKDUni);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001148 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001149 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001150 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001151 funcs->appendf("}\n");
1152}
1153
1154void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001155 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001156 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001157 int stageNum) {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001158 INHERITED::setData(gl, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001159 const GrDiffuseLightingEffect& effect =
1160 static_cast<const GrDiffuseLightingEffect&>(data);
1161 GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
1162}
1163
1164///////////////////////////////////////////////////////////////////////////////
1165
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001166GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1167 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001168 fKS(ks),
1169 fShininess(shininess) {
1170}
1171
1172const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1173 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1174}
1175
1176bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1177 const GrSpecularLightingEffect& s =
1178 static_cast<const GrSpecularLightingEffect&>(sBase);
1179 return INHERITED::isEqual(sBase) &&
1180 this->ks() == s.ks() &&
1181 this->shininess() == s.shininess();
1182}
1183
1184///////////////////////////////////////////////////////////////////////////////
1185
1186GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1187 const GrCustomStage& stage)
1188 : GrGLLightingEffect(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001189 , fKSUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001190 , fKSLocation(0)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001191 , fShininessUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001192 , fShininessLocation(0) {
1193}
1194
bsalomon@google.com032b2212012-07-16 13:36:18 +00001195void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1196 INHERITED::setupVariables(builder, stage);
1197 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1198 kFloat_GrSLType, "uKS", stage);
1199 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1200 kFloat_GrSLType, "uShininess", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001201}
1202
bsalomon@google.com032b2212012-07-16 13:36:18 +00001203void GrGLSpecularLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
1204 const GrGLInterface* gl,
1205 int programID) {
1206 INHERITED::initUniforms(builder, gl, programID);
1207 const char* ks = builder->getUniformCStr(fKSUni);
1208 const char* shininess = builder->getUniformCStr(fShininessUni);
1209 GR_GL_CALL_RET(gl, fKSLocation, GetUniformLocation(programID, ks));
1210 GR_GL_CALL_RET(gl, fShininessLocation, GetUniformLocation(programID, shininess));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001211}
1212
bsalomon@google.com032b2212012-07-16 13:36:18 +00001213void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001214 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1215 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1216
bsalomon@google.com032b2212012-07-16 13:36:18 +00001217 const char* ks = builder->getUniformCStr(fKSUni);
1218 const char* shininess = builder->getUniformCStr(fShininessUni);
1219 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001220 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001221 funcs->appendf("}\n");
1222}
1223
1224void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001225 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001226 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001227 int stageNum) {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001228 INHERITED::setData(gl, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229 const GrSpecularLightingEffect& effect =
1230 static_cast<const GrSpecularLightingEffect&>(data);
1231 GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
1232 GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
1233}
1234
1235///////////////////////////////////////////////////////////////////////////////
1236
bsalomon@google.com032b2212012-07-16 13:36:18 +00001237void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
1238 SkString* out,
1239 const char *surfaceToLight) const {
1240 const char* color = builder->getUniformCStr(fColorUni);
1241 out->append(color);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001242}
1243
bsalomon@google.com032b2212012-07-16 13:36:18 +00001244void GrGLLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1245 const GrGLShaderVar& colorVar = builder->getUniformVariable(fColorUni);
1246 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1247 kVec3f_GrSLType, "uLightColor", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248}
1249
bsalomon@google.com032b2212012-07-16 13:36:18 +00001250void GrGLLight::initUniforms(const GrGLShaderBuilder* builder,
1251 const GrGLInterface* gl,
1252 int programID) {
1253 const char* color = builder->getUniformCStr(fColorUni);
1254 GR_GL_CALL_RET(gl, fColorLocation, GetUniformLocation(programID, color));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001255}
1256
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001257void GrGLLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001258 setUniformPoint3(gl, fColorLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001259}
1260
1261GrGLLight* SkDistantLight::createGLLight() const {
1262 return new GrGLDistantLight();
1263}
1264
1265///////////////////////////////////////////////////////////////////////////////
1266
bsalomon@google.com032b2212012-07-16 13:36:18 +00001267void GrGLDistantLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1268 INHERITED::setupVariables(builder, stage);
1269 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1270 "uLightDirection", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001271}
1272
bsalomon@google.com032b2212012-07-16 13:36:18 +00001273void GrGLDistantLight::initUniforms(const GrGLShaderBuilder* builder,
1274 const GrGLInterface* gl,
1275 int programID) {
1276 INHERITED::initUniforms(builder, gl, programID);
1277 const char* dir = builder->getUniformCStr(fDirectionUni);
1278 GR_GL_CALL_RET(gl, fDirectionLocation, GetUniformLocation(programID, dir));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001279}
1280
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001281void GrGLDistantLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1282 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001283 SkASSERT(light->type() == SkLight::kDistant_LightType);
1284 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001285 setUniformNormal3(gl, fDirectionLocation, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001286}
1287
bsalomon@google.com032b2212012-07-16 13:36:18 +00001288void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1289 SkString* out,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001290 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001291 const char* dir = builder->getUniformCStr(fDirectionUni);
1292 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001293}
1294
1295///////////////////////////////////////////////////////////////////////////////
1296
bsalomon@google.com032b2212012-07-16 13:36:18 +00001297void GrGLPointLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1298 INHERITED::setupVariables(builder, stage);
1299 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1300 "uLightLocation", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001301}
1302
bsalomon@google.com032b2212012-07-16 13:36:18 +00001303void GrGLPointLight::initUniforms(const GrGLShaderBuilder* builder,
1304 const GrGLInterface* gl,
1305 int programID) {
1306 INHERITED::initUniforms(builder, gl, programID);
1307 const char* loc = builder->getUniformCStr(fLocationUni);
1308 GR_GL_CALL_RET(gl, fLocationLocation, GetUniformLocation(programID, loc));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001309}
1310
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001311void GrGLPointLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1312 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001313 SkASSERT(light->type() == SkLight::kPoint_LightType);
1314 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001315 setUniformPoint3FlipY(gl, fLocationLocation, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001316}
1317
bsalomon@google.com032b2212012-07-16 13:36:18 +00001318void GrGLPointLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001319}
1320
bsalomon@google.com032b2212012-07-16 13:36:18 +00001321void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder, SkString* out, const char* z) const {
1322 const char* loc = builder->getUniformCStr(fLocationUni);
1323 out->appendf(
1324 "normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001325}
1326
1327///////////////////////////////////////////////////////////////////////////////
1328
bsalomon@google.com032b2212012-07-16 13:36:18 +00001329void GrGLSpotLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1330 INHERITED::setupVariables(builder, stage);
1331 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1332 kVec3f_GrSLType, "uLightLocation", stage);
1333 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1334 kFloat_GrSLType, "uExponent", stage);
1335 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1336 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1337 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1338 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1339 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1340 kFloat_GrSLType, "uConeScale", stage);
1341 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1342 kVec3f_GrSLType, "uS", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001343}
1344
bsalomon@google.com032b2212012-07-16 13:36:18 +00001345void GrGLSpotLight::initUniforms(const GrGLShaderBuilder* builder, const GrGLInterface* gl, int programID) {
1346 INHERITED::initUniforms(builder, gl, programID);
1347 const char* location = builder->getUniformCStr(fLocationUni);
1348 const char* exponent = builder->getUniformCStr(fExponentUni);
1349 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1350 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1351 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1352 const char* s = builder->getUniformCStr(fSUni);
1353 GR_GL_CALL_RET(gl, fLocationLocation, GetUniformLocation(programID, location));
1354 GR_GL_CALL_RET(gl, fExponentLocation, GetUniformLocation(programID, exponent));
1355 GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation, GetUniformLocation(programID, cosInner));
1356 GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation, GetUniformLocation(programID, cosOuter));
1357 GR_GL_CALL_RET(gl, fConeScaleLocation, GetUniformLocation(programID, coneScale));
1358 GR_GL_CALL_RET(gl, fSLocation, GetUniformLocation(programID, s));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001359}
1360
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001361void GrGLSpotLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1362 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001363 SkASSERT(light->type() == SkLight::kSpot_LightType);
1364 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001365 setUniformPoint3FlipY(gl, fLocationLocation, spotLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001366 GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
1367 GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
1368 GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
1369 GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001370 setUniformNormal3(gl, fSLocation, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001371}
1372
bsalomon@google.com032b2212012-07-16 13:36:18 +00001373void GrGLSpotLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001374}
1375
bsalomon@google.com032b2212012-07-16 13:36:18 +00001376void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
1377 const char* exponent = builder->getUniformCStr(fExponentUni);
1378 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1379 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1380 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1381 const char* s = builder->getUniformCStr(fSUni);
1382 const char* color = builder->getUniformCStr(fColorUni);
1383
1384 out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1385 out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1386 out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
1387 out->appendf("\t\treturn vec3(0);\n");
1388 out->appendf("\t}\n");
1389 out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1390 out->appendf("\tif (cosAngle < %s) {\n", cosInner);
1391 out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
1392 out->appendf("\t}\n");
1393 out->appendf("\treturn %s;\n", color);
1394 out->appendf("}\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001395}
1396
bsalomon@google.com032b2212012-07-16 13:36:18 +00001397void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1398 SkString* out,
1399 const char* z) const {
1400 const char* location= builder->getUniformCStr(fLocationUni);
1401 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001402}
1403
bsalomon@google.com032b2212012-07-16 13:36:18 +00001404void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
1405 SkString* out, const char *surfaceToLight) const {
1406 out->appendf("lightColor(%s)", surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001407}
1408
djsollen@google.com08337772012-06-26 14:33:13 +00001409SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1410 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1411 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1412 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1413 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1414 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1415SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END