blob: 98c294c60cdbde6649ce0a93902af9820503674e [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000011#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000012
13#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000014#include "GrProgramStageFactory.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000015#include "effects/GrSingleTextureEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000016#include "gl/GrGLProgramStage.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000017#include "gl/GrGLTexture.h"
18#include "GrCustomStage.h"
19
20class GrGLDiffuseLightingEffect;
21class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000022
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000023// For brevity
24typedef GrGLUniformManager::UniformHandle UniformHandle;
25static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000026#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000027
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000028namespace {
29
30const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
31const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
32const SkScalar gOneHalf = SkFloatToScalar(0.5f);
33const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
34
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000035#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000036void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000037 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000038 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000039}
40
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000041void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
42 setUniformPoint3(uman, uni, SkPoint3(point.fX, -point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000043}
44
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000045void setUniformPoint3FlipY(const GrGLUniformManager& uman,
46 UniformHandle uni,
47 const SkPoint3& point,
48 int height) {
49 setUniformPoint3(uman, uni, SkPoint3(point.fX, height-point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000050}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000051#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000052
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000053// Shift matrix components to the left, as we advance pixels to the right.
54inline void shiftMatrixLeft(int m[9]) {
55 m[0] = m[1];
56 m[3] = m[4];
57 m[6] = m[7];
58 m[1] = m[2];
59 m[4] = m[5];
60 m[7] = m[8];
61}
62
63class DiffuseLightingType {
64public:
65 DiffuseLightingType(SkScalar kd)
66 : fKD(kd) {}
67 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
68 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
69 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
70 SkPoint3 color(lightColor * colorScale);
71 return SkPackARGB32(255,
72 SkScalarFloorToInt(color.fX),
73 SkScalarFloorToInt(color.fY),
74 SkScalarFloorToInt(color.fZ));
75 }
76private:
77 SkScalar fKD;
78};
79
80class SpecularLightingType {
81public:
82 SpecularLightingType(SkScalar ks, SkScalar shininess)
83 : fKS(ks), fShininess(shininess) {}
84 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
85 SkPoint3 halfDir(surfaceTolight);
86 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
87 halfDir.normalize();
88 SkScalar colorScale = SkScalarMul(fKS,
89 SkScalarPow(normal.dot(halfDir), fShininess));
90 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
91 SkPoint3 color(lightColor * colorScale);
92 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
93 SkScalarFloorToInt(color.fX),
94 SkScalarFloorToInt(color.fY),
95 SkScalarFloorToInt(color.fZ));
96 }
97private:
98 SkScalar fKS;
99 SkScalar fShininess;
100};
101
102inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
103 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
104}
105
106inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
107 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
108 SkScalarMul(-y, surfaceScale),
109 SK_Scalar1);
110 vector.normalize();
111 return vector;
112}
113
114inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
116 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
117 surfaceScale);
118}
119
120inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
122 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
123 surfaceScale);
124}
125
126inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
128 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
129 surfaceScale);
130}
131
132inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
134 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
135 surfaceScale);
136}
137
138
139inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
141 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
142 surfaceScale);
143}
144
145inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
147 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
148 surfaceScale);
149}
150
151inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
153 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
159 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
160 surfaceScale);
161}
162
163inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
165 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
166 surfaceScale);
167}
168
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000169template <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 +0000170 const LightType* l = static_cast<const LightType*>(light);
171 int y = 0;
172 {
173 const SkPMColor* row1 = src.getAddr32(0, 0);
174 const SkPMColor* row2 = src.getAddr32(0, 1);
175 SkPMColor* dptr = dst->getAddr32(0, 0);
176 int m[9];
177 int x = 0;
178 m[4] = SkGetPackedA32(*row1++);
179 m[5] = SkGetPackedA32(*row1++);
180 m[7] = SkGetPackedA32(*row2++);
181 m[8] = SkGetPackedA32(*row2++);
182 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000183 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000184 for (x = 1; x < src.width() - 1; ++x)
185 {
186 shiftMatrixLeft(m);
187 m[5] = SkGetPackedA32(*row1++);
188 m[8] = SkGetPackedA32(*row2++);
189 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000190 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 }
192 shiftMatrixLeft(m);
193 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000194 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000195 }
196
197 for (++y; y < src.height() - 1; ++y) {
198 const SkPMColor* row0 = src.getAddr32(0, y - 1);
199 const SkPMColor* row1 = src.getAddr32(0, y);
200 const SkPMColor* row2 = src.getAddr32(0, y + 1);
201 SkPMColor* dptr = dst->getAddr32(0, y);
202 int m[9];
203 int x = 0;
204 m[1] = SkGetPackedA32(*row0++);
205 m[2] = SkGetPackedA32(*row0++);
206 m[4] = SkGetPackedA32(*row1++);
207 m[5] = SkGetPackedA32(*row1++);
208 m[7] = SkGetPackedA32(*row2++);
209 m[8] = SkGetPackedA32(*row2++);
210 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000211 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000212 for (x = 1; x < src.width() - 1; ++x) {
213 shiftMatrixLeft(m);
214 m[2] = SkGetPackedA32(*row0++);
215 m[5] = SkGetPackedA32(*row1++);
216 m[8] = SkGetPackedA32(*row2++);
217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000218 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000219 }
220 shiftMatrixLeft(m);
221 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000222 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000223 }
224
225 {
226 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
227 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
228 int x = 0;
229 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
230 int m[9];
231 m[1] = SkGetPackedA32(*row0++);
232 m[2] = SkGetPackedA32(*row0++);
233 m[4] = SkGetPackedA32(*row1++);
234 m[5] = SkGetPackedA32(*row1++);
235 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000236 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000237 for (x = 1; x < src.width() - 1; ++x)
238 {
239 shiftMatrixLeft(m);
240 m[2] = SkGetPackedA32(*row0++);
241 m[5] = SkGetPackedA32(*row1++);
242 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000243 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000244 }
245 shiftMatrixLeft(m);
246 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000247 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 }
249}
250
251SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
252 SkPoint3 point;
253 point.fX = buffer.readScalar();
254 point.fY = buffer.readScalar();
255 point.fZ = buffer.readScalar();
256 return point;
257};
258
259void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
260 buffer.writeScalar(point.fX);
261 buffer.writeScalar(point.fY);
262 buffer.writeScalar(point.fZ);
263};
264
265class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
266public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000267 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000268 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
269
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000270 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000271 SkScalar kd() const { return fKD; }
272
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000273protected:
274 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
275 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
276 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
277 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
278
279
280private:
281 typedef SkLightingImageFilter INHERITED;
282 SkScalar fKD;
283};
284
285class SkSpecularLightingImageFilter : public SkLightingImageFilter {
286public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000287 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000288 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
289
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000290 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000291 SkScalar ks() const { return fKS; }
292 SkScalar shininess() const { return fShininess; }
293
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000294protected:
295 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
296 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
297 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
298 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
299
300private:
301 typedef SkLightingImageFilter INHERITED;
302 SkScalar fKS;
303 SkScalar fShininess;
304};
305
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000306#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000307
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000308class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000309public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000310 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000311 virtual ~GrLightingEffect();
312
313 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
314
315 const SkLight* light() const { return fLight; }
316 SkScalar surfaceScale() const { return fSurfaceScale; }
317private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000318 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000319 const SkLight* fLight;
320 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000321};
322
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000323class GrDiffuseLightingEffect : public GrLightingEffect {
324public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000325 GrDiffuseLightingEffect(GrTexture* texture,
326 const SkLight* light,
327 SkScalar surfaceScale,
328 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000329
330 static const char* Name() { return "DiffuseLighting"; }
331
332 typedef GrGLDiffuseLightingEffect GLProgramStage;
333
334 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
335 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
336 SkScalar kd() const { return fKD; }
337private:
338 typedef GrLightingEffect INHERITED;
339 SkScalar fKD;
340};
341
342class GrSpecularLightingEffect : public GrLightingEffect {
343public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000344 GrSpecularLightingEffect(GrTexture* texture,
345 const SkLight* light,
346 SkScalar surfaceScale,
347 SkScalar ks,
348 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000349
350 static const char* Name() { return "SpecularLighting"; }
351
352 typedef GrGLSpecularLightingEffect GLProgramStage;
353
354 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
355 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
356 SkScalar ks() const { return fKS; }
357 SkScalar shininess() const { return fShininess; }
358
359private:
360 typedef GrLightingEffect INHERITED;
361 SkScalar fKS;
362 SkScalar fShininess;
363};
364
365///////////////////////////////////////////////////////////////////////////////
366
367class GrGLLight {
368public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000369 virtual ~GrGLLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000370 virtual void setupVariables(GrGLShaderBuilder* builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000371 virtual void emitVS(SkString* out) const {}
372 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
373 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
374 SkString* out,
375 const char* z) const = 0;
376 virtual void emitLightColor(const GrGLShaderBuilder*,
377 SkString* out,
378 const char *surfaceToLight) const;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000379 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000380
381private:
382 typedef SkRefCnt INHERITED;
383
384protected:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000385 UniformHandle fColorUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000386};
387
388///////////////////////////////////////////////////////////////////////////////
389
390class GrGLDistantLight : public GrGLLight {
391public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000392 virtual ~GrGLDistantLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000393 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000394 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000395 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
396 SkString* out,
397 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000398private:
399 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000400 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000401};
402
403///////////////////////////////////////////////////////////////////////////////
404
405class GrGLPointLight : public GrGLLight {
406public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000407 virtual ~GrGLPointLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000408 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000409 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000410 virtual void emitVS(SkString* out) const SK_OVERRIDE;
411 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
412 SkString* out,
413 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000414private:
415 typedef GrGLLight INHERITED;
416 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000417 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000418};
419
420///////////////////////////////////////////////////////////////////////////////
421
422class GrGLSpotLight : public GrGLLight {
423public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000424 virtual ~GrGLSpotLight() {}
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000425 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000426 virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000427 virtual void emitVS(SkString* out) const SK_OVERRIDE;
428 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
429 virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
430 SkString* out,
431 const char* z) const SK_OVERRIDE;
432 virtual void emitLightColor(const GrGLShaderBuilder*,
433 SkString* out,
434 const char *surfaceToLight) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000435
436private:
437 typedef GrGLLight INHERITED;
438
bsalomon@google.com032b2212012-07-16 13:36:18 +0000439 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000440 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000441 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000442 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000443 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000444 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000445};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000446#else
447
448class GrGLLight;
449
450#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000451
452};
453
454///////////////////////////////////////////////////////////////////////////////
455
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456class SkLight : public SkFlattenable {
457public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000458 SK_DECLARE_INST_COUNT(SkLight)
459
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000460 enum LightType {
461 kDistant_LightType,
462 kPoint_LightType,
463 kSpot_LightType,
464 };
465 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000466 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000467 virtual GrGLLight* createGLLight() const = 0;
468 virtual bool isEqual(const SkLight& other) const {
469 return fColor == other.fColor;
470 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471
djsollen@google.com08337772012-06-26 14:33:13 +0000472protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000473 SkLight(SkColor color)
474 : fColor(SkIntToScalar(SkColorGetR(color)),
475 SkIntToScalar(SkColorGetG(color)),
476 SkIntToScalar(SkColorGetB(color))) {}
477 SkLight(SkFlattenableReadBuffer& buffer)
478 : INHERITED(buffer) {
479 fColor = readPoint3(buffer);
480 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000482 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000483 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000484 }
djsollen@google.com08337772012-06-26 14:33:13 +0000485
486private:
487 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000488 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000489};
490
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000491SK_DEFINE_INST_COUNT(SkLight)
492
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493///////////////////////////////////////////////////////////////////////////////
494
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000495class SkDistantLight : public SkLight {
496public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000497 SkDistantLight(const SkPoint3& direction, SkColor color)
498 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000499 }
djsollen@google.com08337772012-06-26 14:33:13 +0000500
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
502 return fDirection;
503 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000504 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000505 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000507 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
508#if SK_SUPPORT_GPU
509 return SkNEW(GrGLDistantLight);
510#else
511 SkDEBUGFAIL("Should not call in GPU-less build");
512 return NULL;
513#endif
514 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000515 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
516 if (other.type() != kDistant_LightType) {
517 return false;
518 }
519
520 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
521 return INHERITED::isEqual(other) &&
522 fDirection == o.fDirection;
523 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000524
525 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
526
djsollen@google.com08337772012-06-26 14:33:13 +0000527protected:
528 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
529 fDirection = readPoint3(buffer);
530 }
531 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
532 INHERITED::flatten(buffer);
533 writePoint3(fDirection, buffer);
534 }
535
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000536private:
djsollen@google.com08337772012-06-26 14:33:13 +0000537 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000538 SkPoint3 fDirection;
539};
540
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000541///////////////////////////////////////////////////////////////////////////////
542
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000543class SkPointLight : public SkLight {
544public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000545 SkPointLight(const SkPoint3& location, SkColor color)
546 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000547
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000548 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
549 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
550 fLocation.fY - SkIntToScalar(y),
551 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
552 direction.normalize();
553 return direction;
554 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000555 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000556 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000557 const SkPoint3& location() const { return fLocation; }
558 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000559#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000560 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000561#else
562 SkDEBUGFAIL("Should not call in GPU-less build");
563 return NULL;
564#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000566 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567 if (other.type() != kPoint_LightType) {
568 return false;
569 }
570 const SkPointLight& o = static_cast<const SkPointLight&>(other);
571 return INHERITED::isEqual(other) &&
572 fLocation == o.fLocation;
573 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000574
575 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
576
djsollen@google.com08337772012-06-26 14:33:13 +0000577protected:
578 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
579 fLocation = readPoint3(buffer);
580 }
581 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
582 INHERITED::flatten(buffer);
583 writePoint3(fLocation, buffer);
584 }
585
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586private:
djsollen@google.com08337772012-06-26 14:33:13 +0000587 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000588 SkPoint3 fLocation;
589};
590
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000591///////////////////////////////////////////////////////////////////////////////
592
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000593class SkSpotLight : public SkLight {
594public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000595 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
596 : INHERITED(color),
597 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000598 fTarget(target),
599 fSpecularExponent(specularExponent)
600 {
601 fS = target - location;
602 fS.normalize();
603 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
604 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
605 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
606 fConeScale = SkScalarInvert(antiAliasThreshold);
607 }
djsollen@google.com08337772012-06-26 14:33:13 +0000608
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000609 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
610 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
611 fLocation.fY - SkIntToScalar(y),
612 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
613 direction.normalize();
614 return direction;
615 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000616 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000617 SkScalar cosAngle = -surfaceToLight.dot(fS);
618 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000619 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000620 }
621 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
622 if (cosAngle < fCosInnerConeAngle) {
623 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000624 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000625 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000626 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000627 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000629#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000630 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000631#else
632 SkDEBUGFAIL("Should not call in GPU-less build");
633 return NULL;
634#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000635 }
djsollen@google.com08337772012-06-26 14:33:13 +0000636 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000637 const SkPoint3& location() const { return fLocation; }
638 const SkPoint3& target() const { return fTarget; }
639 SkScalar specularExponent() const { return fSpecularExponent; }
640 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
641 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
642 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000643 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000644
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000645 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
646
djsollen@google.com08337772012-06-26 14:33:13 +0000647protected:
648 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
649 fLocation = readPoint3(buffer);
650 fTarget = readPoint3(buffer);
651 fSpecularExponent = buffer.readScalar();
652 fCosOuterConeAngle = buffer.readScalar();
653 fCosInnerConeAngle = buffer.readScalar();
654 fConeScale = buffer.readScalar();
655 fS = readPoint3(buffer);
656 }
657 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
658 INHERITED::flatten(buffer);
659 writePoint3(fLocation, buffer);
660 writePoint3(fTarget, buffer);
661 buffer.writeScalar(fSpecularExponent);
662 buffer.writeScalar(fCosOuterConeAngle);
663 buffer.writeScalar(fCosInnerConeAngle);
664 buffer.writeScalar(fConeScale);
665 writePoint3(fS, buffer);
666 }
667
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000668 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000669 if (other.type() != kSpot_LightType) {
670 return false;
671 }
672
673 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
674 return INHERITED::isEqual(other) &&
675 fLocation == o.fLocation &&
676 fTarget == o.fTarget &&
677 fSpecularExponent == o.fSpecularExponent &&
678 fCosOuterConeAngle == o.fCosOuterConeAngle;
679 }
680
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000681private:
djsollen@google.com08337772012-06-26 14:33:13 +0000682 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000683 SkPoint3 fLocation;
684 SkPoint3 fTarget;
685 SkScalar fSpecularExponent;
686 SkScalar fCosOuterConeAngle;
687 SkScalar fCosInnerConeAngle;
688 SkScalar fConeScale;
689 SkPoint3 fS;
690};
691
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000692///////////////////////////////////////////////////////////////////////////////
693
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000694SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
697{
698 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000699 // our caller knows that we take ownership of the light, so we don't
700 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701}
702
703SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000704 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000705 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000706 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
707 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000708}
709
710SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000711 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000713 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
714 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000715}
716
717SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000718 const SkPoint3& location, const SkPoint3& target,
719 SkScalar specularExponent, SkScalar cutoffAngle,
720 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000721 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
722 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
723 surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000724}
725
726SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000727 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000728 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000729 return SkNEW_ARGS(SkSpecularLightingImageFilter,
730 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731}
732
733SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
735 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000736 return SkNEW_ARGS(SkSpecularLightingImageFilter,
737 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738}
739
740SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 const SkPoint3& location, const SkPoint3& target,
742 SkScalar specularExponent, SkScalar cutoffAngle,
743 SkColor lightColor, SkScalar surfaceScale,
744 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000745 return SkNEW_ARGS(SkSpecularLightingImageFilter,
746 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
747 surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000748}
749
750SkLightingImageFilter::~SkLightingImageFilter() {
751 fLight->unref();
752}
753
754SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
755 : INHERITED(buffer)
756{
djsollen@google.com08337772012-06-26 14:33:13 +0000757 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000758 fSurfaceScale = buffer.readScalar();
759}
760
761void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
762 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000763 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000764 buffer.writeScalar(fSurfaceScale);
765}
766
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000767///////////////////////////////////////////////////////////////////////////////
768
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000769SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
770 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000771 fKD(kd)
772{
773}
774
775SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
776 : INHERITED(buffer)
777{
778 fKD = buffer.readScalar();
779}
780
781void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
782 this->INHERITED::flatten(buffer);
783 buffer.writeScalar(fKD);
784}
785
786bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
787 const SkBitmap& src,
788 const SkMatrix&,
789 SkBitmap* dst,
790 SkIPoint*) {
791 if (src.config() != SkBitmap::kARGB_8888_Config) {
792 return false;
793 }
794 SkAutoLockPixels alp(src);
795 if (!src.getPixels()) {
796 return false;
797 }
798 if (src.width() < 2 || src.height() < 2) {
799 return false;
800 }
801 dst->setConfig(src.config(), src.width(), src.height());
802 dst->allocPixels();
803
804 DiffuseLightingType lightingType(fKD);
805 switch (light()->type()) {
806 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000807 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000808 break;
809 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000810 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000811 break;
812 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000813 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000814 break;
815 }
816 return true;
817}
818
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000819bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
820 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000821#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000822 if (stage) {
823 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000824 *stage = SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light(), scale, kd()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000825 }
826 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000827#else
828 SkDEBUGFAIL("Should not call in GPU-less build");
829 return false;
830#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000831}
832
833///////////////////////////////////////////////////////////////////////////////
834
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000835SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
836 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000837 fKS(ks),
838 fShininess(shininess)
839{
840}
841
842SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
843 : INHERITED(buffer)
844{
845 fKS = buffer.readScalar();
846 fShininess = buffer.readScalar();
847}
848
849void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
850 this->INHERITED::flatten(buffer);
851 buffer.writeScalar(fKS);
852 buffer.writeScalar(fShininess);
853}
854
855bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
856 const SkBitmap& src,
857 const SkMatrix&,
858 SkBitmap* dst,
859 SkIPoint*) {
860 if (src.config() != SkBitmap::kARGB_8888_Config) {
861 return false;
862 }
863 SkAutoLockPixels alp(src);
864 if (!src.getPixels()) {
865 return false;
866 }
867 if (src.width() < 2 || src.height() < 2) {
868 return false;
869 }
870 dst->setConfig(src.config(), src.width(), src.height());
871 dst->allocPixels();
872
873 SpecularLightingType lightingType(fKS, fShininess);
874 switch (light()->type()) {
875 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000876 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000877 break;
878 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000879 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000880 break;
881 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000882 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000883 break;
884 }
885 return true;
886}
887
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000888bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
889 GrTexture* texture) const {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000890#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000891 if (stage) {
892 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000893 *stage = SkNEW_ARGS(GrSpecularLightingEffect, (texture, light(), scale, ks(), shininess()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000894 }
895 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000896#else
897 SkDEBUGFAIL("Should not call in GPU-less build");
898 return false;
899#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000900}
901
902///////////////////////////////////////////////////////////////////////////////
903
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000904#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000905class GrGLLightingEffect : public GrGLProgramStage {
906public:
907 GrGLLightingEffect(const GrProgramStageFactory& factory,
908 const GrCustomStage& stage);
909 virtual ~GrGLLightingEffect();
910
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000911 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000912 virtual void emitVS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000913 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000914 virtual void emitFS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000915 const char* outputColor,
916 const char* inputColor,
917 const char* samplerName) SK_OVERRIDE;
918
bsalomon@google.com032b2212012-07-16 13:36:18 +0000919 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000920
921 static inline StageKey GenKey(const GrCustomStage& s);
922
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000923 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000924 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000925 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000926 int stageNum) SK_OVERRIDE;
927
928private:
929 typedef GrGLProgramStage INHERITED;
930
bsalomon@google.com032b2212012-07-16 13:36:18 +0000931 UniformHandle fImageIncrementUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000932 UniformHandle fSurfaceScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000933 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000934};
935
936///////////////////////////////////////////////////////////////////////////////
937
938class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
939public:
940 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
941 const GrCustomStage& stage);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000942 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000943 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000944 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000945 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000946 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000947 int stageNum) SK_OVERRIDE;
948
949private:
950 typedef GrGLLightingEffect INHERITED;
951
bsalomon@google.com032b2212012-07-16 13:36:18 +0000952 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000953};
954
955///////////////////////////////////////////////////////////////////////////////
956
957class GrGLSpecularLightingEffect : public GrGLLightingEffect {
958public:
959 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
960 const GrCustomStage& stage);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000961 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000962 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000963 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000964 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000965 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000966 int stageNum) SK_OVERRIDE;
967
968private:
969 typedef GrGLLightingEffect INHERITED;
970
bsalomon@google.com032b2212012-07-16 13:36:18 +0000971 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000972 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000973};
974
975///////////////////////////////////////////////////////////////////////////////
976
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000977GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
978 : GrSingleTextureEffect(texture)
979 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000980 , fSurfaceScale(surfaceScale) {
981 fLight->ref();
982}
983
984GrLightingEffect::~GrLightingEffect() {
985 fLight->unref();
986}
987
988bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
989 const GrLightingEffect& s =
990 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000991 return INHERITED::isEqual(sBase) &&
992 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000993 fSurfaceScale == s.fSurfaceScale;
994}
995
996///////////////////////////////////////////////////////////////////////////////
997
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000998GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
999 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001000}
1001
1002const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
1003 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
1004}
1005
1006bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
1007 const GrDiffuseLightingEffect& s =
1008 static_cast<const GrDiffuseLightingEffect&>(sBase);
1009 return INHERITED::isEqual(sBase) &&
1010 this->kd() == s.kd();
1011}
1012
1013///////////////////////////////////////////////////////////////////////////////
1014
1015GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
1016 const GrCustomStage& stage)
1017 : GrGLProgramStage(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001018 , fImageIncrementUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001019 , fSurfaceScaleUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001020 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
1021 fLight = m.light()->createGLLight();
1022}
1023
1024GrGLLightingEffect::~GrGLLightingEffect() {
1025 delete fLight;
1026}
1027
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001028void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001029 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1030 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001031 "ImageIncrement");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001032 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1033 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001034 "SurfaceScale");
1035 fLight->setupVariables(builder);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001036}
1037
bsalomon@google.com032b2212012-07-16 13:36:18 +00001038void GrGLLightingEffect::emitVS(GrGLShaderBuilder* builder,
1039 const char* vertexCoords) {
1040 fLight->emitVS(&builder->fVSCode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001041}
1042
bsalomon@google.com032b2212012-07-16 13:36:18 +00001043void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
1044 const char* outputColor,
1045 const char* inputColor,
1046 const char* samplerName) {
1047 SkString* code = &builder->fFSCode;
1048 SkString* funcs = &builder->fFSFunctions;
1049 fLight->emitFuncs(builder, funcs);
1050 this->emitLightFunc(builder, funcs);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001051 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 +00001052 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001053 funcs->appendf("}\n");
1054 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1055 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1056 funcs->appendf("}\n");
1057 funcs->append("\n\
1058vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1059 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1060 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1061 surfaceScale);\n}\n");
1062
bsalomon@google.com032b2212012-07-16 13:36:18 +00001063 code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001064 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001065
1066 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1067 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1068
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001069 int index = 0;
1070 for (int dy = -1; dy <= 1; dy++) {
1071 for (int dx = -1; dx <= 1; dx++) {
1072 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001073 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001074 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001075 builder->emitTextureLookup(samplerName, texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001076 code->appendf(".a;\n");
1077 }
1078 }
1079 code->appendf("\t\tvec3 surfaceToLight = ");
1080 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001081 arg.appendf("%s * m[4]", surfScale);
1082 fLight->emitSurfaceToLight(builder, code, arg.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001083 code->appendf(";\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001084 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
1085 fLight->emitLightColor(builder, code, "surfaceToLight");
1086 code->appendf(")%s;\n", builder->fModulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001087}
1088
1089GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1090 const GrCustomStage& s) {
1091 return static_cast<const GrLightingEffect&>(s).light()->type();
1092}
1093
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001094void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001095 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001096 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001097 int stageNum) {
1098 const GrLightingEffect& effect =
1099 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001100 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1101 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001102 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1103 uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
1104 fLight->setData(uman, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001105}
1106
1107///////////////////////////////////////////////////////////////////////////////
1108
1109///////////////////////////////////////////////////////////////////////////////
1110
1111GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1112 const GrCustomStage& stage)
1113 : INHERITED(factory, stage)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001114 , fKDUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001115}
1116
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001117void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
1118 INHERITED::setupVariables(builder);
1119 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "KD");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001120}
1121
bsalomon@google.com032b2212012-07-16 13:36:18 +00001122void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
1123 const char* kd = builder->getUniformCStr(fKDUni);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001124 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001125 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001126 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001127 funcs->appendf("}\n");
1128}
1129
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001130void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001131 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001132 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001133 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001134 INHERITED::setData(uman, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001135 const GrDiffuseLightingEffect& effect =
1136 static_cast<const GrDiffuseLightingEffect&>(data);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001137 uman.set1f(fKDUni, effect.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001138}
1139
1140///////////////////////////////////////////////////////////////////////////////
1141
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001142GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1143 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001144 fKS(ks),
1145 fShininess(shininess) {
1146}
1147
1148const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1149 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1150}
1151
1152bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1153 const GrSpecularLightingEffect& s =
1154 static_cast<const GrSpecularLightingEffect&>(sBase);
1155 return INHERITED::isEqual(sBase) &&
1156 this->ks() == s.ks() &&
1157 this->shininess() == s.shininess();
1158}
1159
1160///////////////////////////////////////////////////////////////////////////////
1161
1162GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1163 const GrCustomStage& stage)
1164 : GrGLLightingEffect(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001165 , fKSUni(kInvalidUniformHandle)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001166 , fShininessUni(kInvalidUniformHandle) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001167}
1168
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001169void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder) {
1170 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001171 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001172 kFloat_GrSLType, "KS");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001173 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001174 kFloat_GrSLType, "Shininess");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001175}
1176
bsalomon@google.com032b2212012-07-16 13:36:18 +00001177void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001178 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1179 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1180
bsalomon@google.com032b2212012-07-16 13:36:18 +00001181 const char* ks = builder->getUniformCStr(fKSUni);
1182 const char* shininess = builder->getUniformCStr(fShininessUni);
1183 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001184 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001185 funcs->appendf("}\n");
1186}
1187
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001188void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001189 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001190 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001191 int stageNum) {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001192 INHERITED::setData(uman, data, rt, stageNum);
1193 const GrSpecularLightingEffect& effect = static_cast<const GrSpecularLightingEffect&>(data);
1194 uman.set1f(fKSUni, effect.ks());
1195 uman.set1f(fShininessUni, effect.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001196}
1197
1198///////////////////////////////////////////////////////////////////////////////
1199
bsalomon@google.com032b2212012-07-16 13:36:18 +00001200void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
1201 SkString* out,
1202 const char *surfaceToLight) const {
1203 const char* color = builder->getUniformCStr(fColorUni);
1204 out->append(color);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001205}
1206
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001207void GrGLLight::setupVariables(GrGLShaderBuilder* builder) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001208 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001209 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001210}
1211
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001212void GrGLLight::setData(const GrGLUniformManager& uman,
1213 const GrRenderTarget* rt,
1214 const SkLight* light) const {
1215 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001216}
1217
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001218///////////////////////////////////////////////////////////////////////////////
1219
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001220void GrGLDistantLight::setupVariables(GrGLShaderBuilder* builder) {
1221 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001222 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001223 "LightDirection");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001224}
1225
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001226void GrGLDistantLight::setData(const GrGLUniformManager& uman,
1227 const GrRenderTarget* rt,
1228 const SkLight* light) const {
1229 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001230 SkASSERT(light->type() == SkLight::kDistant_LightType);
1231 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001232 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001233}
1234
bsalomon@google.com032b2212012-07-16 13:36:18 +00001235void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1236 SkString* out,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001237 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001238 const char* dir = builder->getUniformCStr(fDirectionUni);
1239 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001240}
1241
1242///////////////////////////////////////////////////////////////////////////////
1243
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001244void GrGLPointLight::setupVariables(GrGLShaderBuilder* builder) {
1245 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001246 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001247 "LightLocation");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248}
1249
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001250void GrGLPointLight::setData(const GrGLUniformManager& uman,
1251 const GrRenderTarget* rt,
1252 const SkLight* light) const {
1253 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001254 SkASSERT(light->type() == SkLight::kPoint_LightType);
1255 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001256 setUniformPoint3FlipY(uman, fLocationUni, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001257}
1258
bsalomon@google.com032b2212012-07-16 13:36:18 +00001259void GrGLPointLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001260}
1261
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001262void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1263 SkString* out,
1264 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001265 const char* loc = builder->getUniformCStr(fLocationUni);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001266 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001267}
1268
1269///////////////////////////////////////////////////////////////////////////////
1270
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001271void GrGLSpotLight::setupVariables(GrGLShaderBuilder* builder) {
1272 INHERITED::setupVariables(builder);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001273 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001274 kVec3f_GrSLType, "LightLocation");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001275 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001276 kFloat_GrSLType, "Exponent");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001277 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001278 kFloat_GrSLType, "CosInnerConeAngle");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001279 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001280 kFloat_GrSLType, "CosOuterConeAngle");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001281 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001282 kFloat_GrSLType, "ConeScale");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001283 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001284 kVec3f_GrSLType, "S");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001285}
1286
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001287void GrGLSpotLight::setData(const GrGLUniformManager& uman,
1288 const GrRenderTarget* rt,
1289 const SkLight* light) const {
1290 INHERITED::setData(uman, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001291 SkASSERT(light->type() == SkLight::kSpot_LightType);
1292 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001293 setUniformPoint3FlipY(uman, fLocationUni, spotLight->location(), rt->height());
1294 uman.set1f(fExponentUni, spotLight->specularExponent());
1295 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1296 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1297 uman.set1f(fConeScaleUni, spotLight->coneScale());
1298 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001299}
1300
bsalomon@google.com032b2212012-07-16 13:36:18 +00001301void GrGLSpotLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001302}
1303
bsalomon@google.com032b2212012-07-16 13:36:18 +00001304void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
1305 const char* exponent = builder->getUniformCStr(fExponentUni);
1306 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1307 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1308 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1309 const char* s = builder->getUniformCStr(fSUni);
1310 const char* color = builder->getUniformCStr(fColorUni);
1311
1312 out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1313 out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1314 out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
1315 out->appendf("\t\treturn vec3(0);\n");
1316 out->appendf("\t}\n");
1317 out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1318 out->appendf("\tif (cosAngle < %s) {\n", cosInner);
1319 out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
1320 out->appendf("\t}\n");
1321 out->appendf("\treturn %s;\n", color);
1322 out->appendf("}\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001323}
1324
bsalomon@google.com032b2212012-07-16 13:36:18 +00001325void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1326 SkString* out,
1327 const char* z) const {
1328 const char* location= builder->getUniformCStr(fLocationUni);
1329 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001330}
1331
bsalomon@google.com032b2212012-07-16 13:36:18 +00001332void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
1333 SkString* out, const char *surfaceToLight) const {
1334 out->appendf("lightColor(%s)", surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001335}
1336
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001337#endif
1338
djsollen@google.com08337772012-06-26 14:33:13 +00001339SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1340 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1341 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1342 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1343 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1344 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1345SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END