blob: a46cedd4f226c8621d49743f671063bf9baa2957 [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"
tomhudson@google.com300f5622012-07-20 14:15:22 +000011#include "SkTypes.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000012#include "GrProgramStageFactory.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000013#include "effects/GrSingleTextureEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000014#include "gl/GrGLProgramStage.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000015#include "gl/GrGLTexture.h"
16#include "GrCustomStage.h"
17
18class GrGLDiffuseLightingEffect;
19class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000020
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000021// For brevity
22typedef GrGLUniformManager::UniformHandle UniformHandle;
23static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
bsalomon@google.com032b2212012-07-16 13:36:18 +000024
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000025namespace {
26
27const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
28const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
29const SkScalar gOneHalf = SkFloatToScalar(0.5f);
30const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
31
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000032void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000033 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000034 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000035}
36
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000037void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
38 setUniformPoint3(uman, uni, SkPoint3(point.fX, -point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000039}
40
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000041void setUniformPoint3FlipY(const GrGLUniformManager& uman,
42 UniformHandle uni,
43 const SkPoint3& point,
44 int height) {
45 setUniformPoint3(uman, uni, SkPoint3(point.fX, height-point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000046}
47
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000048// Shift matrix components to the left, as we advance pixels to the right.
49inline void shiftMatrixLeft(int m[9]) {
50 m[0] = m[1];
51 m[3] = m[4];
52 m[6] = m[7];
53 m[1] = m[2];
54 m[4] = m[5];
55 m[7] = m[8];
56}
57
58class DiffuseLightingType {
59public:
60 DiffuseLightingType(SkScalar kd)
61 : fKD(kd) {}
62 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
63 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
64 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
65 SkPoint3 color(lightColor * colorScale);
66 return SkPackARGB32(255,
67 SkScalarFloorToInt(color.fX),
68 SkScalarFloorToInt(color.fY),
69 SkScalarFloorToInt(color.fZ));
70 }
71private:
72 SkScalar fKD;
73};
74
75class SpecularLightingType {
76public:
77 SpecularLightingType(SkScalar ks, SkScalar shininess)
78 : fKS(ks), fShininess(shininess) {}
79 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
80 SkPoint3 halfDir(surfaceTolight);
81 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
82 halfDir.normalize();
83 SkScalar colorScale = SkScalarMul(fKS,
84 SkScalarPow(normal.dot(halfDir), fShininess));
85 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
86 SkPoint3 color(lightColor * colorScale);
87 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
88 SkScalarFloorToInt(color.fX),
89 SkScalarFloorToInt(color.fY),
90 SkScalarFloorToInt(color.fZ));
91 }
92private:
93 SkScalar fKS;
94 SkScalar fShininess;
95};
96
97inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
98 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
99}
100
101inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
102 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
103 SkScalarMul(-y, surfaceScale),
104 SK_Scalar1);
105 vector.normalize();
106 return vector;
107}
108
109inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
110 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
111 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
112 surfaceScale);
113}
114
115inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
116 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
117 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
118 surfaceScale);
119}
120
121inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
122 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
123 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
124 surfaceScale);
125}
126
127inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
128 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
129 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
130 surfaceScale);
131}
132
133
134inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
135 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
136 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
137 surfaceScale);
138}
139
140inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
141 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
142 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
143 surfaceScale);
144}
145
146inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
147 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
148 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
149 surfaceScale);
150}
151
152inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
153 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
154 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
155 surfaceScale);
156}
157
158inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
160 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
161 surfaceScale);
162}
163
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000164template <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 +0000165 const LightType* l = static_cast<const LightType*>(light);
166 int y = 0;
167 {
168 const SkPMColor* row1 = src.getAddr32(0, 0);
169 const SkPMColor* row2 = src.getAddr32(0, 1);
170 SkPMColor* dptr = dst->getAddr32(0, 0);
171 int m[9];
172 int x = 0;
173 m[4] = SkGetPackedA32(*row1++);
174 m[5] = SkGetPackedA32(*row1++);
175 m[7] = SkGetPackedA32(*row2++);
176 m[8] = SkGetPackedA32(*row2++);
177 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000178 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000179 for (x = 1; x < src.width() - 1; ++x)
180 {
181 shiftMatrixLeft(m);
182 m[5] = SkGetPackedA32(*row1++);
183 m[8] = SkGetPackedA32(*row2++);
184 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000185 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000186 }
187 shiftMatrixLeft(m);
188 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000189 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000190 }
191
192 for (++y; y < src.height() - 1; ++y) {
193 const SkPMColor* row0 = src.getAddr32(0, y - 1);
194 const SkPMColor* row1 = src.getAddr32(0, y);
195 const SkPMColor* row2 = src.getAddr32(0, y + 1);
196 SkPMColor* dptr = dst->getAddr32(0, y);
197 int m[9];
198 int x = 0;
199 m[1] = SkGetPackedA32(*row0++);
200 m[2] = SkGetPackedA32(*row0++);
201 m[4] = SkGetPackedA32(*row1++);
202 m[5] = SkGetPackedA32(*row1++);
203 m[7] = SkGetPackedA32(*row2++);
204 m[8] = SkGetPackedA32(*row2++);
205 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000206 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000207 for (x = 1; x < src.width() - 1; ++x) {
208 shiftMatrixLeft(m);
209 m[2] = SkGetPackedA32(*row0++);
210 m[5] = SkGetPackedA32(*row1++);
211 m[8] = SkGetPackedA32(*row2++);
212 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000213 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000214 }
215 shiftMatrixLeft(m);
216 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000217 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000218 }
219
220 {
221 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
222 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
223 int x = 0;
224 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
225 int m[9];
226 m[1] = SkGetPackedA32(*row0++);
227 m[2] = SkGetPackedA32(*row0++);
228 m[4] = SkGetPackedA32(*row1++);
229 m[5] = SkGetPackedA32(*row1++);
230 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000231 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000232 for (x = 1; x < src.width() - 1; ++x)
233 {
234 shiftMatrixLeft(m);
235 m[2] = SkGetPackedA32(*row0++);
236 m[5] = SkGetPackedA32(*row1++);
237 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000238 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 }
240 shiftMatrixLeft(m);
241 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000242 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000243 }
244}
245
246SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
247 SkPoint3 point;
248 point.fX = buffer.readScalar();
249 point.fY = buffer.readScalar();
250 point.fZ = buffer.readScalar();
251 return point;
252};
253
254void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
255 buffer.writeScalar(point.fX);
256 buffer.writeScalar(point.fY);
257 buffer.writeScalar(point.fZ);
258};
259
260class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
261public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000262 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000263 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
264
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000265 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000266 SkScalar kd() const { return fKD; }
267
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000268protected:
269 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
270 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
271 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
272 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
273
274
275private:
276 typedef SkLightingImageFilter INHERITED;
277 SkScalar fKD;
278};
279
280class SkSpecularLightingImageFilter : public SkLightingImageFilter {
281public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000282 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000283 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
284
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000285 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000286 SkScalar ks() const { return fKS; }
287 SkScalar shininess() const { return fShininess; }
288
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289protected:
290 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
291 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
292 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
293 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
294
295private:
296 typedef SkLightingImageFilter INHERITED;
297 SkScalar fKS;
298 SkScalar fShininess;
299};
300
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000301
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000302class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000303public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000304 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000305 virtual ~GrLightingEffect();
306
307 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
308
309 const SkLight* light() const { return fLight; }
310 SkScalar surfaceScale() const { return fSurfaceScale; }
311private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000312 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000313 const SkLight* fLight;
314 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000315};
316
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000317class GrDiffuseLightingEffect : public GrLightingEffect {
318public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000319 GrDiffuseLightingEffect(GrTexture* texture,
320 const SkLight* light,
321 SkScalar surfaceScale,
322 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000323
324 static const char* Name() { return "DiffuseLighting"; }
325
326 typedef GrGLDiffuseLightingEffect GLProgramStage;
327
328 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
329 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
330 SkScalar kd() const { return fKD; }
331private:
332 typedef GrLightingEffect INHERITED;
333 SkScalar fKD;
334};
335
336class GrSpecularLightingEffect : public GrLightingEffect {
337public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000338 GrSpecularLightingEffect(GrTexture* texture,
339 const SkLight* light,
340 SkScalar surfaceScale,
341 SkScalar ks,
342 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000343
344 static const char* Name() { return "SpecularLighting"; }
345
346 typedef GrGLSpecularLightingEffect GLProgramStage;
347
348 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
349 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
350 SkScalar ks() const { return fKS; }
351 SkScalar shininess() const { return fShininess; }
352
353private:
354 typedef GrLightingEffect INHERITED;
355 SkScalar fKS;
356 SkScalar fShininess;
357};
358
359///////////////////////////////////////////////////////////////////////////////
360
361class GrGLLight {
362public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000363 virtual ~GrGLLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000364 virtual void setupVariables(GrGLShaderBuilder* builder, int stage);
365 virtual void emitVS(SkString* out) const {}
366 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
367 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
368 SkString* out,
369 const char* z) const = 0;
370 virtual void emitLightColor(const GrGLShaderBuilder*,
371 SkString* out,
372 const char *surfaceToLight) const;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000373 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000374
375private:
376 typedef SkRefCnt INHERITED;
377
378protected:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000379 UniformHandle fColorUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000380};
381
382///////////////////////////////////////////////////////////////////////////////
383
384class GrGLDistantLight : public GrGLLight {
385public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000386 virtual ~GrGLDistantLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000387 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000388 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000389 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
390 SkString* out,
391 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000392private:
393 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000394 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000395};
396
397///////////////////////////////////////////////////////////////////////////////
398
399class GrGLPointLight : public GrGLLight {
400public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000401 virtual ~GrGLPointLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000402 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000403 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000404 virtual void emitVS(SkString* out) const SK_OVERRIDE;
405 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
406 SkString* out,
407 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000408private:
409 typedef GrGLLight INHERITED;
410 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000411 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000412};
413
414///////////////////////////////////////////////////////////////////////////////
415
416class GrGLSpotLight : public GrGLLight {
417public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000418 virtual ~GrGLSpotLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000419 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000420 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000421 virtual void emitVS(SkString* out) const SK_OVERRIDE;
422 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
423 virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
424 SkString* out,
425 const char* z) const SK_OVERRIDE;
426 virtual void emitLightColor(const GrGLShaderBuilder*,
427 SkString* out,
428 const char *surfaceToLight) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000429
430private:
431 typedef GrGLLight INHERITED;
432
bsalomon@google.com032b2212012-07-16 13:36:18 +0000433 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000434 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000435 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000436 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000437 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000438 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000439};
440
441};
442
443///////////////////////////////////////////////////////////////////////////////
444
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000445class SkLight : public SkFlattenable {
446public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000447 SK_DECLARE_INST_COUNT(SkLight)
448
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000449 enum LightType {
450 kDistant_LightType,
451 kPoint_LightType,
452 kSpot_LightType,
453 };
454 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000455 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000456 virtual GrGLLight* createGLLight() const = 0;
457 virtual bool isEqual(const SkLight& other) const {
458 return fColor == other.fColor;
459 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000460
djsollen@google.com08337772012-06-26 14:33:13 +0000461protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000462 SkLight(SkColor color)
463 : fColor(SkIntToScalar(SkColorGetR(color)),
464 SkIntToScalar(SkColorGetG(color)),
465 SkIntToScalar(SkColorGetB(color))) {}
466 SkLight(SkFlattenableReadBuffer& buffer)
467 : INHERITED(buffer) {
468 fColor = readPoint3(buffer);
469 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000470 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000471 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000472 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000473 }
djsollen@google.com08337772012-06-26 14:33:13 +0000474
475private:
476 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000477 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000478};
479
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000480SK_DEFINE_INST_COUNT(SkLight)
481
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000482///////////////////////////////////////////////////////////////////////////////
483
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000484class SkDistantLight : public SkLight {
485public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000486 SkDistantLight(const SkPoint3& direction, SkColor color)
487 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000488 }
djsollen@google.com08337772012-06-26 14:33:13 +0000489
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000490 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
491 return fDirection;
492 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000493 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000494 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000495 const SkPoint3& direction() const { return fDirection; }
496 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000497 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
498 if (other.type() != kDistant_LightType) {
499 return false;
500 }
501
502 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
503 return INHERITED::isEqual(other) &&
504 fDirection == o.fDirection;
505 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000506
507 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
508
djsollen@google.com08337772012-06-26 14:33:13 +0000509protected:
510 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
511 fDirection = readPoint3(buffer);
512 }
513 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
514 INHERITED::flatten(buffer);
515 writePoint3(fDirection, buffer);
516 }
517
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000518private:
djsollen@google.com08337772012-06-26 14:33:13 +0000519 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000520 SkPoint3 fDirection;
521};
522
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000523///////////////////////////////////////////////////////////////////////////////
524
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525class SkPointLight : public SkLight {
526public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000527 SkPointLight(const SkPoint3& location, SkColor color)
528 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000529
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000530 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
531 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
532 fLocation.fY - SkIntToScalar(y),
533 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
534 direction.normalize();
535 return direction;
536 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000537 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000538 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000539 const SkPoint3& location() const { return fLocation; }
540 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000541 return SkNEW(GrGLPointLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000542 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000543 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000544 if (other.type() != kPoint_LightType) {
545 return false;
546 }
547 const SkPointLight& o = static_cast<const SkPointLight&>(other);
548 return INHERITED::isEqual(other) &&
549 fLocation == o.fLocation;
550 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000551
552 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
553
djsollen@google.com08337772012-06-26 14:33:13 +0000554protected:
555 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
556 fLocation = readPoint3(buffer);
557 }
558 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
559 INHERITED::flatten(buffer);
560 writePoint3(fLocation, buffer);
561 }
562
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000563private:
djsollen@google.com08337772012-06-26 14:33:13 +0000564 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000565 SkPoint3 fLocation;
566};
567
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000568///////////////////////////////////////////////////////////////////////////////
569
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000570class SkSpotLight : public SkLight {
571public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000572 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
573 : INHERITED(color),
574 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000575 fTarget(target),
576 fSpecularExponent(specularExponent)
577 {
578 fS = target - location;
579 fS.normalize();
580 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
581 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
582 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
583 fConeScale = SkScalarInvert(antiAliasThreshold);
584 }
djsollen@google.com08337772012-06-26 14:33:13 +0000585
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
587 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
588 fLocation.fY - SkIntToScalar(y),
589 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
590 direction.normalize();
591 return direction;
592 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000593 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000594 SkScalar cosAngle = -surfaceToLight.dot(fS);
595 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000596 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000597 }
598 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
599 if (cosAngle < fCosInnerConeAngle) {
600 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000601 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000602 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000603 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000604 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000605 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000606 return SkNEW(GrGLSpotLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000607 }
djsollen@google.com08337772012-06-26 14:33:13 +0000608 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000609 const SkPoint3& location() const { return fLocation; }
610 const SkPoint3& target() const { return fTarget; }
611 SkScalar specularExponent() const { return fSpecularExponent; }
612 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
613 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
614 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000615 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000616
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000617 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
618
djsollen@google.com08337772012-06-26 14:33:13 +0000619protected:
620 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
621 fLocation = readPoint3(buffer);
622 fTarget = readPoint3(buffer);
623 fSpecularExponent = buffer.readScalar();
624 fCosOuterConeAngle = buffer.readScalar();
625 fCosInnerConeAngle = buffer.readScalar();
626 fConeScale = buffer.readScalar();
627 fS = readPoint3(buffer);
628 }
629 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
630 INHERITED::flatten(buffer);
631 writePoint3(fLocation, buffer);
632 writePoint3(fTarget, buffer);
633 buffer.writeScalar(fSpecularExponent);
634 buffer.writeScalar(fCosOuterConeAngle);
635 buffer.writeScalar(fCosInnerConeAngle);
636 buffer.writeScalar(fConeScale);
637 writePoint3(fS, buffer);
638 }
639
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000640 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000641 if (other.type() != kSpot_LightType) {
642 return false;
643 }
644
645 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
646 return INHERITED::isEqual(other) &&
647 fLocation == o.fLocation &&
648 fTarget == o.fTarget &&
649 fSpecularExponent == o.fSpecularExponent &&
650 fCosOuterConeAngle == o.fCosOuterConeAngle;
651 }
652
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000653private:
djsollen@google.com08337772012-06-26 14:33:13 +0000654 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000655 SkPoint3 fLocation;
656 SkPoint3 fTarget;
657 SkScalar fSpecularExponent;
658 SkScalar fCosOuterConeAngle;
659 SkScalar fCosInnerConeAngle;
660 SkScalar fConeScale;
661 SkPoint3 fS;
662};
663
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000664///////////////////////////////////////////////////////////////////////////////
665
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000666SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000667 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000668 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
669{
670 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000671 // our caller knows that we take ownership of the light, so we don't
672 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000673}
674
675SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000676 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000677 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000678 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
679 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000680}
681
682SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000683 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000684 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000685 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
686 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000687}
688
689SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000690 const SkPoint3& location, const SkPoint3& target,
691 SkScalar specularExponent, SkScalar cutoffAngle,
692 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000693 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
694 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
695 surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696}
697
698SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
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 ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000701 return SkNEW_ARGS(SkSpecularLightingImageFilter,
702 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703}
704
705SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000706 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
707 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000708 return SkNEW_ARGS(SkSpecularLightingImageFilter,
709 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000710}
711
712SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
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,
716 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000717 return SkNEW_ARGS(SkSpecularLightingImageFilter,
718 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
719 surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000720}
721
722SkLightingImageFilter::~SkLightingImageFilter() {
723 fLight->unref();
724}
725
726SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
727 : INHERITED(buffer)
728{
djsollen@google.com08337772012-06-26 14:33:13 +0000729 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000730 fSurfaceScale = buffer.readScalar();
731}
732
733void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
734 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000735 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000736 buffer.writeScalar(fSurfaceScale);
737}
738
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000739///////////////////////////////////////////////////////////////////////////////
740
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
742 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743 fKD(kd)
744{
745}
746
747SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
748 : INHERITED(buffer)
749{
750 fKD = buffer.readScalar();
751}
752
753void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
754 this->INHERITED::flatten(buffer);
755 buffer.writeScalar(fKD);
756}
757
758bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
759 const SkBitmap& src,
760 const SkMatrix&,
761 SkBitmap* dst,
762 SkIPoint*) {
763 if (src.config() != SkBitmap::kARGB_8888_Config) {
764 return false;
765 }
766 SkAutoLockPixels alp(src);
767 if (!src.getPixels()) {
768 return false;
769 }
770 if (src.width() < 2 || src.height() < 2) {
771 return false;
772 }
773 dst->setConfig(src.config(), src.width(), src.height());
774 dst->allocPixels();
775
776 DiffuseLightingType lightingType(fKD);
777 switch (light()->type()) {
778 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000779 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000780 break;
781 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000782 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000783 break;
784 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000785 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786 break;
787 }
788 return true;
789}
790
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000791bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
792 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000793 if (stage) {
794 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000795 *stage = SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light(), scale, kd()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000796 }
797 return true;
798}
799
800///////////////////////////////////////////////////////////////////////////////
801
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000802SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
803 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000804 fKS(ks),
805 fShininess(shininess)
806{
807}
808
809SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
810 : INHERITED(buffer)
811{
812 fKS = buffer.readScalar();
813 fShininess = buffer.readScalar();
814}
815
816void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
817 this->INHERITED::flatten(buffer);
818 buffer.writeScalar(fKS);
819 buffer.writeScalar(fShininess);
820}
821
822bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
823 const SkBitmap& src,
824 const SkMatrix&,
825 SkBitmap* dst,
826 SkIPoint*) {
827 if (src.config() != SkBitmap::kARGB_8888_Config) {
828 return false;
829 }
830 SkAutoLockPixels alp(src);
831 if (!src.getPixels()) {
832 return false;
833 }
834 if (src.width() < 2 || src.height() < 2) {
835 return false;
836 }
837 dst->setConfig(src.config(), src.width(), src.height());
838 dst->allocPixels();
839
840 SpecularLightingType lightingType(fKS, fShininess);
841 switch (light()->type()) {
842 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000843 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000844 break;
845 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000846 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000847 break;
848 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000849 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850 break;
851 }
852 return true;
853}
854
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000855bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
856 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000857 if (stage) {
858 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000859 *stage = SkNEW_ARGS(GrSpecularLightingEffect, (texture, light(), scale, ks(), shininess()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000860 }
861 return true;
862}
863
864///////////////////////////////////////////////////////////////////////////////
865
866class GrGLLightingEffect : public GrGLProgramStage {
867public:
868 GrGLLightingEffect(const GrProgramStageFactory& factory,
869 const GrCustomStage& stage);
870 virtual ~GrGLLightingEffect();
871
bsalomon@google.com032b2212012-07-16 13:36:18 +0000872 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000873 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000874 virtual void emitVS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000875 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000876 virtual void emitFS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000877 const char* outputColor,
878 const char* inputColor,
879 const char* samplerName) SK_OVERRIDE;
880
bsalomon@google.com032b2212012-07-16 13:36:18 +0000881 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000882
883 static inline StageKey GenKey(const GrCustomStage& s);
884
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000885 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000886 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000887 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000888 int stageNum) SK_OVERRIDE;
889
890private:
891 typedef GrGLProgramStage INHERITED;
892
bsalomon@google.com032b2212012-07-16 13:36:18 +0000893 UniformHandle fImageIncrementUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000894 UniformHandle fSurfaceScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000895 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000896};
897
898///////////////////////////////////////////////////////////////////////////////
899
900class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
901public:
902 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
903 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000904 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000905 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000906 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000907 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000908 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000909 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000910 int stageNum) SK_OVERRIDE;
911
912private:
913 typedef GrGLLightingEffect INHERITED;
914
bsalomon@google.com032b2212012-07-16 13:36:18 +0000915 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000916};
917
918///////////////////////////////////////////////////////////////////////////////
919
920class GrGLSpecularLightingEffect : public GrGLLightingEffect {
921public:
922 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
923 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000924 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000925 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000926 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000927 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000928 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000929 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000930 int stageNum) SK_OVERRIDE;
931
932private:
933 typedef GrGLLightingEffect INHERITED;
934
bsalomon@google.com032b2212012-07-16 13:36:18 +0000935 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000936 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000937};
938
939///////////////////////////////////////////////////////////////////////////////
940
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000941GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
942 : GrSingleTextureEffect(texture)
943 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000944 , fSurfaceScale(surfaceScale) {
945 fLight->ref();
946}
947
948GrLightingEffect::~GrLightingEffect() {
949 fLight->unref();
950}
951
952bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
953 const GrLightingEffect& s =
954 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000955 return INHERITED::isEqual(sBase) &&
956 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000957 fSurfaceScale == s.fSurfaceScale;
958}
959
960///////////////////////////////////////////////////////////////////////////////
961
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000962GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
963 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000964}
965
966const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
967 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
968}
969
970bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
971 const GrDiffuseLightingEffect& s =
972 static_cast<const GrDiffuseLightingEffect&>(sBase);
973 return INHERITED::isEqual(sBase) &&
974 this->kd() == s.kd();
975}
976
977///////////////////////////////////////////////////////////////////////////////
978
979GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
980 const GrCustomStage& stage)
981 : GrGLProgramStage(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000982 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000983 , fSurfaceScaleUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000984 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
985 fLight = m.light()->createGLLight();
986}
987
988GrGLLightingEffect::~GrGLLightingEffect() {
989 delete fLight;
990}
991
bsalomon@google.com032b2212012-07-16 13:36:18 +0000992void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
993 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
994 kVec2f_GrSLType,
995 "uImageIncrement", stage);
996 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
997 kFloat_GrSLType,
998 "uSurfaceScale", stage);
999 fLight->setupVariables(builder, stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000}
1001
bsalomon@google.com032b2212012-07-16 13:36:18 +00001002void GrGLLightingEffect::emitVS(GrGLShaderBuilder* builder,
1003 const char* vertexCoords) {
1004 fLight->emitVS(&builder->fVSCode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001005}
1006
bsalomon@google.com032b2212012-07-16 13:36:18 +00001007void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
1008 const char* outputColor,
1009 const char* inputColor,
1010 const char* samplerName) {
1011 SkString* code = &builder->fFSCode;
1012 SkString* funcs = &builder->fFSFunctions;
1013 fLight->emitFuncs(builder, funcs);
1014 this->emitLightFunc(builder, funcs);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001015 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 +00001016 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001017 funcs->appendf("}\n");
1018 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1019 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1020 funcs->appendf("}\n");
1021 funcs->append("\n\
1022vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1023 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1024 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1025 surfaceScale);\n}\n");
1026
bsalomon@google.com032b2212012-07-16 13:36:18 +00001027 code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001028 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001029
1030 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1031 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1032
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001033 int index = 0;
1034 for (int dy = -1; dy <= 1; dy++) {
1035 for (int dx = -1; dx <= 1; dx++) {
1036 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001037 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001038 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001039 builder->emitTextureLookup(samplerName, texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001040 code->appendf(".a;\n");
1041 }
1042 }
1043 code->appendf("\t\tvec3 surfaceToLight = ");
1044 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001045 arg.appendf("%s * m[4]", surfScale);
1046 fLight->emitSurfaceToLight(builder, code, arg.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001047 code->appendf(";\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001048 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
1049 fLight->emitLightColor(builder, code, "surfaceToLight");
1050 code->appendf(")%s;\n", builder->fModulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001051}
1052
1053GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1054 const GrCustomStage& s) {
1055 return static_cast<const GrLightingEffect&>(s).light()->type();
1056}
1057
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001058void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001059 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001060 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001061 int stageNum) {
1062 const GrLightingEffect& effect =
1063 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001064 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1065 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001066 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1067 uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
1068 fLight->setData(uman, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001069}
1070
1071///////////////////////////////////////////////////////////////////////////////
1072
1073///////////////////////////////////////////////////////////////////////////////
1074
1075GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1076 const GrCustomStage& stage)
1077 : INHERITED(factory, stage)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001078 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001079}
1080
bsalomon@google.com032b2212012-07-16 13:36:18 +00001081void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1082 INHERITED::setupVariables(builder, stage);
1083 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "uKD",
1084 stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001085}
1086
bsalomon@google.com032b2212012-07-16 13:36:18 +00001087void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
1088 const char* kd = builder->getUniformCStr(fKDUni);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001089 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001090 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001091 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001092 funcs->appendf("}\n");
1093}
1094
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001095void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001096 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001097 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001098 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001099 INHERITED::setData(uman, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001100 const GrDiffuseLightingEffect& effect =
1101 static_cast<const GrDiffuseLightingEffect&>(data);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001102 uman.set1f(fKDUni, effect.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001103}
1104
1105///////////////////////////////////////////////////////////////////////////////
1106
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001107GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1108 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001109 fKS(ks),
1110 fShininess(shininess) {
1111}
1112
1113const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1114 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1115}
1116
1117bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1118 const GrSpecularLightingEffect& s =
1119 static_cast<const GrSpecularLightingEffect&>(sBase);
1120 return INHERITED::isEqual(sBase) &&
1121 this->ks() == s.ks() &&
1122 this->shininess() == s.shininess();
1123}
1124
1125///////////////////////////////////////////////////////////////////////////////
1126
1127GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1128 const GrCustomStage& stage)
1129 : GrGLLightingEffect(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001130 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001131 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001132}
1133
bsalomon@google.com032b2212012-07-16 13:36:18 +00001134void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1135 INHERITED::setupVariables(builder, stage);
1136 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1137 kFloat_GrSLType, "uKS", stage);
1138 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1139 kFloat_GrSLType, "uShininess", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001140}
1141
bsalomon@google.com032b2212012-07-16 13:36:18 +00001142void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001143 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1144 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1145
bsalomon@google.com032b2212012-07-16 13:36:18 +00001146 const char* ks = builder->getUniformCStr(fKSUni);
1147 const char* shininess = builder->getUniformCStr(fShininessUni);
1148 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001149 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001150 funcs->appendf("}\n");
1151}
1152
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001153void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001154 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001155 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001156 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001157 INHERITED::setData(uman, data, rt, stageNum);
1158 const GrSpecularLightingEffect& effect = static_cast<const GrSpecularLightingEffect&>(data);
1159 uman.set1f(fKSUni, effect.ks());
1160 uman.set1f(fShininessUni, effect.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001161}
1162
1163///////////////////////////////////////////////////////////////////////////////
1164
bsalomon@google.com032b2212012-07-16 13:36:18 +00001165void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
1166 SkString* out,
1167 const char *surfaceToLight) const {
1168 const char* color = builder->getUniformCStr(fColorUni);
1169 out->append(color);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001170}
1171
bsalomon@google.com032b2212012-07-16 13:36:18 +00001172void GrGLLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001173 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1174 kVec3f_GrSLType, "uLightColor", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001175}
1176
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001177void GrGLLight::setData(const GrGLUniformManager& uman,
1178 const GrRenderTarget* rt,
1179 const SkLight* light) const {
1180 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001181}
1182
1183GrGLLight* SkDistantLight::createGLLight() const {
tomhudson@google.com300f5622012-07-20 14:15:22 +00001184 return SkNEW(GrGLDistantLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001185}
1186
1187///////////////////////////////////////////////////////////////////////////////
1188
bsalomon@google.com032b2212012-07-16 13:36:18 +00001189void GrGLDistantLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1190 INHERITED::setupVariables(builder, stage);
1191 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1192 "uLightDirection", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001193}
1194
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001195void GrGLDistantLight::setData(const GrGLUniformManager& uman,
1196 const GrRenderTarget* rt,
1197 const SkLight* light) const {
1198 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001199 SkASSERT(light->type() == SkLight::kDistant_LightType);
1200 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001201 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001202}
1203
bsalomon@google.com032b2212012-07-16 13:36:18 +00001204void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1205 SkString* out,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001206 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001207 const char* dir = builder->getUniformCStr(fDirectionUni);
1208 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001209}
1210
1211///////////////////////////////////////////////////////////////////////////////
1212
bsalomon@google.com032b2212012-07-16 13:36:18 +00001213void GrGLPointLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1214 INHERITED::setupVariables(builder, stage);
1215 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1216 "uLightLocation", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001217}
1218
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001219void GrGLPointLight::setData(const GrGLUniformManager& uman,
1220 const GrRenderTarget* rt,
1221 const SkLight* light) const {
1222 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001223 SkASSERT(light->type() == SkLight::kPoint_LightType);
1224 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001225 setUniformPoint3FlipY(uman, fLocationUni, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001226}
1227
bsalomon@google.com032b2212012-07-16 13:36:18 +00001228void GrGLPointLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229}
1230
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001231void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1232 SkString* out,
1233 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001234 const char* loc = builder->getUniformCStr(fLocationUni);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001235 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001236}
1237
1238///////////////////////////////////////////////////////////////////////////////
1239
bsalomon@google.com032b2212012-07-16 13:36:18 +00001240void GrGLSpotLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1241 INHERITED::setupVariables(builder, stage);
1242 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1243 kVec3f_GrSLType, "uLightLocation", stage);
1244 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1245 kFloat_GrSLType, "uExponent", stage);
1246 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1247 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1248 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1249 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1250 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1251 kFloat_GrSLType, "uConeScale", stage);
1252 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1253 kVec3f_GrSLType, "uS", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001254}
1255
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001256void GrGLSpotLight::setData(const GrGLUniformManager& uman,
1257 const GrRenderTarget* rt,
1258 const SkLight* light) const {
1259 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001260 SkASSERT(light->type() == SkLight::kSpot_LightType);
1261 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001262 setUniformPoint3FlipY(uman, fLocationUni, spotLight->location(), rt->height());
1263 uman.set1f(fExponentUni, spotLight->specularExponent());
1264 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1265 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1266 uman.set1f(fConeScaleUni, spotLight->coneScale());
1267 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001268}
1269
bsalomon@google.com032b2212012-07-16 13:36:18 +00001270void GrGLSpotLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001271}
1272
bsalomon@google.com032b2212012-07-16 13:36:18 +00001273void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
1274 const char* exponent = builder->getUniformCStr(fExponentUni);
1275 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1276 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1277 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1278 const char* s = builder->getUniformCStr(fSUni);
1279 const char* color = builder->getUniformCStr(fColorUni);
1280
1281 out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1282 out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1283 out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
1284 out->appendf("\t\treturn vec3(0);\n");
1285 out->appendf("\t}\n");
1286 out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1287 out->appendf("\tif (cosAngle < %s) {\n", cosInner);
1288 out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
1289 out->appendf("\t}\n");
1290 out->appendf("\treturn %s;\n", color);
1291 out->appendf("}\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001292}
1293
bsalomon@google.com032b2212012-07-16 13:36:18 +00001294void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1295 SkString* out,
1296 const char* z) const {
1297 const char* location= builder->getUniformCStr(fLocationUni);
1298 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001299}
1300
bsalomon@google.com032b2212012-07-16 13:36:18 +00001301void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
1302 SkString* out, const char *surfaceToLight) const {
1303 out->appendf("lightColor(%s)", surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001304}
1305
djsollen@google.com08337772012-06-26 14:33:13 +00001306SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1307 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1308 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1309 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1310 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1311 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1312SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END