blob: 0aa90eff9015f42b043b648441fc6e53fa1f64bd [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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkFlattenableBuffers.h"
12#include "SkOrderedReadBuffer.h"
13#include "SkOrderedWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000015
16#if SK_SUPPORT_GPU
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000017#include "effects/GrSingleTextureEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000018#include "gl/GrGLEffect.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000019#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000020#include "GrTBackendEffectFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000021
22class GrGLDiffuseLightingEffect;
23class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000024
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000025// For brevity
26typedef GrGLUniformManager::UniformHandle UniformHandle;
27static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000028#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000029
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000030namespace {
31
32const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
33const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
34const SkScalar gOneHalf = SkFloatToScalar(0.5f);
35const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
36
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000037#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000038void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000039 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000040 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000041}
42
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000043void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000044 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000045}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000046#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000047
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.org254eae22012-10-05 17:38:00 +0000262 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
263 SkScalar kd, SkImageFilter* input);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
265
bsalomon@google.com021fc732012-10-25 12:47:42 +0000266 virtual bool asNewEffect(GrEffect** effect, 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.org254eae22012-10-05 17:38:00 +0000283 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000284 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
285
bsalomon@google.com021fc732012-10-25 12:47:42 +0000286 virtual bool asNewEffect(GrEffect** effect, 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
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000302#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000303
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000304class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000305public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000306 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000307 virtual ~GrLightingEffect();
308
bsalomon@google.coma469c282012-10-24 18:28:34 +0000309 virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000310
311 const SkLight* light() const { return fLight; }
312 SkScalar surfaceScale() const { return fSurfaceScale; }
313private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000314 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000315 const SkLight* fLight;
316 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000317};
318
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000319class GrDiffuseLightingEffect : public GrLightingEffect {
320public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000321 GrDiffuseLightingEffect(GrTexture* texture,
322 const SkLight* light,
323 SkScalar surfaceScale,
324 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000325
326 static const char* Name() { return "DiffuseLighting"; }
327
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000328 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000329
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000330 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
bsalomon@google.coma469c282012-10-24 18:28:34 +0000331 virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000332 SkScalar kd() const { return fKD; }
333private:
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000334 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000335 typedef GrLightingEffect INHERITED;
336 SkScalar fKD;
337};
338
339class GrSpecularLightingEffect : public GrLightingEffect {
340public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000341 GrSpecularLightingEffect(GrTexture* texture,
342 const SkLight* light,
343 SkScalar surfaceScale,
344 SkScalar ks,
345 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000346
347 static const char* Name() { return "SpecularLighting"; }
348
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000349 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000350
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000351 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
bsalomon@google.coma469c282012-10-24 18:28:34 +0000352 virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000353 SkScalar ks() const { return fKS; }
354 SkScalar shininess() const { return fShininess; }
355
356private:
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000357 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000358 typedef GrLightingEffect INHERITED;
359 SkScalar fKS;
360 SkScalar fShininess;
361};
362
363///////////////////////////////////////////////////////////////////////////////
364
365class GrGLLight {
366public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000367 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000368
369 /**
370 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
371 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
372 */
373 void emitLightColorUniform(GrGLShaderBuilder*);
374
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000375 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000376 * These two functions are called from GrGLLightingEffect's emitCode() function.
377 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
378 * the light. The expression will be used in the FS. emitLightColor writes an expression into
379 * the FS that is the color of the light. Either function may add functions and/or uniforms to
380 * the FS. The default of emitLightColor appends the name of the constant light color uniform
381 * and so this function only needs to be overridden if the light color varies spatially.
382 */
383 virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) = 0;
384 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
385
386 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
387 // INHERITED::setData().
bsalomon@google.com706f6682012-10-23 14:53:55 +0000388 virtual void setData(const GrGLUniformManager&, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000389
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000390protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000391 /**
392 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
393 * function.
394 */
395 UniformHandle lightColorUni() const { return fColorUni; }
396
397private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000398 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000399
400 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000401};
402
403///////////////////////////////////////////////////////////////////////////////
404
405class GrGLDistantLight : public GrGLLight {
406public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000407 virtual ~GrGLDistantLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000408 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000409 virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000410private:
411 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000412 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000413};
414
415///////////////////////////////////////////////////////////////////////////////
416
417class GrGLPointLight : public GrGLLight {
418public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000419 virtual ~GrGLPointLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000420 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000421 virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000422private:
423 typedef GrGLLight INHERITED;
424 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000425 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000426};
427
428///////////////////////////////////////////////////////////////////////////////
429
430class GrGLSpotLight : public GrGLLight {
431public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000432 virtual ~GrGLSpotLight() {}
bsalomon@google.com706f6682012-10-23 14:53:55 +0000433 virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000434 virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) SK_OVERRIDE;
435 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000436private:
437 typedef GrGLLight INHERITED;
438
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000439 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000440 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000441 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000442 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000443 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000444 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000445 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000446};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000447#else
448
449class GrGLLight;
450
451#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000452
453};
454
455///////////////////////////////////////////////////////////////////////////////
456
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000457class SkLight : public SkFlattenable {
458public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000459 SK_DECLARE_INST_COUNT(SkLight)
460
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461 enum LightType {
462 kDistant_LightType,
463 kPoint_LightType,
464 kSpot_LightType,
465 };
466 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000467 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000468 virtual GrGLLight* createGLLight() const = 0;
469 virtual bool isEqual(const SkLight& other) const {
470 return fColor == other.fColor;
471 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000472
djsollen@google.com08337772012-06-26 14:33:13 +0000473protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000474 SkLight(SkColor color)
475 : fColor(SkIntToScalar(SkColorGetR(color)),
476 SkIntToScalar(SkColorGetG(color)),
477 SkIntToScalar(SkColorGetB(color))) {}
478 SkLight(SkFlattenableReadBuffer& buffer)
479 : INHERITED(buffer) {
480 fColor = readPoint3(buffer);
481 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000482 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000483 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000484 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485 }
djsollen@google.com08337772012-06-26 14:33:13 +0000486
487private:
488 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000489 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000490};
491
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000492SK_DEFINE_INST_COUNT(SkLight)
493
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494///////////////////////////////////////////////////////////////////////////////
495
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000496class SkDistantLight : public SkLight {
497public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000498 SkDistantLight(const SkPoint3& direction, SkColor color)
499 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000500 }
djsollen@google.com08337772012-06-26 14:33:13 +0000501
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000502 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
503 return fDirection;
504 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000505 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000506 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000507 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000508 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
509#if SK_SUPPORT_GPU
510 return SkNEW(GrGLDistantLight);
511#else
512 SkDEBUGFAIL("Should not call in GPU-less build");
513 return NULL;
514#endif
515 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000516 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
517 if (other.type() != kDistant_LightType) {
518 return false;
519 }
520
521 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
522 return INHERITED::isEqual(other) &&
523 fDirection == o.fDirection;
524 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525
526 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
527
djsollen@google.com08337772012-06-26 14:33:13 +0000528protected:
529 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
530 fDirection = readPoint3(buffer);
531 }
532 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
533 INHERITED::flatten(buffer);
534 writePoint3(fDirection, buffer);
535 }
536
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000537private:
djsollen@google.com08337772012-06-26 14:33:13 +0000538 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539 SkPoint3 fDirection;
540};
541
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000542///////////////////////////////////////////////////////////////////////////////
543
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000544class SkPointLight : public SkLight {
545public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000546 SkPointLight(const SkPoint3& location, SkColor color)
547 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000548
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000549 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
550 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
551 fLocation.fY - SkIntToScalar(y),
552 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
553 direction.normalize();
554 return direction;
555 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000556 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000557 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000558 const SkPoint3& location() const { return fLocation; }
559 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000560#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000561 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000562#else
563 SkDEBUGFAIL("Should not call in GPU-less build");
564 return NULL;
565#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000567 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000568 if (other.type() != kPoint_LightType) {
569 return false;
570 }
571 const SkPointLight& o = static_cast<const SkPointLight&>(other);
572 return INHERITED::isEqual(other) &&
573 fLocation == o.fLocation;
574 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000575
576 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
577
djsollen@google.com08337772012-06-26 14:33:13 +0000578protected:
579 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
580 fLocation = readPoint3(buffer);
581 }
582 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
583 INHERITED::flatten(buffer);
584 writePoint3(fLocation, buffer);
585 }
586
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587private:
djsollen@google.com08337772012-06-26 14:33:13 +0000588 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589 SkPoint3 fLocation;
590};
591
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000592///////////////////////////////////////////////////////////////////////////////
593
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000594class SkSpotLight : public SkLight {
595public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000596 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
597 : INHERITED(color),
598 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000599 fTarget(target),
600 fSpecularExponent(specularExponent)
601 {
602 fS = target - location;
603 fS.normalize();
604 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
605 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
606 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
607 fConeScale = SkScalarInvert(antiAliasThreshold);
608 }
djsollen@google.com08337772012-06-26 14:33:13 +0000609
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000610 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
611 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
612 fLocation.fY - SkIntToScalar(y),
613 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
614 direction.normalize();
615 return direction;
616 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000617 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618 SkScalar cosAngle = -surfaceToLight.dot(fS);
619 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000620 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000621 }
622 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
623 if (cosAngle < fCosInnerConeAngle) {
624 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000625 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000626 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000627 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000628 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000629 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000630#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000631 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000632#else
633 SkDEBUGFAIL("Should not call in GPU-less build");
634 return NULL;
635#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000636 }
djsollen@google.com08337772012-06-26 14:33:13 +0000637 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638 const SkPoint3& location() const { return fLocation; }
639 const SkPoint3& target() const { return fTarget; }
640 SkScalar specularExponent() const { return fSpecularExponent; }
641 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
642 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
643 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000644 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000645
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000646 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
647
djsollen@google.com08337772012-06-26 14:33:13 +0000648protected:
649 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
650 fLocation = readPoint3(buffer);
651 fTarget = readPoint3(buffer);
652 fSpecularExponent = buffer.readScalar();
653 fCosOuterConeAngle = buffer.readScalar();
654 fCosInnerConeAngle = buffer.readScalar();
655 fConeScale = buffer.readScalar();
656 fS = readPoint3(buffer);
657 }
658 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
659 INHERITED::flatten(buffer);
660 writePoint3(fLocation, buffer);
661 writePoint3(fTarget, buffer);
662 buffer.writeScalar(fSpecularExponent);
663 buffer.writeScalar(fCosOuterConeAngle);
664 buffer.writeScalar(fCosInnerConeAngle);
665 buffer.writeScalar(fConeScale);
666 writePoint3(fS, buffer);
667 }
668
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000669 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000670 if (other.type() != kSpot_LightType) {
671 return false;
672 }
673
674 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
675 return INHERITED::isEqual(other) &&
676 fLocation == o.fLocation &&
677 fTarget == o.fTarget &&
678 fSpecularExponent == o.fSpecularExponent &&
679 fCosOuterConeAngle == o.fCosOuterConeAngle;
680 }
681
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000682private:
djsollen@google.com08337772012-06-26 14:33:13 +0000683 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000684 SkPoint3 fLocation;
685 SkPoint3 fTarget;
686 SkScalar fSpecularExponent;
687 SkScalar fCosOuterConeAngle;
688 SkScalar fCosInnerConeAngle;
689 SkScalar fConeScale;
690 SkPoint3 fS;
691};
692
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000693///////////////////////////////////////////////////////////////////////////////
694
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000695SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input)
696 : INHERITED(input),
697 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
699{
700 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000701 // our caller knows that we take ownership of the light, so we don't
702 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703}
704
705SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000706 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000707 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000708 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000709 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
710 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711}
712
713SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000714 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000715 SkScalar kd, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000716 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000717 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
718 input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000719}
720
721SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000722 const SkPoint3& location, const SkPoint3& target,
723 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000724 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
725 SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000726 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000727 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
728 cutoffAngle, lightColor)),
729 surfaceScale, kd, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000730}
731
732SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000733 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000734 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000735 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000736 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
737 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738}
739
740SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000742 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000743 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000744 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
745 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000746}
747
748SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000749 const SkPoint3& location, const SkPoint3& target,
750 SkScalar specularExponent, SkScalar cutoffAngle,
751 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000752 SkScalar ks, SkScalar shininess, SkImageFilter* input) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000753 return SkNEW_ARGS(SkSpecularLightingImageFilter,
754 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000755 surfaceScale, ks, shininess, input));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000756}
757
758SkLightingImageFilter::~SkLightingImageFilter() {
759 fLight->unref();
760}
761
762SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
763 : INHERITED(buffer)
764{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000765 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000766 fSurfaceScale = buffer.readScalar();
767}
768
769void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
770 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000771 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000772 buffer.writeScalar(fSurfaceScale);
773}
774
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000775///////////////////////////////////////////////////////////////////////////////
776
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000777SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input)
778 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779 fKD(kd)
780{
781}
782
783SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
784 : INHERITED(buffer)
785{
786 fKD = buffer.readScalar();
787}
788
789void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
790 this->INHERITED::flatten(buffer);
791 buffer.writeScalar(fKD);
792}
793
794bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
795 const SkBitmap& src,
796 const SkMatrix&,
797 SkBitmap* dst,
798 SkIPoint*) {
799 if (src.config() != SkBitmap::kARGB_8888_Config) {
800 return false;
801 }
802 SkAutoLockPixels alp(src);
803 if (!src.getPixels()) {
804 return false;
805 }
806 if (src.width() < 2 || src.height() < 2) {
807 return false;
808 }
809 dst->setConfig(src.config(), src.width(), src.height());
810 dst->allocPixels();
811
812 DiffuseLightingType lightingType(fKD);
813 switch (light()->type()) {
814 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000815 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000816 break;
817 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000818 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000819 break;
820 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000821 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000822 break;
823 }
824 return true;
825}
826
bsalomon@google.com021fc732012-10-25 12:47:42 +0000827bool SkDiffuseLightingImageFilter::asNewEffect(GrEffect** effect,
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000828 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000829#if SK_SUPPORT_GPU
bsalomon@google.com021fc732012-10-25 12:47:42 +0000830 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000831 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com021fc732012-10-25 12:47:42 +0000832 *effect = SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light(), scale, kd()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000833 }
834 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000835#else
836 SkDEBUGFAIL("Should not call in GPU-less build");
837 return false;
838#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000839}
840
841///////////////////////////////////////////////////////////////////////////////
842
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000843SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input)
844 : SkLightingImageFilter(light, surfaceScale, input),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000845 fKS(ks),
846 fShininess(shininess)
847{
848}
849
850SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
851 : INHERITED(buffer)
852{
853 fKS = buffer.readScalar();
854 fShininess = buffer.readScalar();
855}
856
857void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
858 this->INHERITED::flatten(buffer);
859 buffer.writeScalar(fKS);
860 buffer.writeScalar(fShininess);
861}
862
863bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
864 const SkBitmap& src,
865 const SkMatrix&,
866 SkBitmap* dst,
867 SkIPoint*) {
868 if (src.config() != SkBitmap::kARGB_8888_Config) {
869 return false;
870 }
871 SkAutoLockPixels alp(src);
872 if (!src.getPixels()) {
873 return false;
874 }
875 if (src.width() < 2 || src.height() < 2) {
876 return false;
877 }
878 dst->setConfig(src.config(), src.width(), src.height());
879 dst->allocPixels();
880
881 SpecularLightingType lightingType(fKS, fShininess);
882 switch (light()->type()) {
883 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000884 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000885 break;
886 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000887 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000888 break;
889 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000890 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000891 break;
892 }
893 return true;
894}
895
bsalomon@google.com021fc732012-10-25 12:47:42 +0000896bool SkSpecularLightingImageFilter::asNewEffect(GrEffect** effect,
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000897 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000898#if SK_SUPPORT_GPU
bsalomon@google.com021fc732012-10-25 12:47:42 +0000899 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000900 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
bsalomon@google.com021fc732012-10-25 12:47:42 +0000901 *effect = SkNEW_ARGS(GrSpecularLightingEffect, (texture, light(), scale, ks(), shininess()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000902 }
903 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000904#else
905 SkDEBUGFAIL("Should not call in GPU-less build");
906 return false;
907#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000908}
909
910///////////////////////////////////////////////////////////////////////////////
911
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000912#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000913
914namespace {
915SkPoint3 random_point3(SkRandom* random) {
916 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
917 SkScalarToFloat(random->nextSScalar1()),
918 SkScalarToFloat(random->nextSScalar1()));
919}
920
921SkLight* create_random_light(SkRandom* random) {
922 int type = random->nextULessThan(3);
923 switch (type) {
924 case 0: {
925 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
926 }
927 case 1: {
928 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
929 }
930 case 2: {
931 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
932 random_point3(random),
933 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000934 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000935 random->nextU()));
936 }
937 default:
938 GrCrash();
939 return NULL;
940 }
941}
942
943}
944
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000945class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000946public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000947 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +0000948 const GrEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000949 virtual ~GrGLLightingEffect();
950
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000951 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000952 const GrEffectStage&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000953 EffectKey,
954 const char* vertexCoords,
955 const char* outputColor,
956 const char* inputColor,
957 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000958
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000959 static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000960
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000961 /**
962 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
963 */
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000964 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000965
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000966protected:
967 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
968
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000969private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000970 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000971
bsalomon@google.com032b2212012-07-16 13:36:18 +0000972 UniformHandle fImageIncrementUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000973 UniformHandle fSurfaceScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000974 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000975};
976
977///////////////////////////////////////////////////////////////////////////////
978
979class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
980public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000981 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +0000982 const GrEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000983 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000984 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000985
986private:
987 typedef GrGLLightingEffect INHERITED;
988
bsalomon@google.com032b2212012-07-16 13:36:18 +0000989 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000990};
991
992///////////////////////////////////////////////////////////////////////////////
993
994class GrGLSpecularLightingEffect : public GrGLLightingEffect {
995public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000996 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +0000997 const GrEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000998 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000999 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000
1001private:
1002 typedef GrGLLightingEffect INHERITED;
1003
bsalomon@google.com032b2212012-07-16 13:36:18 +00001004 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001005 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001006};
1007
1008///////////////////////////////////////////////////////////////////////////////
1009
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001010GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
1011 : GrSingleTextureEffect(texture)
1012 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001013 , fSurfaceScale(surfaceScale) {
1014 fLight->ref();
1015}
1016
1017GrLightingEffect::~GrLightingEffect() {
1018 fLight->unref();
1019}
1020
bsalomon@google.coma469c282012-10-24 18:28:34 +00001021bool GrLightingEffect::isEqual(const GrEffect& sBase) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001022 const GrLightingEffect& s =
1023 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001024 return INHERITED::isEqual(sBase) &&
1025 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001026 fSurfaceScale == s.fSurfaceScale;
1027}
1028
1029///////////////////////////////////////////////////////////////////////////////
1030
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001031GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1032 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001033}
1034
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001035const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1036 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001037}
1038
bsalomon@google.coma469c282012-10-24 18:28:34 +00001039bool GrDiffuseLightingEffect::isEqual(const GrEffect& sBase) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001040 const GrDiffuseLightingEffect& s =
1041 static_cast<const GrDiffuseLightingEffect&>(sBase);
1042 return INHERITED::isEqual(sBase) &&
1043 this->kd() == s.kd();
1044}
1045
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001046GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001047
bsalomon@google.coma469c282012-10-24 18:28:34 +00001048GrEffect* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1049 GrContext* context,
1050 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001051 SkScalar surfaceScale = random->nextSScalar1();
1052 SkScalar kd = random->nextUScalar1();
1053 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com6f261be2012-10-24 19:07:10 +00001054 return SkNEW_ARGS(GrDiffuseLightingEffect, (textures[GrEffectUnitTest::kAlphaTextureIdx],
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001055 light, surfaceScale, kd));
1056}
1057
1058
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001059///////////////////////////////////////////////////////////////////////////////
1060
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001061GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +00001062 const GrEffect& effect)
bsalomon@google.com374e7592012-10-23 17:30:45 +00001063 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001064 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001065 , fSurfaceScaleUni(kInvalidUniformHandle) {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001066 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001067 fLight = m.light()->createGLLight();
1068}
1069
1070GrGLLightingEffect::~GrGLLightingEffect() {
1071 delete fLight;
1072}
1073
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001074void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001075 const GrEffectStage&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001076 EffectKey,
1077 const char* vertexCoords,
1078 const char* outputColor,
1079 const char* inputColor,
1080 const TextureSamplerArray& samplers) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001081 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1082 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001083 "ImageIncrement");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001084 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1085 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001086 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001087 fLight->emitLightColorUniform(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001088 SkString* code = &builder->fFSCode;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001089 SkString lightFunc;
1090 this->emitLightFunc(builder, &lightFunc);
1091 static const GrGLShaderVar gSobelArgs[] = {
1092 GrGLShaderVar("a", kFloat_GrSLType),
1093 GrGLShaderVar("b", kFloat_GrSLType),
1094 GrGLShaderVar("c", kFloat_GrSLType),
1095 GrGLShaderVar("d", kFloat_GrSLType),
1096 GrGLShaderVar("e", kFloat_GrSLType),
1097 GrGLShaderVar("f", kFloat_GrSLType),
1098 GrGLShaderVar("scale", kFloat_GrSLType),
1099 };
1100 SkString sobelFuncName;
1101 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1102 kFloat_GrSLType,
1103 "sobel",
1104 SK_ARRAY_COUNT(gSobelArgs),
1105 gSobelArgs,
1106 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1107 &sobelFuncName);
1108 static const GrGLShaderVar gPointToNormalArgs[] = {
1109 GrGLShaderVar("x", kFloat_GrSLType),
1110 GrGLShaderVar("y", kFloat_GrSLType),
1111 GrGLShaderVar("scale", kFloat_GrSLType),
1112 };
1113 SkString pointToNormalName;
1114 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1115 kVec3f_GrSLType,
1116 "pointToNormal",
1117 SK_ARRAY_COUNT(gPointToNormalArgs),
1118 gPointToNormalArgs,
bsalomon@google.com706f6682012-10-23 14:53:55 +00001119 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001120 &pointToNormalName);
1121
1122 static const GrGLShaderVar gInteriorNormalArgs[] = {
1123 GrGLShaderVar("m", kFloat_GrSLType, 9),
1124 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1125 };
1126 SkString interiorNormalBody;
1127 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1128 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1129 "\t surfaceScale);\n",
1130 pointToNormalName.c_str(),
1131 sobelFuncName.c_str(),
1132 sobelFuncName.c_str());
1133 SkString interiorNormalName;
1134 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1135 kVec3f_GrSLType,
1136 "interiorNormal",
1137 SK_ARRAY_COUNT(gInteriorNormalArgs),
1138 gInteriorNormalArgs,
1139 interiorNormalBody.c_str(),
1140 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001141
bsalomon@google.com34bcb9f2012-08-28 18:20:18 +00001142 code->appendf("\t\tvec2 coord = %s;\n", builder->defaultTexCoordsName());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001143 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001144
1145 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1146 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1147
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001148 int index = 0;
1149 for (int dy = -1; dy <= 1; dy++) {
1150 for (int dx = -1; dx <= 1; dx++) {
1151 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001152 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001153 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +00001154 builder->appendTextureLookup(code, samplers[0], texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001155 code->appendf(".a;\n");
1156 }
1157 }
1158 code->appendf("\t\tvec3 surfaceToLight = ");
1159 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001160 arg.appendf("%s * m[4]", surfScale);
1161 fLight->emitSurfaceToLight(builder, code, arg.c_str());
bsalomon@google.com868a8e72012-08-30 19:11:34 +00001162 code->append(";\n");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001163 code->appendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1164 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
1165 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.com868a8e72012-08-30 19:11:34 +00001166 code->append(");\n");
1167 GrGLSLMulVarBy4f(code, 2, outputColor, inputColor);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001168}
1169
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001170GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrEffectStage& s,
1171 const GrGLCaps& caps) {
1172 return static_cast<const GrLightingEffect&>(*s.getEffect()).light()->type();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001173}
1174
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001175void GrGLLightingEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
1176 const GrLightingEffect& effect =static_cast<const GrLightingEffect&>(*stage.getEffect());
bsalomon@google.com2d0bade2012-10-26 19:01:17 +00001177 GrTexture* texture = effect.texture(0);
1178 float ySign = texture->origin() == GrSurface::kTopLeft_Origin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001179 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1180 uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
bsalomon@google.com706f6682012-10-23 14:53:55 +00001181 fLight->setData(uman, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001182}
1183
1184///////////////////////////////////////////////////////////////////////////////
1185
1186///////////////////////////////////////////////////////////////////////////////
1187
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001188GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +00001189 const GrEffect& effect)
1190 : INHERITED(factory, effect)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001191 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001192}
1193
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001194void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001195 const char* kd;
1196 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1197 kFloat_GrSLType,
1198 "KD",
1199 &kd);
1200
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001201 static const GrGLShaderVar gLightArgs[] = {
1202 GrGLShaderVar("normal", kVec3f_GrSLType),
1203 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1204 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1205 };
1206 SkString lightBody;
1207 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1208 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1209 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1210 kVec4f_GrSLType,
1211 "light",
1212 SK_ARRAY_COUNT(gLightArgs),
1213 gLightArgs,
1214 lightBody.c_str(),
1215 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001216}
1217
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001218void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
1219 const GrEffectStage& stage) {
1220 INHERITED::setData(uman, stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001221 const GrDiffuseLightingEffect& effect =
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001222 static_cast<const GrDiffuseLightingEffect&>(*stage.getEffect());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001223 uman.set1f(fKDUni, effect.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001224}
1225
1226///////////////////////////////////////////////////////////////////////////////
1227
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001228GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1229 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001230 fKS(ks),
1231 fShininess(shininess) {
1232}
1233
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001234const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1235 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001236}
1237
bsalomon@google.coma469c282012-10-24 18:28:34 +00001238bool GrSpecularLightingEffect::isEqual(const GrEffect& sBase) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001239 const GrSpecularLightingEffect& s =
1240 static_cast<const GrSpecularLightingEffect&>(sBase);
1241 return INHERITED::isEqual(sBase) &&
1242 this->ks() == s.ks() &&
1243 this->shininess() == s.shininess();
1244}
1245
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001246GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001247
bsalomon@google.coma469c282012-10-24 18:28:34 +00001248GrEffect* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1249 GrContext* context,
1250 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001251 SkScalar surfaceScale = random->nextSScalar1();
1252 SkScalar ks = random->nextUScalar1();
1253 SkScalar shininess = random->nextUScalar1();
1254 SkAutoTUnref<SkLight> light(create_random_light(random));
bsalomon@google.com6f261be2012-10-24 19:07:10 +00001255 return SkNEW_ARGS(GrSpecularLightingEffect, (textures[GrEffectUnitTest::kAlphaTextureIdx],
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001256 light, surfaceScale, ks, shininess));
1257}
1258
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001259///////////////////////////////////////////////////////////////////////////////
1260
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001261GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +00001262 const GrEffect& effect)
1263 : GrGLLightingEffect(factory, effect)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001264 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001265 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001266}
1267
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001268void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001269 const char* ks;
1270 const char* shininess;
1271
1272 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1273 kFloat_GrSLType, "KS", &ks);
1274 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1275 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001276
1277 static const GrGLShaderVar gLightArgs[] = {
1278 GrGLShaderVar("normal", kVec3f_GrSLType),
1279 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1280 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1281 };
1282 SkString lightBody;
1283 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1284 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001285 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1286 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001287 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1288 kVec4f_GrSLType,
1289 "light",
1290 SK_ARRAY_COUNT(gLightArgs),
1291 gLightArgs,
1292 lightBody.c_str(),
1293 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001294}
1295
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001296void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001297 const GrEffectStage& stage) {
1298 INHERITED::setData(uman, stage);
1299 const GrSpecularLightingEffect& effect =
1300 static_cast<const GrSpecularLightingEffect&>(*stage.getEffect());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001301 uman.set1f(fKSUni, effect.ks());
1302 uman.set1f(fShininessUni, effect.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001303}
1304
1305///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001306void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001307 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001308 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001309}
1310
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001311void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1312 const char *surfaceToLight) {
1313 builder->fFSCode.append(builder->getUniformCStr(this->lightColorUni()));
1314}
1315
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001316void GrGLLight::setData(const GrGLUniformManager& uman,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001317 const SkLight* light) const {
1318 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001319}
1320
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001321///////////////////////////////////////////////////////////////////////////////
1322
bsalomon@google.com706f6682012-10-23 14:53:55 +00001323void GrGLDistantLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
1324 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001325 SkASSERT(light->type() == SkLight::kDistant_LightType);
1326 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001327 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001328}
1329
bsalomon@google.com706f6682012-10-23 14:53:55 +00001330void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001331 SkString* out,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001332 const char* z) {
1333 const char* dir;
1334 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1335 "LightDirection", &dir);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001336 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001337}
1338
1339///////////////////////////////////////////////////////////////////////////////
1340
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001341void GrGLPointLight::setData(const GrGLUniformManager& uman,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001342 const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001343 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001344 SkASSERT(light->type() == SkLight::kPoint_LightType);
1345 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001346 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001347}
1348
bsalomon@google.com706f6682012-10-23 14:53:55 +00001349void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001350 SkString* out,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001351 const char* z) {
1352 const char* loc;
1353 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1354 "LightLocation", &loc);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001355 out->appendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001356}
1357
1358///////////////////////////////////////////////////////////////////////////////
1359
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001360void GrGLSpotLight::setData(const GrGLUniformManager& uman,
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001361 const SkLight* light) const {
bsalomon@google.com706f6682012-10-23 14:53:55 +00001362 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001363 SkASSERT(light->type() == SkLight::kSpot_LightType);
1364 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.com706f6682012-10-23 14:53:55 +00001365 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001366 uman.set1f(fExponentUni, spotLight->specularExponent());
1367 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1368 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1369 uman.set1f(fConeScaleUni, spotLight->coneScale());
1370 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001371}
1372
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001373void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
1374 SkString* out,
1375 const char* z) {
1376 const char* location;
1377 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1378 kVec3f_GrSLType, "LightLocation", &location);
1379 out->appendf("normalize(%s - vec3(%s.xy, %s))", location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001380}
1381
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001382void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1383 const char *surfaceToLight) {
1384
1385 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1386
1387 const char* exponent;
1388 const char* cosInner;
1389 const char* cosOuter;
1390 const char* coneScale;
1391 const char* s;
1392 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1393 kFloat_GrSLType, "Exponent", &exponent);
1394 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1395 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1396 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1397 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1398 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1399 kFloat_GrSLType, "ConeScale", &coneScale);
1400 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1401 kVec3f_GrSLType, "S", &s);
1402
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001403 static const GrGLShaderVar gLightColorArgs[] = {
1404 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1405 };
1406 SkString lightColorBody;
1407 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1408 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1409 lightColorBody.appendf("\t\treturn vec3(0);\n");
1410 lightColorBody.appendf("\t}\n");
1411 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1412 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1413 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1414 color, cosOuter, coneScale);
1415 lightColorBody.appendf("\t}\n");
1416 lightColorBody.appendf("\treturn %s;\n", color);
1417 builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
1418 kVec3f_GrSLType,
1419 "lightColor",
1420 SK_ARRAY_COUNT(gLightColorArgs),
1421 gLightColorArgs,
1422 lightColorBody.c_str(),
1423 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001424
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001425 builder->fFSCode.appendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001426}
1427
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001428#endif
1429
djsollen@google.com08337772012-06-26 14:33:13 +00001430SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1431 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1432 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1433 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1434 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1435 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1436SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END