blob: 21a553dd71dbdaadfb6e0613dcc7bf297a0a276a [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) {
33 GR_STATIC_ASSERT(offsetof(SkPoint3, fX) + sizeof(float) == offsetof(SkPoint3, fY));
34 GR_STATIC_ASSERT(offsetof(SkPoint3, fY) + sizeof(float) == offsetof(SkPoint3, fZ));
35 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000036}
37
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000038void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
39 setUniformPoint3(uman, uni, SkPoint3(point.fX, -point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000040}
41
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000042void setUniformPoint3FlipY(const GrGLUniformManager& uman,
43 UniformHandle uni,
44 const SkPoint3& point,
45 int height) {
46 setUniformPoint3(uman, uni, SkPoint3(point.fX, height-point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000047}
48
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000049// Shift matrix components to the left, as we advance pixels to the right.
50inline void shiftMatrixLeft(int m[9]) {
51 m[0] = m[1];
52 m[3] = m[4];
53 m[6] = m[7];
54 m[1] = m[2];
55 m[4] = m[5];
56 m[7] = m[8];
57}
58
59class DiffuseLightingType {
60public:
61 DiffuseLightingType(SkScalar kd)
62 : fKD(kd) {}
63 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
64 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
65 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
66 SkPoint3 color(lightColor * colorScale);
67 return SkPackARGB32(255,
68 SkScalarFloorToInt(color.fX),
69 SkScalarFloorToInt(color.fY),
70 SkScalarFloorToInt(color.fZ));
71 }
72private:
73 SkScalar fKD;
74};
75
76class SpecularLightingType {
77public:
78 SpecularLightingType(SkScalar ks, SkScalar shininess)
79 : fKS(ks), fShininess(shininess) {}
80 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
81 SkPoint3 halfDir(surfaceTolight);
82 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
83 halfDir.normalize();
84 SkScalar colorScale = SkScalarMul(fKS,
85 SkScalarPow(normal.dot(halfDir), fShininess));
86 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
87 SkPoint3 color(lightColor * colorScale);
88 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
89 SkScalarFloorToInt(color.fX),
90 SkScalarFloorToInt(color.fY),
91 SkScalarFloorToInt(color.fZ));
92 }
93private:
94 SkScalar fKS;
95 SkScalar fShininess;
96};
97
98inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
99 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
100}
101
102inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
103 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
104 SkScalarMul(-y, surfaceScale),
105 SK_Scalar1);
106 vector.normalize();
107 return vector;
108}
109
110inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
111 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
112 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
113 surfaceScale);
114}
115
116inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
117 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
118 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
119 surfaceScale);
120}
121
122inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
123 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
124 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
125 surfaceScale);
126}
127
128inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
129 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
130 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
131 surfaceScale);
132}
133
134
135inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
137 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
138 surfaceScale);
139}
140
141inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
142 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
143 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
144 surfaceScale);
145}
146
147inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
148 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
149 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
150 surfaceScale);
151}
152
153inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
154 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
155 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
156 surfaceScale);
157}
158
159inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
160 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
161 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
162 surfaceScale);
163}
164
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000165template <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 +0000166 const LightType* l = static_cast<const LightType*>(light);
167 int y = 0;
168 {
169 const SkPMColor* row1 = src.getAddr32(0, 0);
170 const SkPMColor* row2 = src.getAddr32(0, 1);
171 SkPMColor* dptr = dst->getAddr32(0, 0);
172 int m[9];
173 int x = 0;
174 m[4] = SkGetPackedA32(*row1++);
175 m[5] = SkGetPackedA32(*row1++);
176 m[7] = SkGetPackedA32(*row2++);
177 m[8] = SkGetPackedA32(*row2++);
178 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000179 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000180 for (x = 1; x < src.width() - 1; ++x)
181 {
182 shiftMatrixLeft(m);
183 m[5] = SkGetPackedA32(*row1++);
184 m[8] = SkGetPackedA32(*row2++);
185 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000186 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000187 }
188 shiftMatrixLeft(m);
189 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000190 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 }
192
193 for (++y; y < src.height() - 1; ++y) {
194 const SkPMColor* row0 = src.getAddr32(0, y - 1);
195 const SkPMColor* row1 = src.getAddr32(0, y);
196 const SkPMColor* row2 = src.getAddr32(0, y + 1);
197 SkPMColor* dptr = dst->getAddr32(0, y);
198 int m[9];
199 int x = 0;
200 m[1] = SkGetPackedA32(*row0++);
201 m[2] = SkGetPackedA32(*row0++);
202 m[4] = SkGetPackedA32(*row1++);
203 m[5] = SkGetPackedA32(*row1++);
204 m[7] = SkGetPackedA32(*row2++);
205 m[8] = SkGetPackedA32(*row2++);
206 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000207 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000208 for (x = 1; x < src.width() - 1; ++x) {
209 shiftMatrixLeft(m);
210 m[2] = SkGetPackedA32(*row0++);
211 m[5] = SkGetPackedA32(*row1++);
212 m[8] = SkGetPackedA32(*row2++);
213 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000214 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000215 }
216 shiftMatrixLeft(m);
217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000218 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000219 }
220
221 {
222 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
223 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
224 int x = 0;
225 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
226 int m[9];
227 m[1] = SkGetPackedA32(*row0++);
228 m[2] = SkGetPackedA32(*row0++);
229 m[4] = SkGetPackedA32(*row1++);
230 m[5] = SkGetPackedA32(*row1++);
231 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000232 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 for (x = 1; x < src.width() - 1; ++x)
234 {
235 shiftMatrixLeft(m);
236 m[2] = SkGetPackedA32(*row0++);
237 m[5] = SkGetPackedA32(*row1++);
238 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000239 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 }
241 shiftMatrixLeft(m);
242 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000243 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000244 }
245}
246
247SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
248 SkPoint3 point;
249 point.fX = buffer.readScalar();
250 point.fY = buffer.readScalar();
251 point.fZ = buffer.readScalar();
252 return point;
253};
254
255void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
256 buffer.writeScalar(point.fX);
257 buffer.writeScalar(point.fY);
258 buffer.writeScalar(point.fZ);
259};
260
261class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
262public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000263 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
265
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000266 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000267 SkScalar kd() const { return fKD; }
268
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000269protected:
270 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
271 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
272 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
273 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
274
275
276private:
277 typedef SkLightingImageFilter INHERITED;
278 SkScalar fKD;
279};
280
281class SkSpecularLightingImageFilter : public SkLightingImageFilter {
282public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000283 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000284 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
285
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000286 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000287 SkScalar ks() const { return fKS; }
288 SkScalar shininess() const { return fShininess; }
289
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290protected:
291 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
292 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
293 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
294 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
295
296private:
297 typedef SkLightingImageFilter INHERITED;
298 SkScalar fKS;
299 SkScalar fShininess;
300};
301
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000302
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000303class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000304public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000305 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000306 virtual ~GrLightingEffect();
307
308 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
309
310 const SkLight* light() const { return fLight; }
311 SkScalar surfaceScale() const { return fSurfaceScale; }
312private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000313 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000314 const SkLight* fLight;
315 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000316};
317
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000318class GrDiffuseLightingEffect : public GrLightingEffect {
319public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000320 GrDiffuseLightingEffect(GrTexture* texture,
321 const SkLight* light,
322 SkScalar surfaceScale,
323 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000324
325 static const char* Name() { return "DiffuseLighting"; }
326
327 typedef GrGLDiffuseLightingEffect GLProgramStage;
328
329 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
330 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
331 SkScalar kd() const { return fKD; }
332private:
333 typedef GrLightingEffect INHERITED;
334 SkScalar fKD;
335};
336
337class GrSpecularLightingEffect : public GrLightingEffect {
338public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000339 GrSpecularLightingEffect(GrTexture* texture,
340 const SkLight* light,
341 SkScalar surfaceScale,
342 SkScalar ks,
343 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000344
345 static const char* Name() { return "SpecularLighting"; }
346
347 typedef GrGLSpecularLightingEffect GLProgramStage;
348
349 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
350 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
351 SkScalar ks() const { return fKS; }
352 SkScalar shininess() const { return fShininess; }
353
354private:
355 typedef GrLightingEffect INHERITED;
356 SkScalar fKS;
357 SkScalar fShininess;
358};
359
360///////////////////////////////////////////////////////////////////////////////
361
362class GrGLLight {
363public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000364 virtual ~GrGLLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000365 virtual void setupVariables(GrGLShaderBuilder* builder, int stage);
366 virtual void emitVS(SkString* out) const {}
367 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
368 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
369 SkString* out,
370 const char* z) const = 0;
371 virtual void emitLightColor(const GrGLShaderBuilder*,
372 SkString* out,
373 const char *surfaceToLight) const;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000374 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000375
376private:
377 typedef SkRefCnt INHERITED;
378
379protected:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000380 UniformHandle fColorUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000381};
382
383///////////////////////////////////////////////////////////////////////////////
384
385class GrGLDistantLight : public GrGLLight {
386public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000387 virtual ~GrGLDistantLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000388 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000389 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000390 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
391 SkString* out,
392 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000393private:
394 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000395 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000396};
397
398///////////////////////////////////////////////////////////////////////////////
399
400class GrGLPointLight : public GrGLLight {
401public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000402 virtual ~GrGLPointLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000403 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000404 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000405 virtual void emitVS(SkString* out) const SK_OVERRIDE;
406 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
407 SkString* out,
408 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000409private:
410 typedef GrGLLight INHERITED;
411 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000412 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000413};
414
415///////////////////////////////////////////////////////////////////////////////
416
417class GrGLSpotLight : public GrGLLight {
418public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000419 virtual ~GrGLSpotLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000420 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000421 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000422 virtual void emitVS(SkString* out) const SK_OVERRIDE;
423 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
424 virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
425 SkString* out,
426 const char* z) const SK_OVERRIDE;
427 virtual void emitLightColor(const GrGLShaderBuilder*,
428 SkString* out,
429 const char *surfaceToLight) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000430
431private:
432 typedef GrGLLight INHERITED;
433
bsalomon@google.com032b2212012-07-16 13:36:18 +0000434 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000435 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000436 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000437 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000438 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000439 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000440};
441
442};
443
444///////////////////////////////////////////////////////////////////////////////
445
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000446class SkLight : public SkFlattenable {
447public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000448 SK_DECLARE_INST_COUNT(SkLight)
449
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000450 enum LightType {
451 kDistant_LightType,
452 kPoint_LightType,
453 kSpot_LightType,
454 };
455 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000456 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000457 virtual GrGLLight* createGLLight() const = 0;
458 virtual bool isEqual(const SkLight& other) const {
459 return fColor == other.fColor;
460 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461
djsollen@google.com08337772012-06-26 14:33:13 +0000462protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000463 SkLight(SkColor color)
464 : fColor(SkIntToScalar(SkColorGetR(color)),
465 SkIntToScalar(SkColorGetG(color)),
466 SkIntToScalar(SkColorGetB(color))) {}
467 SkLight(SkFlattenableReadBuffer& buffer)
468 : INHERITED(buffer) {
469 fColor = readPoint3(buffer);
470 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000472 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000473 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474 }
djsollen@google.com08337772012-06-26 14:33:13 +0000475
476private:
477 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000478 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479};
480
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000481SK_DEFINE_INST_COUNT(SkLight)
482
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000483///////////////////////////////////////////////////////////////////////////////
484
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485class SkDistantLight : public SkLight {
486public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000487 SkDistantLight(const SkPoint3& direction, SkColor color)
488 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000489 }
djsollen@google.com08337772012-06-26 14:33:13 +0000490
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000491 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
492 return fDirection;
493 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000494 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000495 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496 const SkPoint3& direction() const { return fDirection; }
497 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000498 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
499 if (other.type() != kDistant_LightType) {
500 return false;
501 }
502
503 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
504 return INHERITED::isEqual(other) &&
505 fDirection == o.fDirection;
506 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000507
508 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
509
djsollen@google.com08337772012-06-26 14:33:13 +0000510protected:
511 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
512 fDirection = readPoint3(buffer);
513 }
514 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
515 INHERITED::flatten(buffer);
516 writePoint3(fDirection, buffer);
517 }
518
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000519private:
djsollen@google.com08337772012-06-26 14:33:13 +0000520 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000521 SkPoint3 fDirection;
522};
523
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000524///////////////////////////////////////////////////////////////////////////////
525
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000526class SkPointLight : public SkLight {
527public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000528 SkPointLight(const SkPoint3& location, SkColor color)
529 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000530
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000531 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
532 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
533 fLocation.fY - SkIntToScalar(y),
534 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
535 direction.normalize();
536 return direction;
537 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000538 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000540 const SkPoint3& location() const { return fLocation; }
541 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000542 return SkNEW(GrGLPointLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000543 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000544 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000545 if (other.type() != kPoint_LightType) {
546 return false;
547 }
548 const SkPointLight& o = static_cast<const SkPointLight&>(other);
549 return INHERITED::isEqual(other) &&
550 fLocation == o.fLocation;
551 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000552
553 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
554
djsollen@google.com08337772012-06-26 14:33:13 +0000555protected:
556 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
557 fLocation = readPoint3(buffer);
558 }
559 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
560 INHERITED::flatten(buffer);
561 writePoint3(fLocation, buffer);
562 }
563
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000564private:
djsollen@google.com08337772012-06-26 14:33:13 +0000565 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000566 SkPoint3 fLocation;
567};
568
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000569///////////////////////////////////////////////////////////////////////////////
570
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000571class SkSpotLight : public SkLight {
572public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000573 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
574 : INHERITED(color),
575 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000576 fTarget(target),
577 fSpecularExponent(specularExponent)
578 {
579 fS = target - location;
580 fS.normalize();
581 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
582 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
583 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
584 fConeScale = SkScalarInvert(antiAliasThreshold);
585 }
djsollen@google.com08337772012-06-26 14:33:13 +0000586
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
588 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
589 fLocation.fY - SkIntToScalar(y),
590 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
591 direction.normalize();
592 return direction;
593 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000594 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000595 SkScalar cosAngle = -surfaceToLight.dot(fS);
596 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000597 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000598 }
599 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
600 if (cosAngle < fCosInnerConeAngle) {
601 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000602 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000603 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000604 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000605 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000606 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000607 return SkNEW(GrGLSpotLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000608 }
djsollen@google.com08337772012-06-26 14:33:13 +0000609 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000610 const SkPoint3& location() const { return fLocation; }
611 const SkPoint3& target() const { return fTarget; }
612 SkScalar specularExponent() const { return fSpecularExponent; }
613 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
614 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
615 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000616 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000617
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
619
djsollen@google.com08337772012-06-26 14:33:13 +0000620protected:
621 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
622 fLocation = readPoint3(buffer);
623 fTarget = readPoint3(buffer);
624 fSpecularExponent = buffer.readScalar();
625 fCosOuterConeAngle = buffer.readScalar();
626 fCosInnerConeAngle = buffer.readScalar();
627 fConeScale = buffer.readScalar();
628 fS = readPoint3(buffer);
629 }
630 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
631 INHERITED::flatten(buffer);
632 writePoint3(fLocation, buffer);
633 writePoint3(fTarget, buffer);
634 buffer.writeScalar(fSpecularExponent);
635 buffer.writeScalar(fCosOuterConeAngle);
636 buffer.writeScalar(fCosInnerConeAngle);
637 buffer.writeScalar(fConeScale);
638 writePoint3(fS, buffer);
639 }
640
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000641 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000642 if (other.type() != kSpot_LightType) {
643 return false;
644 }
645
646 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
647 return INHERITED::isEqual(other) &&
648 fLocation == o.fLocation &&
649 fTarget == o.fTarget &&
650 fSpecularExponent == o.fSpecularExponent &&
651 fCosOuterConeAngle == o.fCosOuterConeAngle;
652 }
653
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000654private:
djsollen@google.com08337772012-06-26 14:33:13 +0000655 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000656 SkPoint3 fLocation;
657 SkPoint3 fTarget;
658 SkScalar fSpecularExponent;
659 SkScalar fCosOuterConeAngle;
660 SkScalar fCosInnerConeAngle;
661 SkScalar fConeScale;
662 SkPoint3 fS;
663};
664
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000665///////////////////////////////////////////////////////////////////////////////
666
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000667SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000668 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000669 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
670{
671 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000672 // our caller knows that we take ownership of the light, so we don't
673 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000674}
675
676SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000677 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000678 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000679 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
680 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000681}
682
683SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000684 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000685 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000686 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
687 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000688}
689
690SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000691 const SkPoint3& location, const SkPoint3& target,
692 SkScalar specularExponent, SkScalar cutoffAngle,
693 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000694 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
695 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
696 surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000697}
698
699SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000700 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000702 return SkNEW_ARGS(SkSpecularLightingImageFilter,
703 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704}
705
706SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000707 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
708 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000709 return SkNEW_ARGS(SkSpecularLightingImageFilter,
710 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711}
712
713SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000714 const SkPoint3& location, const SkPoint3& target,
715 SkScalar specularExponent, SkScalar cutoffAngle,
716 SkColor lightColor, SkScalar surfaceScale,
717 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000718 return SkNEW_ARGS(SkSpecularLightingImageFilter,
719 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
720 surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000721}
722
723SkLightingImageFilter::~SkLightingImageFilter() {
724 fLight->unref();
725}
726
727SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
728 : INHERITED(buffer)
729{
djsollen@google.com08337772012-06-26 14:33:13 +0000730 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 fSurfaceScale = buffer.readScalar();
732}
733
734void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
735 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000736 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000737 buffer.writeScalar(fSurfaceScale);
738}
739
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000740///////////////////////////////////////////////////////////////////////////////
741
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000742SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
743 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000744 fKD(kd)
745{
746}
747
748SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
749 : INHERITED(buffer)
750{
751 fKD = buffer.readScalar();
752}
753
754void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
755 this->INHERITED::flatten(buffer);
756 buffer.writeScalar(fKD);
757}
758
759bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
760 const SkBitmap& src,
761 const SkMatrix&,
762 SkBitmap* dst,
763 SkIPoint*) {
764 if (src.config() != SkBitmap::kARGB_8888_Config) {
765 return false;
766 }
767 SkAutoLockPixels alp(src);
768 if (!src.getPixels()) {
769 return false;
770 }
771 if (src.width() < 2 || src.height() < 2) {
772 return false;
773 }
774 dst->setConfig(src.config(), src.width(), src.height());
775 dst->allocPixels();
776
777 DiffuseLightingType lightingType(fKD);
778 switch (light()->type()) {
779 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000780 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000781 break;
782 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000783 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784 break;
785 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000786 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000787 break;
788 }
789 return true;
790}
791
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000792bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
793 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000794 if (stage) {
795 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000796 *stage = SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light(), scale, kd()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000797 }
798 return true;
799}
800
801///////////////////////////////////////////////////////////////////////////////
802
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000803SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
804 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000805 fKS(ks),
806 fShininess(shininess)
807{
808}
809
810SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
811 : INHERITED(buffer)
812{
813 fKS = buffer.readScalar();
814 fShininess = buffer.readScalar();
815}
816
817void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
818 this->INHERITED::flatten(buffer);
819 buffer.writeScalar(fKS);
820 buffer.writeScalar(fShininess);
821}
822
823bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
824 const SkBitmap& src,
825 const SkMatrix&,
826 SkBitmap* dst,
827 SkIPoint*) {
828 if (src.config() != SkBitmap::kARGB_8888_Config) {
829 return false;
830 }
831 SkAutoLockPixels alp(src);
832 if (!src.getPixels()) {
833 return false;
834 }
835 if (src.width() < 2 || src.height() < 2) {
836 return false;
837 }
838 dst->setConfig(src.config(), src.width(), src.height());
839 dst->allocPixels();
840
841 SpecularLightingType lightingType(fKS, fShininess);
842 switch (light()->type()) {
843 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000844 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000845 break;
846 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000847 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848 break;
849 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000850 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851 break;
852 }
853 return true;
854}
855
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000856bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
857 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000858 if (stage) {
859 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000860 *stage = SkNEW_ARGS(GrSpecularLightingEffect, (texture, light(), scale, ks(), shininess()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000861 }
862 return true;
863}
864
865///////////////////////////////////////////////////////////////////////////////
866
867class GrGLLightingEffect : public GrGLProgramStage {
868public:
869 GrGLLightingEffect(const GrProgramStageFactory& factory,
870 const GrCustomStage& stage);
871 virtual ~GrGLLightingEffect();
872
bsalomon@google.com032b2212012-07-16 13:36:18 +0000873 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000874 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000875 virtual void emitVS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000876 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000877 virtual void emitFS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000878 const char* outputColor,
879 const char* inputColor,
880 const char* samplerName) SK_OVERRIDE;
881
bsalomon@google.com032b2212012-07-16 13:36:18 +0000882 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000883
884 static inline StageKey GenKey(const GrCustomStage& s);
885
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000886 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000887 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000888 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000889 int stageNum) SK_OVERRIDE;
890
891private:
892 typedef GrGLProgramStage INHERITED;
893
bsalomon@google.com032b2212012-07-16 13:36:18 +0000894 UniformHandle fImageIncrementUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000895 UniformHandle fSurfaceScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000896 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000897};
898
899///////////////////////////////////////////////////////////////////////////////
900
901class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
902public:
903 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
904 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000905 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000906 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000907 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000908 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000909 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000910 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000911 int stageNum) SK_OVERRIDE;
912
913private:
914 typedef GrGLLightingEffect INHERITED;
915
bsalomon@google.com032b2212012-07-16 13:36:18 +0000916 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000917};
918
919///////////////////////////////////////////////////////////////////////////////
920
921class GrGLSpecularLightingEffect : public GrGLLightingEffect {
922public:
923 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
924 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000925 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000926 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000927 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000928 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000929 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000930 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000931 int stageNum) SK_OVERRIDE;
932
933private:
934 typedef GrGLLightingEffect INHERITED;
935
bsalomon@google.com032b2212012-07-16 13:36:18 +0000936 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000937 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000938};
939
940///////////////////////////////////////////////////////////////////////////////
941
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000942GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
943 : GrSingleTextureEffect(texture)
944 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000945 , fSurfaceScale(surfaceScale) {
946 fLight->ref();
947}
948
949GrLightingEffect::~GrLightingEffect() {
950 fLight->unref();
951}
952
953bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
954 const GrLightingEffect& s =
955 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000956 return INHERITED::isEqual(sBase) &&
957 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000958 fSurfaceScale == s.fSurfaceScale;
959}
960
961///////////////////////////////////////////////////////////////////////////////
962
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000963GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
964 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000965}
966
967const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
968 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
969}
970
971bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
972 const GrDiffuseLightingEffect& s =
973 static_cast<const GrDiffuseLightingEffect&>(sBase);
974 return INHERITED::isEqual(sBase) &&
975 this->kd() == s.kd();
976}
977
978///////////////////////////////////////////////////////////////////////////////
979
980GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
981 const GrCustomStage& stage)
982 : GrGLProgramStage(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000983 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000984 , fSurfaceScaleUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000985 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
986 fLight = m.light()->createGLLight();
987}
988
989GrGLLightingEffect::~GrGLLightingEffect() {
990 delete fLight;
991}
992
bsalomon@google.com032b2212012-07-16 13:36:18 +0000993void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
994 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
995 kVec2f_GrSLType,
996 "uImageIncrement", stage);
997 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
998 kFloat_GrSLType,
999 "uSurfaceScale", stage);
1000 fLight->setupVariables(builder, stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001001}
1002
bsalomon@google.com032b2212012-07-16 13:36:18 +00001003void GrGLLightingEffect::emitVS(GrGLShaderBuilder* builder,
1004 const char* vertexCoords) {
1005 fLight->emitVS(&builder->fVSCode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001006}
1007
bsalomon@google.com032b2212012-07-16 13:36:18 +00001008void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
1009 const char* outputColor,
1010 const char* inputColor,
1011 const char* samplerName) {
1012 SkString* code = &builder->fFSCode;
1013 SkString* funcs = &builder->fFSFunctions;
1014 fLight->emitFuncs(builder, funcs);
1015 this->emitLightFunc(builder, funcs);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001016 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 +00001017 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001018 funcs->appendf("}\n");
1019 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1020 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1021 funcs->appendf("}\n");
1022 funcs->append("\n\
1023vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1024 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1025 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1026 surfaceScale);\n}\n");
1027
bsalomon@google.com032b2212012-07-16 13:36:18 +00001028 code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001029 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001030
1031 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1032 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1033
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001034 int index = 0;
1035 for (int dy = -1; dy <= 1; dy++) {
1036 for (int dx = -1; dx <= 1; dx++) {
1037 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001038 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001039 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001040 builder->emitTextureLookup(samplerName, texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001041 code->appendf(".a;\n");
1042 }
1043 }
1044 code->appendf("\t\tvec3 surfaceToLight = ");
1045 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001046 arg.appendf("%s * m[4]", surfScale);
1047 fLight->emitSurfaceToLight(builder, code, arg.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001048 code->appendf(";\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001049 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
1050 fLight->emitLightColor(builder, code, "surfaceToLight");
1051 code->appendf(")%s;\n", builder->fModulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001052}
1053
1054GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1055 const GrCustomStage& s) {
1056 return static_cast<const GrLightingEffect&>(s).light()->type();
1057}
1058
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001059void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001060 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001061 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001062 int stageNum) {
1063 const GrLightingEffect& effect =
1064 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001065 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1066 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001067 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1068 uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
1069 fLight->setData(uman, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001070}
1071
1072///////////////////////////////////////////////////////////////////////////////
1073
1074///////////////////////////////////////////////////////////////////////////////
1075
1076GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1077 const GrCustomStage& stage)
1078 : INHERITED(factory, stage)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001079 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001080}
1081
bsalomon@google.com032b2212012-07-16 13:36:18 +00001082void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1083 INHERITED::setupVariables(builder, stage);
1084 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "uKD",
1085 stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001086}
1087
bsalomon@google.com032b2212012-07-16 13:36:18 +00001088void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
1089 const char* kd = builder->getUniformCStr(fKDUni);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001090 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001091 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001092 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001093 funcs->appendf("}\n");
1094}
1095
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001096void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001097 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001098 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001099 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001100 INHERITED::setData(uman, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001101 const GrDiffuseLightingEffect& effect =
1102 static_cast<const GrDiffuseLightingEffect&>(data);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001103 uman.set1f(fKDUni, effect.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001104}
1105
1106///////////////////////////////////////////////////////////////////////////////
1107
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001108GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1109 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001110 fKS(ks),
1111 fShininess(shininess) {
1112}
1113
1114const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1115 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1116}
1117
1118bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1119 const GrSpecularLightingEffect& s =
1120 static_cast<const GrSpecularLightingEffect&>(sBase);
1121 return INHERITED::isEqual(sBase) &&
1122 this->ks() == s.ks() &&
1123 this->shininess() == s.shininess();
1124}
1125
1126///////////////////////////////////////////////////////////////////////////////
1127
1128GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1129 const GrCustomStage& stage)
1130 : GrGLLightingEffect(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001131 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001132 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001133}
1134
bsalomon@google.com032b2212012-07-16 13:36:18 +00001135void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1136 INHERITED::setupVariables(builder, stage);
1137 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1138 kFloat_GrSLType, "uKS", stage);
1139 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1140 kFloat_GrSLType, "uShininess", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001141}
1142
bsalomon@google.com032b2212012-07-16 13:36:18 +00001143void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001144 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1145 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1146
bsalomon@google.com032b2212012-07-16 13:36:18 +00001147 const char* ks = builder->getUniformCStr(fKSUni);
1148 const char* shininess = builder->getUniformCStr(fShininessUni);
1149 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
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
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001154void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001155 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001156 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001157 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001158 INHERITED::setData(uman, data, rt, stageNum);
1159 const GrSpecularLightingEffect& effect = static_cast<const GrSpecularLightingEffect&>(data);
1160 uman.set1f(fKSUni, effect.ks());
1161 uman.set1f(fShininessUni, effect.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001162}
1163
1164///////////////////////////////////////////////////////////////////////////////
1165
bsalomon@google.com032b2212012-07-16 13:36:18 +00001166void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
1167 SkString* out,
1168 const char *surfaceToLight) const {
1169 const char* color = builder->getUniformCStr(fColorUni);
1170 out->append(color);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001171}
1172
bsalomon@google.com032b2212012-07-16 13:36:18 +00001173void GrGLLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001174 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1175 kVec3f_GrSLType, "uLightColor", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001176}
1177
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001178void GrGLLight::setData(const GrGLUniformManager& uman,
1179 const GrRenderTarget* rt,
1180 const SkLight* light) const {
1181 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001182}
1183
1184GrGLLight* SkDistantLight::createGLLight() const {
tomhudson@google.com300f5622012-07-20 14:15:22 +00001185 return SkNEW(GrGLDistantLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001186}
1187
1188///////////////////////////////////////////////////////////////////////////////
1189
bsalomon@google.com032b2212012-07-16 13:36:18 +00001190void GrGLDistantLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1191 INHERITED::setupVariables(builder, stage);
1192 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1193 "uLightDirection", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194}
1195
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001196void GrGLDistantLight::setData(const GrGLUniformManager& uman,
1197 const GrRenderTarget* rt,
1198 const SkLight* light) const {
1199 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001200 SkASSERT(light->type() == SkLight::kDistant_LightType);
1201 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001202 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001203}
1204
bsalomon@google.com032b2212012-07-16 13:36:18 +00001205void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1206 SkString* out,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001207 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001208 const char* dir = builder->getUniformCStr(fDirectionUni);
1209 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001210}
1211
1212///////////////////////////////////////////////////////////////////////////////
1213
bsalomon@google.com032b2212012-07-16 13:36:18 +00001214void GrGLPointLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1215 INHERITED::setupVariables(builder, stage);
1216 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1217 "uLightLocation", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001218}
1219
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001220void GrGLPointLight::setData(const GrGLUniformManager& uman,
1221 const GrRenderTarget* rt,
1222 const SkLight* light) const {
1223 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001224 SkASSERT(light->type() == SkLight::kPoint_LightType);
1225 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001226 setUniformPoint3FlipY(uman, fLocationUni, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001227}
1228
bsalomon@google.com032b2212012-07-16 13:36:18 +00001229void GrGLPointLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001230}
1231
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001232void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1233 SkString* out,
1234 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001235 const char* loc = builder->getUniformCStr(fLocationUni);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001236 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001237}
1238
1239///////////////////////////////////////////////////////////////////////////////
1240
bsalomon@google.com032b2212012-07-16 13:36:18 +00001241void GrGLSpotLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1242 INHERITED::setupVariables(builder, stage);
1243 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1244 kVec3f_GrSLType, "uLightLocation", stage);
1245 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1246 kFloat_GrSLType, "uExponent", stage);
1247 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1248 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1249 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1250 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1251 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1252 kFloat_GrSLType, "uConeScale", stage);
1253 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1254 kVec3f_GrSLType, "uS", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001255}
1256
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001257void GrGLSpotLight::setData(const GrGLUniformManager& uman,
1258 const GrRenderTarget* rt,
1259 const SkLight* light) const {
1260 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001261 SkASSERT(light->type() == SkLight::kSpot_LightType);
1262 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001263 setUniformPoint3FlipY(uman, fLocationUni, spotLight->location(), rt->height());
1264 uman.set1f(fExponentUni, spotLight->specularExponent());
1265 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1266 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1267 uman.set1f(fConeScaleUni, spotLight->coneScale());
1268 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001269}
1270
bsalomon@google.com032b2212012-07-16 13:36:18 +00001271void GrGLSpotLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001272}
1273
bsalomon@google.com032b2212012-07-16 13:36:18 +00001274void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
1275 const char* exponent = builder->getUniformCStr(fExponentUni);
1276 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1277 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1278 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1279 const char* s = builder->getUniformCStr(fSUni);
1280 const char* color = builder->getUniformCStr(fColorUni);
1281
1282 out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1283 out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1284 out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
1285 out->appendf("\t\treturn vec3(0);\n");
1286 out->appendf("\t}\n");
1287 out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1288 out->appendf("\tif (cosAngle < %s) {\n", cosInner);
1289 out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
1290 out->appendf("\t}\n");
1291 out->appendf("\treturn %s;\n", color);
1292 out->appendf("}\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001293}
1294
bsalomon@google.com032b2212012-07-16 13:36:18 +00001295void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1296 SkString* out,
1297 const char* z) const {
1298 const char* location= builder->getUniformCStr(fLocationUni);
1299 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001300}
1301
bsalomon@google.com032b2212012-07-16 13:36:18 +00001302void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
1303 SkString* out, const char *surfaceToLight) const {
1304 out->appendf("lightColor(%s)", surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001305}
1306
djsollen@google.com08337772012-06-26 14:33:13 +00001307SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1308 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1309 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1310 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1311 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1312 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1313SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END