blob: c590c262e8e63e9117b02e3f05d79878cbf206d6 [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
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000017#include "GrProgramStageFactory.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000018#include "effects/GrSingleTextureEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000019#include "gl/GrGLProgramStage.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000020#include "gl/GrGLTexture.h"
21#include "GrCustomStage.h"
22
23class GrGLDiffuseLightingEffect;
24class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000025
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000026// For brevity
27typedef GrGLUniformManager::UniformHandle UniformHandle;
28static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000029#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000030
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000031namespace {
32
33const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
34const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
35const SkScalar gOneHalf = SkFloatToScalar(0.5f);
36const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
37
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000038#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000039void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000040 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000041 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000042}
43
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000044void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
45 setUniformPoint3(uman, uni, SkPoint3(point.fX, -point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000046}
47
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000048void setUniformPoint3FlipY(const GrGLUniformManager& uman,
49 UniformHandle uni,
50 const SkPoint3& point,
51 int height) {
52 setUniformPoint3(uman, uni, SkPoint3(point.fX, height-point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000053}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000054#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000055
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000056// Shift matrix components to the left, as we advance pixels to the right.
57inline void shiftMatrixLeft(int m[9]) {
58 m[0] = m[1];
59 m[3] = m[4];
60 m[6] = m[7];
61 m[1] = m[2];
62 m[4] = m[5];
63 m[7] = m[8];
64}
65
66class DiffuseLightingType {
67public:
68 DiffuseLightingType(SkScalar kd)
69 : fKD(kd) {}
70 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
71 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
72 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
73 SkPoint3 color(lightColor * colorScale);
74 return SkPackARGB32(255,
75 SkScalarFloorToInt(color.fX),
76 SkScalarFloorToInt(color.fY),
77 SkScalarFloorToInt(color.fZ));
78 }
79private:
80 SkScalar fKD;
81};
82
83class SpecularLightingType {
84public:
85 SpecularLightingType(SkScalar ks, SkScalar shininess)
86 : fKS(ks), fShininess(shininess) {}
87 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
88 SkPoint3 halfDir(surfaceTolight);
89 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
90 halfDir.normalize();
91 SkScalar colorScale = SkScalarMul(fKS,
92 SkScalarPow(normal.dot(halfDir), fShininess));
93 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
94 SkPoint3 color(lightColor * colorScale);
95 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
96 SkScalarFloorToInt(color.fX),
97 SkScalarFloorToInt(color.fY),
98 SkScalarFloorToInt(color.fZ));
99 }
100private:
101 SkScalar fKS;
102 SkScalar fShininess;
103};
104
105inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
106 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
107}
108
109inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
110 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
111 SkScalarMul(-y, surfaceScale),
112 SK_Scalar1);
113 vector.normalize();
114 return vector;
115}
116
117inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
118 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
119 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
120 surfaceScale);
121}
122
123inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
124 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
125 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
126 surfaceScale);
127}
128
129inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
130 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
131 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
132 surfaceScale);
133}
134
135inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
137 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
138 surfaceScale);
139}
140
141
142inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
143 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
144 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
145 surfaceScale);
146}
147
148inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
149 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
150 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
151 surfaceScale);
152}
153
154inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
155 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
156 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
157 surfaceScale);
158}
159
160inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
161 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
162 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
163 surfaceScale);
164}
165
166inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
167 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
168 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
169 surfaceScale);
170}
171
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000172template <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 +0000173 const LightType* l = static_cast<const LightType*>(light);
174 int y = 0;
175 {
176 const SkPMColor* row1 = src.getAddr32(0, 0);
177 const SkPMColor* row2 = src.getAddr32(0, 1);
178 SkPMColor* dptr = dst->getAddr32(0, 0);
179 int m[9];
180 int x = 0;
181 m[4] = SkGetPackedA32(*row1++);
182 m[5] = SkGetPackedA32(*row1++);
183 m[7] = SkGetPackedA32(*row2++);
184 m[8] = SkGetPackedA32(*row2++);
185 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000186 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000187 for (x = 1; x < src.width() - 1; ++x)
188 {
189 shiftMatrixLeft(m);
190 m[5] = SkGetPackedA32(*row1++);
191 m[8] = SkGetPackedA32(*row2++);
192 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000193 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000194 }
195 shiftMatrixLeft(m);
196 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000197 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000198 }
199
200 for (++y; y < src.height() - 1; ++y) {
201 const SkPMColor* row0 = src.getAddr32(0, y - 1);
202 const SkPMColor* row1 = src.getAddr32(0, y);
203 const SkPMColor* row2 = src.getAddr32(0, y + 1);
204 SkPMColor* dptr = dst->getAddr32(0, y);
205 int m[9];
206 int x = 0;
207 m[1] = SkGetPackedA32(*row0++);
208 m[2] = SkGetPackedA32(*row0++);
209 m[4] = SkGetPackedA32(*row1++);
210 m[5] = SkGetPackedA32(*row1++);
211 m[7] = SkGetPackedA32(*row2++);
212 m[8] = SkGetPackedA32(*row2++);
213 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000214 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000215 for (x = 1; x < src.width() - 1; ++x) {
216 shiftMatrixLeft(m);
217 m[2] = SkGetPackedA32(*row0++);
218 m[5] = SkGetPackedA32(*row1++);
219 m[8] = SkGetPackedA32(*row2++);
220 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000221 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000222 }
223 shiftMatrixLeft(m);
224 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000225 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000226 }
227
228 {
229 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
230 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
231 int x = 0;
232 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
233 int m[9];
234 m[1] = SkGetPackedA32(*row0++);
235 m[2] = SkGetPackedA32(*row0++);
236 m[4] = SkGetPackedA32(*row1++);
237 m[5] = SkGetPackedA32(*row1++);
238 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000239 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 for (x = 1; x < src.width() - 1; ++x)
241 {
242 shiftMatrixLeft(m);
243 m[2] = SkGetPackedA32(*row0++);
244 m[5] = SkGetPackedA32(*row1++);
245 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000246 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000247 }
248 shiftMatrixLeft(m);
249 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000250 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000251 }
252}
253
254SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
255 SkPoint3 point;
256 point.fX = buffer.readScalar();
257 point.fY = buffer.readScalar();
258 point.fZ = buffer.readScalar();
259 return point;
260};
261
262void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
263 buffer.writeScalar(point.fX);
264 buffer.writeScalar(point.fY);
265 buffer.writeScalar(point.fZ);
266};
267
268class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
269public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000270 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
272
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000273 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000274 SkScalar kd() const { return fKD; }
275
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000276protected:
277 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
278 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
279 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
280 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
281
282
283private:
284 typedef SkLightingImageFilter INHERITED;
285 SkScalar fKD;
286};
287
288class SkSpecularLightingImageFilter : public SkLightingImageFilter {
289public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000290 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000291 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
292
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000293 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000294 SkScalar ks() const { return fKS; }
295 SkScalar shininess() const { return fShininess; }
296
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297protected:
298 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
299 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
300 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
301 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
302
303private:
304 typedef SkLightingImageFilter INHERITED;
305 SkScalar fKS;
306 SkScalar fShininess;
307};
308
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000309#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000310
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000311class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000312public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000313 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000314 virtual ~GrLightingEffect();
315
316 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
317
318 const SkLight* light() const { return fLight; }
319 SkScalar surfaceScale() const { return fSurfaceScale; }
320private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000321 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000322 const SkLight* fLight;
323 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000324};
325
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000326class GrDiffuseLightingEffect : public GrLightingEffect {
327public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000328 GrDiffuseLightingEffect(GrTexture* texture,
329 const SkLight* light,
330 SkScalar surfaceScale,
331 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000332
333 static const char* Name() { return "DiffuseLighting"; }
334
335 typedef GrGLDiffuseLightingEffect GLProgramStage;
336
337 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
338 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
339 SkScalar kd() const { return fKD; }
340private:
341 typedef GrLightingEffect INHERITED;
342 SkScalar fKD;
343};
344
345class GrSpecularLightingEffect : public GrLightingEffect {
346public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000347 GrSpecularLightingEffect(GrTexture* texture,
348 const SkLight* light,
349 SkScalar surfaceScale,
350 SkScalar ks,
351 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000352
353 static const char* Name() { return "SpecularLighting"; }
354
355 typedef GrGLSpecularLightingEffect GLProgramStage;
356
357 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
358 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
359 SkScalar ks() const { return fKS; }
360 SkScalar shininess() const { return fShininess; }
361
362private:
363 typedef GrLightingEffect INHERITED;
364 SkScalar fKS;
365 SkScalar fShininess;
366};
367
368///////////////////////////////////////////////////////////////////////////////
369
370class GrGLLight {
371public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000372 virtual ~GrGLLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000373 virtual void setupVariables(GrGLShaderBuilder* builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000374 virtual void emitVS(SkString* out) const {}
375 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
376 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
377 SkString* out,
378 const char* z) const = 0;
379 virtual void emitLightColor(const GrGLShaderBuilder*,
380 SkString* out,
381 const char *surfaceToLight) const;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000382 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000383
384private:
385 typedef SkRefCnt INHERITED;
386
387protected:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000388 UniformHandle fColorUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000389};
390
391///////////////////////////////////////////////////////////////////////////////
392
393class GrGLDistantLight : public GrGLLight {
394public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000395 virtual ~GrGLDistantLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000396 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000397 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000398 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
399 SkString* out,
400 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000401private:
402 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000403 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000404};
405
406///////////////////////////////////////////////////////////////////////////////
407
408class GrGLPointLight : public GrGLLight {
409public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000410 virtual ~GrGLPointLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000411 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000412 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000413 virtual void emitVS(SkString* out) const SK_OVERRIDE;
414 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
415 SkString* out,
416 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000417private:
418 typedef GrGLLight INHERITED;
419 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000420 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000421};
422
423///////////////////////////////////////////////////////////////////////////////
424
425class GrGLSpotLight : public GrGLLight {
426public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000427 virtual ~GrGLSpotLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000428 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000429 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000430 virtual void emitVS(SkString* out) const SK_OVERRIDE;
431 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
432 virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
433 SkString* out,
434 const char* z) const SK_OVERRIDE;
435 virtual void emitLightColor(const GrGLShaderBuilder*,
436 SkString* out,
437 const char *surfaceToLight) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000438
439private:
440 typedef GrGLLight INHERITED;
441
bsalomon@google.com032b2212012-07-16 13:36:18 +0000442 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000443 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000444 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000445 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000446 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000447 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000448};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000449#else
450
451class GrGLLight;
452
453#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000454
455};
456
457///////////////////////////////////////////////////////////////////////////////
458
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000459class SkLight : public SkFlattenable {
460public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000461 SK_DECLARE_INST_COUNT(SkLight)
462
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000463 enum LightType {
464 kDistant_LightType,
465 kPoint_LightType,
466 kSpot_LightType,
467 };
468 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000469 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000470 virtual GrGLLight* createGLLight() const = 0;
471 virtual bool isEqual(const SkLight& other) const {
472 return fColor == other.fColor;
473 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474
djsollen@google.com08337772012-06-26 14:33:13 +0000475protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000476 SkLight(SkColor color)
477 : fColor(SkIntToScalar(SkColorGetR(color)),
478 SkIntToScalar(SkColorGetG(color)),
479 SkIntToScalar(SkColorGetB(color))) {}
480 SkLight(SkFlattenableReadBuffer& buffer)
481 : INHERITED(buffer) {
482 fColor = readPoint3(buffer);
483 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000484 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000485 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000486 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000487 }
djsollen@google.com08337772012-06-26 14:33:13 +0000488
489private:
490 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000491 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000492};
493
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000494SK_DEFINE_INST_COUNT(SkLight)
495
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496///////////////////////////////////////////////////////////////////////////////
497
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000498class SkDistantLight : public SkLight {
499public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000500 SkDistantLight(const SkPoint3& direction, SkColor color)
501 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000502 }
djsollen@google.com08337772012-06-26 14:33:13 +0000503
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000504 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
505 return fDirection;
506 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000507 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000508 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000509 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000510 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
511#if SK_SUPPORT_GPU
512 return SkNEW(GrGLDistantLight);
513#else
514 SkDEBUGFAIL("Should not call in GPU-less build");
515 return NULL;
516#endif
517 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000518 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
519 if (other.type() != kDistant_LightType) {
520 return false;
521 }
522
523 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
524 return INHERITED::isEqual(other) &&
525 fDirection == o.fDirection;
526 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000527
528 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
529
djsollen@google.com08337772012-06-26 14:33:13 +0000530protected:
531 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
532 fDirection = readPoint3(buffer);
533 }
534 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
535 INHERITED::flatten(buffer);
536 writePoint3(fDirection, buffer);
537 }
538
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539private:
djsollen@google.com08337772012-06-26 14:33:13 +0000540 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000541 SkPoint3 fDirection;
542};
543
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000544///////////////////////////////////////////////////////////////////////////////
545
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000546class SkPointLight : public SkLight {
547public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000548 SkPointLight(const SkPoint3& location, SkColor color)
549 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000550
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000551 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
552 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
553 fLocation.fY - SkIntToScalar(y),
554 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
555 direction.normalize();
556 return direction;
557 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000558 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000559 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000560 const SkPoint3& location() const { return fLocation; }
561 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000562#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000563 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000564#else
565 SkDEBUGFAIL("Should not call in GPU-less build");
566 return NULL;
567#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000568 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000569 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000570 if (other.type() != kPoint_LightType) {
571 return false;
572 }
573 const SkPointLight& o = static_cast<const SkPointLight&>(other);
574 return INHERITED::isEqual(other) &&
575 fLocation == o.fLocation;
576 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000577
578 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
579
djsollen@google.com08337772012-06-26 14:33:13 +0000580protected:
581 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
582 fLocation = readPoint3(buffer);
583 }
584 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
585 INHERITED::flatten(buffer);
586 writePoint3(fLocation, buffer);
587 }
588
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589private:
djsollen@google.com08337772012-06-26 14:33:13 +0000590 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591 SkPoint3 fLocation;
592};
593
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000594///////////////////////////////////////////////////////////////////////////////
595
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000596class SkSpotLight : public SkLight {
597public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000598 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
599 : INHERITED(color),
600 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000601 fTarget(target),
602 fSpecularExponent(specularExponent)
603 {
604 fS = target - location;
605 fS.normalize();
606 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
607 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
608 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
609 fConeScale = SkScalarInvert(antiAliasThreshold);
610 }
djsollen@google.com08337772012-06-26 14:33:13 +0000611
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000612 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
613 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
614 fLocation.fY - SkIntToScalar(y),
615 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
616 direction.normalize();
617 return direction;
618 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000619 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000620 SkScalar cosAngle = -surfaceToLight.dot(fS);
621 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000622 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000623 }
624 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
625 if (cosAngle < fCosInnerConeAngle) {
626 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000627 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000628 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000629 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000630 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000631 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000632#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000633 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000634#else
635 SkDEBUGFAIL("Should not call in GPU-less build");
636 return NULL;
637#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638 }
djsollen@google.com08337772012-06-26 14:33:13 +0000639 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000640 const SkPoint3& location() const { return fLocation; }
641 const SkPoint3& target() const { return fTarget; }
642 SkScalar specularExponent() const { return fSpecularExponent; }
643 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
644 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
645 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000646 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000647
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000648 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
649
djsollen@google.com08337772012-06-26 14:33:13 +0000650protected:
651 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
652 fLocation = readPoint3(buffer);
653 fTarget = readPoint3(buffer);
654 fSpecularExponent = buffer.readScalar();
655 fCosOuterConeAngle = buffer.readScalar();
656 fCosInnerConeAngle = buffer.readScalar();
657 fConeScale = buffer.readScalar();
658 fS = readPoint3(buffer);
659 }
660 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
661 INHERITED::flatten(buffer);
662 writePoint3(fLocation, buffer);
663 writePoint3(fTarget, buffer);
664 buffer.writeScalar(fSpecularExponent);
665 buffer.writeScalar(fCosOuterConeAngle);
666 buffer.writeScalar(fCosInnerConeAngle);
667 buffer.writeScalar(fConeScale);
668 writePoint3(fS, buffer);
669 }
670
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000671 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000672 if (other.type() != kSpot_LightType) {
673 return false;
674 }
675
676 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
677 return INHERITED::isEqual(other) &&
678 fLocation == o.fLocation &&
679 fTarget == o.fTarget &&
680 fSpecularExponent == o.fSpecularExponent &&
681 fCosOuterConeAngle == o.fCosOuterConeAngle;
682 }
683
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000684private:
djsollen@google.com08337772012-06-26 14:33:13 +0000685 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000686 SkPoint3 fLocation;
687 SkPoint3 fTarget;
688 SkScalar fSpecularExponent;
689 SkScalar fCosOuterConeAngle;
690 SkScalar fCosInnerConeAngle;
691 SkScalar fConeScale;
692 SkPoint3 fS;
693};
694
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000695///////////////////////////////////////////////////////////////////////////////
696
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000697SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000699 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
700{
701 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000702 // our caller knows that we take ownership of the light, so we don't
703 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704}
705
706SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000707 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000708 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000709 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
710 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd));
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.orgf49b4292012-06-22 21:01:23 +0000715 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000716 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
717 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000718}
719
720SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000721 const SkPoint3& location, const SkPoint3& target,
722 SkScalar specularExponent, SkScalar cutoffAngle,
723 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000724 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
725 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
726 surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000727}
728
729SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000730 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000732 return SkNEW_ARGS(SkSpecularLightingImageFilter,
733 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000734}
735
736SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000737 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
738 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000739 return SkNEW_ARGS(SkSpecularLightingImageFilter,
740 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000741}
742
743SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000744 const SkPoint3& location, const SkPoint3& target,
745 SkScalar specularExponent, SkScalar cutoffAngle,
746 SkColor lightColor, SkScalar surfaceScale,
747 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000748 return SkNEW_ARGS(SkSpecularLightingImageFilter,
749 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
750 surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000751}
752
753SkLightingImageFilter::~SkLightingImageFilter() {
754 fLight->unref();
755}
756
757SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
758 : INHERITED(buffer)
759{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000760 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000761 fSurfaceScale = buffer.readScalar();
762}
763
764void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
765 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000766 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000767 buffer.writeScalar(fSurfaceScale);
768}
769
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000770///////////////////////////////////////////////////////////////////////////////
771
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000772SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
773 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774 fKD(kd)
775{
776}
777
778SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
779 : INHERITED(buffer)
780{
781 fKD = buffer.readScalar();
782}
783
784void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
785 this->INHERITED::flatten(buffer);
786 buffer.writeScalar(fKD);
787}
788
789bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
790 const SkBitmap& src,
791 const SkMatrix&,
792 SkBitmap* dst,
793 SkIPoint*) {
794 if (src.config() != SkBitmap::kARGB_8888_Config) {
795 return false;
796 }
797 SkAutoLockPixels alp(src);
798 if (!src.getPixels()) {
799 return false;
800 }
801 if (src.width() < 2 || src.height() < 2) {
802 return false;
803 }
804 dst->setConfig(src.config(), src.width(), src.height());
805 dst->allocPixels();
806
807 DiffuseLightingType lightingType(fKD);
808 switch (light()->type()) {
809 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000810 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000811 break;
812 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000813 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000814 break;
815 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000816 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000817 break;
818 }
819 return true;
820}
821
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000822bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
823 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000824#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000825 if (stage) {
826 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000827 *stage = SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light(), scale, kd()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000828 }
829 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000830#else
831 SkDEBUGFAIL("Should not call in GPU-less build");
832 return false;
833#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000834}
835
836///////////////////////////////////////////////////////////////////////////////
837
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000838SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
839 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000840 fKS(ks),
841 fShininess(shininess)
842{
843}
844
845SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
846 : INHERITED(buffer)
847{
848 fKS = buffer.readScalar();
849 fShininess = buffer.readScalar();
850}
851
852void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
853 this->INHERITED::flatten(buffer);
854 buffer.writeScalar(fKS);
855 buffer.writeScalar(fShininess);
856}
857
858bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
859 const SkBitmap& src,
860 const SkMatrix&,
861 SkBitmap* dst,
862 SkIPoint*) {
863 if (src.config() != SkBitmap::kARGB_8888_Config) {
864 return false;
865 }
866 SkAutoLockPixels alp(src);
867 if (!src.getPixels()) {
868 return false;
869 }
870 if (src.width() < 2 || src.height() < 2) {
871 return false;
872 }
873 dst->setConfig(src.config(), src.width(), src.height());
874 dst->allocPixels();
875
876 SpecularLightingType lightingType(fKS, fShininess);
877 switch (light()->type()) {
878 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000879 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000880 break;
881 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000882 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000883 break;
884 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000885 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000886 break;
887 }
888 return true;
889}
890
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000891bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
892 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000893#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000894 if (stage) {
895 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000896 *stage = SkNEW_ARGS(GrSpecularLightingEffect, (texture, light(), scale, ks(), shininess()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000897 }
898 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000899#else
900 SkDEBUGFAIL("Should not call in GPU-less build");
901 return false;
902#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000903}
904
905///////////////////////////////////////////////////////////////////////////////
906
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000907#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000908class GrGLLightingEffect : public GrGLProgramStage {
909public:
910 GrGLLightingEffect(const GrProgramStageFactory& factory,
911 const GrCustomStage& stage);
912 virtual ~GrGLLightingEffect();
913
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000914 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000915 virtual void emitVS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000916 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000917 virtual void emitFS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000918 const char* outputColor,
919 const char* inputColor,
920 const char* samplerName) SK_OVERRIDE;
921
bsalomon@google.com032b2212012-07-16 13:36:18 +0000922 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000923
twiz@google.coma5e65ec2012-08-02 15:15:16 +0000924 static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000925
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000926 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000927 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000928 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000929 int stageNum) SK_OVERRIDE;
930
931private:
932 typedef GrGLProgramStage INHERITED;
933
bsalomon@google.com032b2212012-07-16 13:36:18 +0000934 UniformHandle fImageIncrementUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000935 UniformHandle fSurfaceScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000936 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000937};
938
939///////////////////////////////////////////////////////////////////////////////
940
941class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
942public:
943 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
944 const GrCustomStage& stage);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000945 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000946 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000947 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000948 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000949 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000950 int stageNum) SK_OVERRIDE;
951
952private:
953 typedef GrGLLightingEffect INHERITED;
954
bsalomon@google.com032b2212012-07-16 13:36:18 +0000955 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000956};
957
958///////////////////////////////////////////////////////////////////////////////
959
960class GrGLSpecularLightingEffect : public GrGLLightingEffect {
961public:
962 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
963 const GrCustomStage& stage);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000964 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000965 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000966 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000967 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000968 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000969 int stageNum) SK_OVERRIDE;
970
971private:
972 typedef GrGLLightingEffect INHERITED;
973
bsalomon@google.com032b2212012-07-16 13:36:18 +0000974 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000975 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000976};
977
978///////////////////////////////////////////////////////////////////////////////
979
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000980GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
981 : GrSingleTextureEffect(texture)
982 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000983 , fSurfaceScale(surfaceScale) {
984 fLight->ref();
985}
986
987GrLightingEffect::~GrLightingEffect() {
988 fLight->unref();
989}
990
991bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
992 const GrLightingEffect& s =
993 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000994 return INHERITED::isEqual(sBase) &&
995 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000996 fSurfaceScale == s.fSurfaceScale;
997}
998
999///////////////////////////////////////////////////////////////////////////////
1000
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001001GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1002 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001003}
1004
1005const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
1006 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
1007}
1008
1009bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
1010 const GrDiffuseLightingEffect& s =
1011 static_cast<const GrDiffuseLightingEffect&>(sBase);
1012 return INHERITED::isEqual(sBase) &&
1013 this->kd() == s.kd();
1014}
1015
1016///////////////////////////////////////////////////////////////////////////////
1017
1018GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
1019 const GrCustomStage& stage)
1020 : GrGLProgramStage(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001021 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001022 , fSurfaceScaleUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001023 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
1024 fLight = m.light()->createGLLight();
1025}
1026
1027GrGLLightingEffect::~GrGLLightingEffect() {
1028 delete fLight;
1029}
1030
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001031void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001032 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1033 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001034 "ImageIncrement");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001035 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1036 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001037 "SurfaceScale");
1038 fLight->setupVariables(builder);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001039}
1040
bsalomon@google.com032b2212012-07-16 13:36:18 +00001041void GrGLLightingEffect::emitVS(GrGLShaderBuilder* builder,
1042 const char* vertexCoords) {
1043 fLight->emitVS(&builder->fVSCode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001044}
1045
bsalomon@google.com032b2212012-07-16 13:36:18 +00001046void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
1047 const char* outputColor,
1048 const char* inputColor,
1049 const char* samplerName) {
1050 SkString* code = &builder->fFSCode;
1051 SkString* funcs = &builder->fFSFunctions;
1052 fLight->emitFuncs(builder, funcs);
1053 this->emitLightFunc(builder, funcs);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001054 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 +00001055 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001056 funcs->appendf("}\n");
1057 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1058 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1059 funcs->appendf("}\n");
1060 funcs->append("\n\
1061vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1062 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1063 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1064 surfaceScale);\n}\n");
1065
bsalomon@google.com032b2212012-07-16 13:36:18 +00001066 code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001067 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001068
1069 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1070 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1071
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001072 int index = 0;
1073 for (int dy = -1; dy <= 1; dy++) {
1074 for (int dx = -1; dx <= 1; dx++) {
1075 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001076 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001077 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001078 builder->emitTextureLookup(samplerName, texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001079 code->appendf(".a;\n");
1080 }
1081 }
1082 code->appendf("\t\tvec3 surfaceToLight = ");
1083 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001084 arg.appendf("%s * m[4]", surfScale);
1085 fLight->emitSurfaceToLight(builder, code, arg.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001086 code->appendf(";\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001087 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
1088 fLight->emitLightColor(builder, code, "surfaceToLight");
1089 code->appendf(")%s;\n", builder->fModulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001090}
1091
twiz@google.coma5e65ec2012-08-02 15:15:16 +00001092GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(const GrCustomStage& s,
1093 const GrGLCaps& caps) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001094 return static_cast<const GrLightingEffect&>(s).light()->type();
1095}
1096
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001097void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001098 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001099 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001100 int stageNum) {
1101 const GrLightingEffect& effect =
1102 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001103 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1104 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001105 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1106 uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
1107 fLight->setData(uman, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001108}
1109
1110///////////////////////////////////////////////////////////////////////////////
1111
1112///////////////////////////////////////////////////////////////////////////////
1113
1114GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1115 const GrCustomStage& stage)
1116 : INHERITED(factory, stage)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001117 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001118}
1119
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001120void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
1121 INHERITED::setupVariables(builder);
1122 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "KD");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001123}
1124
bsalomon@google.com032b2212012-07-16 13:36:18 +00001125void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
1126 const char* kd = builder->getUniformCStr(fKDUni);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001127 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001128 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001129 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001130 funcs->appendf("}\n");
1131}
1132
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001133void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001134 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001135 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001136 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001137 INHERITED::setData(uman, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001138 const GrDiffuseLightingEffect& effect =
1139 static_cast<const GrDiffuseLightingEffect&>(data);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001140 uman.set1f(fKDUni, effect.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001141}
1142
1143///////////////////////////////////////////////////////////////////////////////
1144
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001145GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1146 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001147 fKS(ks),
1148 fShininess(shininess) {
1149}
1150
1151const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1152 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1153}
1154
1155bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1156 const GrSpecularLightingEffect& s =
1157 static_cast<const GrSpecularLightingEffect&>(sBase);
1158 return INHERITED::isEqual(sBase) &&
1159 this->ks() == s.ks() &&
1160 this->shininess() == s.shininess();
1161}
1162
1163///////////////////////////////////////////////////////////////////////////////
1164
1165GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1166 const GrCustomStage& stage)
1167 : GrGLLightingEffect(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001168 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001169 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001170}
1171
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001172void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
1173 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001174 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001175 kFloat_GrSLType, "KS");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001176 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001177 kFloat_GrSLType, "Shininess");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001178}
1179
bsalomon@google.com032b2212012-07-16 13:36:18 +00001180void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001181 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1182 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1183
bsalomon@google.com032b2212012-07-16 13:36:18 +00001184 const char* ks = builder->getUniformCStr(fKSUni);
1185 const char* shininess = builder->getUniformCStr(fShininessUni);
1186 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001187 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001188 funcs->appendf("}\n");
1189}
1190
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001191void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001192 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001193 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001194 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001195 INHERITED::setData(uman, data, rt, stageNum);
1196 const GrSpecularLightingEffect& effect = static_cast<const GrSpecularLightingEffect&>(data);
1197 uman.set1f(fKSUni, effect.ks());
1198 uman.set1f(fShininessUni, effect.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001199}
1200
1201///////////////////////////////////////////////////////////////////////////////
1202
bsalomon@google.com032b2212012-07-16 13:36:18 +00001203void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
1204 SkString* out,
1205 const char *surfaceToLight) const {
1206 const char* color = builder->getUniformCStr(fColorUni);
1207 out->append(color);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001208}
1209
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001210void GrGLLight::setupVariables(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001211 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001212 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001213}
1214
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001215void GrGLLight::setData(const GrGLUniformManager& uman,
1216 const GrRenderTarget* rt,
1217 const SkLight* light) const {
1218 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001219}
1220
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001221///////////////////////////////////////////////////////////////////////////////
1222
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001223void GrGLDistantLight::setupVariables(GrGLShaderBuilder* builder) {
1224 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001225 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001226 "LightDirection");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001227}
1228
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001229void GrGLDistantLight::setData(const GrGLUniformManager& uman,
1230 const GrRenderTarget* rt,
1231 const SkLight* light) const {
1232 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001233 SkASSERT(light->type() == SkLight::kDistant_LightType);
1234 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001235 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001236}
1237
bsalomon@google.com032b2212012-07-16 13:36:18 +00001238void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1239 SkString* out,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001240 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001241 const char* dir = builder->getUniformCStr(fDirectionUni);
1242 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001243}
1244
1245///////////////////////////////////////////////////////////////////////////////
1246
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001247void GrGLPointLight::setupVariables(GrGLShaderBuilder* builder) {
1248 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001249 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001250 "LightLocation");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001251}
1252
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001253void GrGLPointLight::setData(const GrGLUniformManager& uman,
1254 const GrRenderTarget* rt,
1255 const SkLight* light) const {
1256 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001257 SkASSERT(light->type() == SkLight::kPoint_LightType);
1258 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001259 setUniformPoint3FlipY(uman, fLocationUni, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001260}
1261
bsalomon@google.com032b2212012-07-16 13:36:18 +00001262void GrGLPointLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001263}
1264
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001265void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1266 SkString* out,
1267 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001268 const char* loc = builder->getUniformCStr(fLocationUni);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001269 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001270}
1271
1272///////////////////////////////////////////////////////////////////////////////
1273
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001274void GrGLSpotLight::setupVariables(GrGLShaderBuilder* builder) {
1275 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001276 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001277 kVec3f_GrSLType, "LightLocation");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001278 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001279 kFloat_GrSLType, "Exponent");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001280 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001281 kFloat_GrSLType, "CosInnerConeAngle");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001282 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001283 kFloat_GrSLType, "CosOuterConeAngle");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001284 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001285 kFloat_GrSLType, "ConeScale");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001286 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001287 kVec3f_GrSLType, "S");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001288}
1289
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001290void GrGLSpotLight::setData(const GrGLUniformManager& uman,
1291 const GrRenderTarget* rt,
1292 const SkLight* light) const {
1293 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001294 SkASSERT(light->type() == SkLight::kSpot_LightType);
1295 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001296 setUniformPoint3FlipY(uman, fLocationUni, spotLight->location(), rt->height());
1297 uman.set1f(fExponentUni, spotLight->specularExponent());
1298 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1299 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1300 uman.set1f(fConeScaleUni, spotLight->coneScale());
1301 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001302}
1303
bsalomon@google.com032b2212012-07-16 13:36:18 +00001304void GrGLSpotLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001305}
1306
bsalomon@google.com032b2212012-07-16 13:36:18 +00001307void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
1308 const char* exponent = builder->getUniformCStr(fExponentUni);
1309 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1310 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1311 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1312 const char* s = builder->getUniformCStr(fSUni);
1313 const char* color = builder->getUniformCStr(fColorUni);
1314
1315 out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1316 out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1317 out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
1318 out->appendf("\t\treturn vec3(0);\n");
1319 out->appendf("\t}\n");
1320 out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1321 out->appendf("\tif (cosAngle < %s) {\n", cosInner);
1322 out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
1323 out->appendf("\t}\n");
1324 out->appendf("\treturn %s;\n", color);
1325 out->appendf("}\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001326}
1327
bsalomon@google.com032b2212012-07-16 13:36:18 +00001328void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1329 SkString* out,
1330 const char* z) const {
1331 const char* location= builder->getUniformCStr(fLocationUni);
1332 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001333}
1334
bsalomon@google.com032b2212012-07-16 13:36:18 +00001335void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
1336 SkString* out, const char *surfaceToLight) const {
1337 out->appendf("lightColor(%s)", surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001338}
1339
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001340#endif
1341
djsollen@google.com08337772012-06-26 14:33:13 +00001342SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1343 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1344 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1345 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1346 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1347 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1348SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END