blob: e81eac5f5277c3edcc92a79d78301d202b12ad54 [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000011#include "SkTypes.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000012#include "GrProgramStageFactory.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000013#include "effects/GrSingleTextureEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000014#include "gl/GrGLProgramStage.h"
15#include "gl/GrGLSL.h"
16#include "gl/GrGLTexture.h"
17#include "GrCustomStage.h"
18
19class GrGLDiffuseLightingEffect;
20class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000021
bsalomon@google.com032b2212012-07-16 13:36:18 +000022// For brevity, and these definitions are likely to move to a different class soon.
23typedef GrGLShaderBuilder::UniformHandle UniformHandle;
24static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
25
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000026// FIXME: Eventually, this should be implemented properly, and put in
27// SkScalar.h.
28#define SkScalarPow(x, y) SkFloatToScalar(powf(SkScalarToFloat(x), SkScalarToFloat(y)))
29namespace {
30
31const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
32const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
33const SkScalar gOneHalf = SkFloatToScalar(0.5f);
34const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
35
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000036void setUniformPoint3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
37 float x = SkScalarToFloat(point.fX);
38 float y = SkScalarToFloat(point.fY);
39 float z = SkScalarToFloat(point.fZ);
40 GR_GL_CALL(gl, Uniform3f(location, x, y, z));
41}
42
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000043void setUniformNormal3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
44 setUniformPoint3(gl, location, SkPoint3(point.fX, -point.fY, point.fZ));
45}
46
47void setUniformPoint3FlipY(const GrGLInterface* gl, GrGLint location, const SkPoint3& point, int height) {
48 setUniformPoint3(gl, location, SkPoint3(point.fX, height-point.fY, point.fZ));
49}
50
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000051// Shift matrix components to the left, as we advance pixels to the right.
52inline void shiftMatrixLeft(int m[9]) {
53 m[0] = m[1];
54 m[3] = m[4];
55 m[6] = m[7];
56 m[1] = m[2];
57 m[4] = m[5];
58 m[7] = m[8];
59}
60
61class DiffuseLightingType {
62public:
63 DiffuseLightingType(SkScalar kd)
64 : fKD(kd) {}
65 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
66 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
67 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
68 SkPoint3 color(lightColor * colorScale);
69 return SkPackARGB32(255,
70 SkScalarFloorToInt(color.fX),
71 SkScalarFloorToInt(color.fY),
72 SkScalarFloorToInt(color.fZ));
73 }
74private:
75 SkScalar fKD;
76};
77
78class SpecularLightingType {
79public:
80 SpecularLightingType(SkScalar ks, SkScalar shininess)
81 : fKS(ks), fShininess(shininess) {}
82 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
83 SkPoint3 halfDir(surfaceTolight);
84 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
85 halfDir.normalize();
86 SkScalar colorScale = SkScalarMul(fKS,
87 SkScalarPow(normal.dot(halfDir), fShininess));
88 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
89 SkPoint3 color(lightColor * colorScale);
90 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
91 SkScalarFloorToInt(color.fX),
92 SkScalarFloorToInt(color.fY),
93 SkScalarFloorToInt(color.fZ));
94 }
95private:
96 SkScalar fKS;
97 SkScalar fShininess;
98};
99
100inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
101 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
102}
103
104inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
105 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
106 SkScalarMul(-y, surfaceScale),
107 SK_Scalar1);
108 vector.normalize();
109 return vector;
110}
111
112inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
113 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
114 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
115 surfaceScale);
116}
117
118inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
119 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
120 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
121 surfaceScale);
122}
123
124inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
125 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
126 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
127 surfaceScale);
128}
129
130inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
131 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
132 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
133 surfaceScale);
134}
135
136
137inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
138 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
139 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
140 surfaceScale);
141}
142
143inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
144 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
145 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
146 surfaceScale);
147}
148
149inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
150 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
151 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
152 surfaceScale);
153}
154
155inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
156 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
157 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
158 surfaceScale);
159}
160
161inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
162 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
163 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
164 surfaceScale);
165}
166
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000167template <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 +0000168 const LightType* l = static_cast<const LightType*>(light);
169 int y = 0;
170 {
171 const SkPMColor* row1 = src.getAddr32(0, 0);
172 const SkPMColor* row2 = src.getAddr32(0, 1);
173 SkPMColor* dptr = dst->getAddr32(0, 0);
174 int m[9];
175 int x = 0;
176 m[4] = SkGetPackedA32(*row1++);
177 m[5] = SkGetPackedA32(*row1++);
178 m[7] = SkGetPackedA32(*row2++);
179 m[8] = SkGetPackedA32(*row2++);
180 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000181 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000182 for (x = 1; x < src.width() - 1; ++x)
183 {
184 shiftMatrixLeft(m);
185 m[5] = SkGetPackedA32(*row1++);
186 m[8] = SkGetPackedA32(*row2++);
187 surfaceToLight = l->surfaceToLight(x, 0, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000188 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000189 }
190 shiftMatrixLeft(m);
191 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000192 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000193 }
194
195 for (++y; y < src.height() - 1; ++y) {
196 const SkPMColor* row0 = src.getAddr32(0, y - 1);
197 const SkPMColor* row1 = src.getAddr32(0, y);
198 const SkPMColor* row2 = src.getAddr32(0, y + 1);
199 SkPMColor* dptr = dst->getAddr32(0, y);
200 int m[9];
201 int x = 0;
202 m[1] = SkGetPackedA32(*row0++);
203 m[2] = SkGetPackedA32(*row0++);
204 m[4] = SkGetPackedA32(*row1++);
205 m[5] = SkGetPackedA32(*row1++);
206 m[7] = SkGetPackedA32(*row2++);
207 m[8] = SkGetPackedA32(*row2++);
208 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000209 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 for (x = 1; x < src.width() - 1; ++x) {
211 shiftMatrixLeft(m);
212 m[2] = SkGetPackedA32(*row0++);
213 m[5] = SkGetPackedA32(*row1++);
214 m[8] = SkGetPackedA32(*row2++);
215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000216 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000217 }
218 shiftMatrixLeft(m);
219 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000220 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 }
222
223 {
224 const SkPMColor* row0 = src.getAddr32(0, src.height() - 2);
225 const SkPMColor* row1 = src.getAddr32(0, src.height() - 1);
226 int x = 0;
227 SkPMColor* dptr = dst->getAddr32(0, src.height() - 1);
228 int m[9];
229 m[1] = SkGetPackedA32(*row0++);
230 m[2] = SkGetPackedA32(*row0++);
231 m[4] = SkGetPackedA32(*row1++);
232 m[5] = SkGetPackedA32(*row1++);
233 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000234 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000235 for (x = 1; x < src.width() - 1; ++x)
236 {
237 shiftMatrixLeft(m);
238 m[2] = SkGetPackedA32(*row0++);
239 m[5] = SkGetPackedA32(*row1++);
240 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000241 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000242 }
243 shiftMatrixLeft(m);
244 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000245 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000246 }
247}
248
249SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
250 SkPoint3 point;
251 point.fX = buffer.readScalar();
252 point.fY = buffer.readScalar();
253 point.fZ = buffer.readScalar();
254 return point;
255};
256
257void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
258 buffer.writeScalar(point.fX);
259 buffer.writeScalar(point.fY);
260 buffer.writeScalar(point.fZ);
261};
262
263class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
264public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000265 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000266 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
267
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000268 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000269 SkScalar kd() const { return fKD; }
270
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271protected:
272 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
273 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
274 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
275 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
276
277
278private:
279 typedef SkLightingImageFilter INHERITED;
280 SkScalar fKD;
281};
282
283class SkSpecularLightingImageFilter : public SkLightingImageFilter {
284public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000285 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
287
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000288 virtual bool asNewCustomStage(GrCustomStage** stage, GrTexture*) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000289 SkScalar ks() const { return fKS; }
290 SkScalar shininess() const { return fShininess; }
291
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000292protected:
293 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
294 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
295 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
296 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
297
298private:
299 typedef SkLightingImageFilter INHERITED;
300 SkScalar fKS;
301 SkScalar fShininess;
302};
303
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000304
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000305class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000306public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000307 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000308 virtual ~GrLightingEffect();
309
310 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
311
312 const SkLight* light() const { return fLight; }
313 SkScalar surfaceScale() const { return fSurfaceScale; }
314private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000315 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000316 const SkLight* fLight;
317 SkScalar fSurfaceScale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000318};
319
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000320class GrDiffuseLightingEffect : public GrLightingEffect {
321public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000322 GrDiffuseLightingEffect(GrTexture* texture,
323 const SkLight* light,
324 SkScalar surfaceScale,
325 SkScalar kd);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000326
327 static const char* Name() { return "DiffuseLighting"; }
328
329 typedef GrGLDiffuseLightingEffect GLProgramStage;
330
331 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
332 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
333 SkScalar kd() const { return fKD; }
334private:
335 typedef GrLightingEffect INHERITED;
336 SkScalar fKD;
337};
338
339class GrSpecularLightingEffect : public GrLightingEffect {
340public:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000341 GrSpecularLightingEffect(GrTexture* texture,
342 const SkLight* light,
343 SkScalar surfaceScale,
344 SkScalar ks,
345 SkScalar shininess);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000346
347 static const char* Name() { return "SpecularLighting"; }
348
349 typedef GrGLSpecularLightingEffect GLProgramStage;
350
351 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
352 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
353 SkScalar ks() const { return fKS; }
354 SkScalar shininess() const { return fShininess; }
355
356private:
357 typedef GrLightingEffect INHERITED;
358 SkScalar fKS;
359 SkScalar fShininess;
360};
361
362///////////////////////////////////////////////////////////////////////////////
363
364class GrGLLight {
365public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000366 virtual ~GrGLLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000367 virtual void setupVariables(GrGLShaderBuilder* builder, int stage);
368 virtual void emitVS(SkString* out) const {}
369 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {}
370 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
371 SkString* out,
372 const char* z) const = 0;
373 virtual void emitLightColor(const GrGLShaderBuilder*,
374 SkString* out,
375 const char *surfaceToLight) const;
376 virtual void initUniforms(const GrGLShaderBuilder*, const GrGLInterface* gl, int programID);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000377 virtual void setData(const GrGLInterface*, const GrRenderTarget* rt, const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000378
379private:
380 typedef SkRefCnt INHERITED;
381
382protected:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000383 UniformHandle fColorUni;
384 int fColorLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000385};
386
387///////////////////////////////////////////////////////////////////////////////
388
389class GrGLDistantLight : public GrGLLight {
390public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000391 virtual ~GrGLDistantLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000392 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
393 virtual void initUniforms(const GrGLShaderBuilder*,
394 const GrGLInterface* gl,
395 int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000396 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000397 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
398 SkString* out,
399 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000400
401private:
402 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000403 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000404 int fDirectionLocation;
405};
406
407///////////////////////////////////////////////////////////////////////////////
408
409class GrGLPointLight : public GrGLLight {
410public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000411 virtual ~GrGLPointLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000412 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
413 virtual void initUniforms(const GrGLShaderBuilder*,
414 const GrGLInterface*,
415 int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000416 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000417 virtual void emitVS(SkString* out) const SK_OVERRIDE;
418 virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
419 SkString* out,
420 const char* z) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000421
422private:
423 typedef GrGLLight INHERITED;
424 SkPoint3 fLocation;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000425 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000426 int fLocationLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000427};
428
429///////////////////////////////////////////////////////////////////////////////
430
431class GrGLSpotLight : public GrGLLight {
432public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000433 virtual ~GrGLSpotLight() {}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000434 virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
435 virtual void initUniforms(const GrGLShaderBuilder* builder,
436 const GrGLInterface* gl,
437 int programID) SK_OVERRIDE;
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000438 virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000439 virtual void emitVS(SkString* out) const SK_OVERRIDE;
440 virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
441 virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
442 SkString* out,
443 const char* z) const SK_OVERRIDE;
444 virtual void emitLightColor(const GrGLShaderBuilder*,
445 SkString* out,
446 const char *surfaceToLight) const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000447
448private:
449 typedef GrGLLight INHERITED;
450
bsalomon@google.com032b2212012-07-16 13:36:18 +0000451 UniformHandle fLocationUni;
452 int fLocationLocation;
453 UniformHandle fExponentUni;
454 int fExponentLocation;
455 UniformHandle fCosOuterConeAngleUni;
456 int fCosOuterConeAngleLocation;
457 UniformHandle fCosInnerConeAngleUni;
458 int fCosInnerConeAngleLocation;
459 UniformHandle fConeScaleUni;
460 int fConeScaleLocation;
461 UniformHandle fSUni;
462 int fSLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000463};
464
465};
466
467///////////////////////////////////////////////////////////////////////////////
468
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000469class SkLight : public SkFlattenable {
470public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000471 SK_DECLARE_INST_COUNT(SkLight)
472
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000473 enum LightType {
474 kDistant_LightType,
475 kPoint_LightType,
476 kSpot_LightType,
477 };
478 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000479 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000480 virtual GrGLLight* createGLLight() const = 0;
481 virtual bool isEqual(const SkLight& other) const {
482 return fColor == other.fColor;
483 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000484
djsollen@google.com08337772012-06-26 14:33:13 +0000485protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000486 SkLight(SkColor color)
487 : fColor(SkIntToScalar(SkColorGetR(color)),
488 SkIntToScalar(SkColorGetG(color)),
489 SkIntToScalar(SkColorGetB(color))) {}
490 SkLight(SkFlattenableReadBuffer& buffer)
491 : INHERITED(buffer) {
492 fColor = readPoint3(buffer);
493 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000494 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000495 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000496 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000497 }
djsollen@google.com08337772012-06-26 14:33:13 +0000498
499private:
500 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000501 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000502};
503
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000504SK_DEFINE_INST_COUNT(SkLight)
505
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506///////////////////////////////////////////////////////////////////////////////
507
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000508class SkDistantLight : public SkLight {
509public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000510 SkDistantLight(const SkPoint3& direction, SkColor color)
511 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512 }
djsollen@google.com08337772012-06-26 14:33:13 +0000513
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000514 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
515 return fDirection;
516 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000517 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000518 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000519 const SkPoint3& direction() const { return fDirection; }
520 virtual GrGLLight* createGLLight() const SK_OVERRIDE;
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000521 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
522 if (other.type() != kDistant_LightType) {
523 return false;
524 }
525
526 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
527 return INHERITED::isEqual(other) &&
528 fDirection == o.fDirection;
529 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000530
531 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
532
djsollen@google.com08337772012-06-26 14:33:13 +0000533protected:
534 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
535 fDirection = readPoint3(buffer);
536 }
537 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
538 INHERITED::flatten(buffer);
539 writePoint3(fDirection, buffer);
540 }
541
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000542private:
djsollen@google.com08337772012-06-26 14:33:13 +0000543 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000544 SkPoint3 fDirection;
545};
546
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000547///////////////////////////////////////////////////////////////////////////////
548
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000549class SkPointLight : public SkLight {
550public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000551 SkPointLight(const SkPoint3& location, SkColor color)
552 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000553
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000554 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
555 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
556 fLocation.fY - SkIntToScalar(y),
557 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
558 direction.normalize();
559 return direction;
560 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000561 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000562 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000563 const SkPoint3& location() const { return fLocation; }
564 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000565 return SkNEW(GrGLPointLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566 }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000567 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000568 if (other.type() != kPoint_LightType) {
569 return false;
570 }
571 const SkPointLight& o = static_cast<const SkPointLight&>(other);
572 return INHERITED::isEqual(other) &&
573 fLocation == o.fLocation;
574 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000575
576 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
577
djsollen@google.com08337772012-06-26 14:33:13 +0000578protected:
579 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
580 fLocation = readPoint3(buffer);
581 }
582 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
583 INHERITED::flatten(buffer);
584 writePoint3(fLocation, buffer);
585 }
586
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000587private:
djsollen@google.com08337772012-06-26 14:33:13 +0000588 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589 SkPoint3 fLocation;
590};
591
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000592///////////////////////////////////////////////////////////////////////////////
593
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000594class SkSpotLight : public SkLight {
595public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000596 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
597 : INHERITED(color),
598 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000599 fTarget(target),
600 fSpecularExponent(specularExponent)
601 {
602 fS = target - location;
603 fS.normalize();
604 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
605 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
606 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
607 fConeScale = SkScalarInvert(antiAliasThreshold);
608 }
djsollen@google.com08337772012-06-26 14:33:13 +0000609
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000610 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
611 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
612 fLocation.fY - SkIntToScalar(y),
613 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
614 direction.normalize();
615 return direction;
616 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000617 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000618 SkScalar cosAngle = -surfaceToLight.dot(fS);
619 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000620 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000621 }
622 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
623 if (cosAngle < fCosInnerConeAngle) {
624 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000625 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000626 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000627 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000628 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000629 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000630 return SkNEW(GrGLSpotLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000631 }
djsollen@google.com08337772012-06-26 14:33:13 +0000632 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633 const SkPoint3& location() const { return fLocation; }
634 const SkPoint3& target() const { return fTarget; }
635 SkScalar specularExponent() const { return fSpecularExponent; }
636 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
637 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
638 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000639 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000640
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000641 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
642
djsollen@google.com08337772012-06-26 14:33:13 +0000643protected:
644 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
645 fLocation = readPoint3(buffer);
646 fTarget = readPoint3(buffer);
647 fSpecularExponent = buffer.readScalar();
648 fCosOuterConeAngle = buffer.readScalar();
649 fCosInnerConeAngle = buffer.readScalar();
650 fConeScale = buffer.readScalar();
651 fS = readPoint3(buffer);
652 }
653 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
654 INHERITED::flatten(buffer);
655 writePoint3(fLocation, buffer);
656 writePoint3(fTarget, buffer);
657 buffer.writeScalar(fSpecularExponent);
658 buffer.writeScalar(fCosOuterConeAngle);
659 buffer.writeScalar(fCosInnerConeAngle);
660 buffer.writeScalar(fConeScale);
661 writePoint3(fS, buffer);
662 }
663
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000664 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000665 if (other.type() != kSpot_LightType) {
666 return false;
667 }
668
669 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
670 return INHERITED::isEqual(other) &&
671 fLocation == o.fLocation &&
672 fTarget == o.fTarget &&
673 fSpecularExponent == o.fSpecularExponent &&
674 fCosOuterConeAngle == o.fCosOuterConeAngle;
675 }
676
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000677private:
djsollen@google.com08337772012-06-26 14:33:13 +0000678 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000679 SkPoint3 fLocation;
680 SkPoint3 fTarget;
681 SkScalar fSpecularExponent;
682 SkScalar fCosOuterConeAngle;
683 SkScalar fCosInnerConeAngle;
684 SkScalar fConeScale;
685 SkPoint3 fS;
686};
687
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000688///////////////////////////////////////////////////////////////////////////////
689
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000690SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691 : fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000692 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
693{
694 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000695 // our caller knows that we take ownership of the light, so we don't
696 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000697}
698
699SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000700 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701 SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000702 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
703 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704}
705
706SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000707 const SkPoint3& location, 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(SkPointLight, (location, lightColor)), surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711}
712
713SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000714 const SkPoint3& location, const SkPoint3& target,
715 SkScalar specularExponent, SkScalar cutoffAngle,
716 SkColor lightColor, SkScalar surfaceScale, SkScalar kd) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000717 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
718 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
719 surfaceScale, kd));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000720}
721
722SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000723 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000724 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000725 return SkNEW_ARGS(SkSpecularLightingImageFilter,
726 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000727}
728
729SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000730 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
731 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000732 return SkNEW_ARGS(SkSpecularLightingImageFilter,
733 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000734}
735
736SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000737 const SkPoint3& location, const SkPoint3& target,
738 SkScalar specularExponent, SkScalar cutoffAngle,
739 SkColor lightColor, SkScalar surfaceScale,
740 SkScalar ks, SkScalar shininess) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000741 return SkNEW_ARGS(SkSpecularLightingImageFilter,
742 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
743 surfaceScale, ks, shininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000744}
745
746SkLightingImageFilter::~SkLightingImageFilter() {
747 fLight->unref();
748}
749
750SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
751 : INHERITED(buffer)
752{
djsollen@google.com08337772012-06-26 14:33:13 +0000753 fLight = (SkLight*)buffer.readFlattenable();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000754 fSurfaceScale = buffer.readScalar();
755}
756
757void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
758 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000759 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000760 buffer.writeScalar(fSurfaceScale);
761}
762
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000763///////////////////////////////////////////////////////////////////////////////
764
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000765SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd)
766 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000767 fKD(kd)
768{
769}
770
771SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
772 : INHERITED(buffer)
773{
774 fKD = buffer.readScalar();
775}
776
777void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
778 this->INHERITED::flatten(buffer);
779 buffer.writeScalar(fKD);
780}
781
782bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
783 const SkBitmap& src,
784 const SkMatrix&,
785 SkBitmap* dst,
786 SkIPoint*) {
787 if (src.config() != SkBitmap::kARGB_8888_Config) {
788 return false;
789 }
790 SkAutoLockPixels alp(src);
791 if (!src.getPixels()) {
792 return false;
793 }
794 if (src.width() < 2 || src.height() < 2) {
795 return false;
796 }
797 dst->setConfig(src.config(), src.width(), src.height());
798 dst->allocPixels();
799
800 DiffuseLightingType lightingType(fKD);
801 switch (light()->type()) {
802 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000803 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000804 break;
805 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000806 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000807 break;
808 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000809 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000810 break;
811 }
812 return true;
813}
814
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000815bool SkDiffuseLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
816 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000817 if (stage) {
818 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000819 *stage = SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light(), scale, kd()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000820 }
821 return true;
822}
823
824///////////////////////////////////////////////////////////////////////////////
825
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000826SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
827 : SkLightingImageFilter(light, surfaceScale),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000828 fKS(ks),
829 fShininess(shininess)
830{
831}
832
833SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
834 : INHERITED(buffer)
835{
836 fKS = buffer.readScalar();
837 fShininess = buffer.readScalar();
838}
839
840void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
841 this->INHERITED::flatten(buffer);
842 buffer.writeScalar(fKS);
843 buffer.writeScalar(fShininess);
844}
845
846bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
847 const SkBitmap& src,
848 const SkMatrix&,
849 SkBitmap* dst,
850 SkIPoint*) {
851 if (src.config() != SkBitmap::kARGB_8888_Config) {
852 return false;
853 }
854 SkAutoLockPixels alp(src);
855 if (!src.getPixels()) {
856 return false;
857 }
858 if (src.width() < 2 || src.height() < 2) {
859 return false;
860 }
861 dst->setConfig(src.config(), src.width(), src.height());
862 dst->allocPixels();
863
864 SpecularLightingType lightingType(fKS, fShininess);
865 switch (light()->type()) {
866 case SkLight::kDistant_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000867 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000868 break;
869 case SkLight::kPoint_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000870 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000871 break;
872 case SkLight::kSpot_LightType:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000873 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, light(), src, dst, surfaceScale());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000874 break;
875 }
876 return true;
877}
878
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000879bool SkSpecularLightingImageFilter::asNewCustomStage(GrCustomStage** stage,
880 GrTexture* texture) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000881 if (stage) {
882 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
tomhudson@google.com300f5622012-07-20 14:15:22 +0000883 *stage = SkNEW_ARGS(GrSpecularLightingEffect, (texture, light(), scale, ks(), shininess()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000884 }
885 return true;
886}
887
888///////////////////////////////////////////////////////////////////////////////
889
890class GrGLLightingEffect : public GrGLProgramStage {
891public:
892 GrGLLightingEffect(const GrProgramStageFactory& factory,
893 const GrCustomStage& stage);
894 virtual ~GrGLLightingEffect();
895
bsalomon@google.com032b2212012-07-16 13:36:18 +0000896 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000897 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000898 virtual void emitVS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000899 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000900 virtual void emitFS(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000901 const char* outputColor,
902 const char* inputColor,
903 const char* samplerName) SK_OVERRIDE;
904
bsalomon@google.com032b2212012-07-16 13:36:18 +0000905 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) = 0;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000906
907 static inline StageKey GenKey(const GrCustomStage& s);
908
bsalomon@google.com032b2212012-07-16 13:36:18 +0000909 virtual void initUniforms(const GrGLShaderBuilder* builder,
910 const GrGLInterface*,
911 int programID) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000912 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000913 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000914 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000915 int stageNum) SK_OVERRIDE;
916
917private:
918 typedef GrGLProgramStage INHERITED;
919
bsalomon@google.com032b2212012-07-16 13:36:18 +0000920 UniformHandle fImageIncrementUni;
921 GrGLint fImageIncrementLocation;
922 UniformHandle fSurfaceScaleUni;
923 GrGLint fSurfaceScaleLocation;
924 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000925};
926
927///////////////////////////////////////////////////////////////////////////////
928
929class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
930public:
931 GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
932 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000933 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000934 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000935 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
936 virtual void initUniforms(const GrGLShaderBuilder*,
937 const GrGLInterface*,
938 int programID) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000939 virtual void setData(const GrGLInterface*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000940 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000941 const GrRenderTarget*,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000942 int stageNum) SK_OVERRIDE;
943
944private:
945 typedef GrGLLightingEffect INHERITED;
946
bsalomon@google.com032b2212012-07-16 13:36:18 +0000947 UniformHandle fKDUni;
948 GrGLint fKDLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000949};
950
951///////////////////////////////////////////////////////////////////////////////
952
953class GrGLSpecularLightingEffect : public GrGLLightingEffect {
954public:
955 GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
956 const GrCustomStage& stage);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000957 virtual void setupVariables(GrGLShaderBuilder* builder,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000958 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000959 virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
960 virtual void initUniforms(const GrGLShaderBuilder*,
961 const GrGLInterface*,
962 int programID) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000963 virtual void setData(const GrGLInterface*,
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;
972 GrGLint fKSLocation;
973 UniformHandle fShininessUni;
974 GrGLint fShininessLocation;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000975};
976
977///////////////////////////////////////////////////////////////////////////////
978
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000979GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale)
980 : GrSingleTextureEffect(texture)
981 , fLight(light)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000982 , fSurfaceScale(surfaceScale) {
983 fLight->ref();
984}
985
986GrLightingEffect::~GrLightingEffect() {
987 fLight->unref();
988}
989
990bool GrLightingEffect::isEqual(const GrCustomStage& sBase) const {
991 const GrLightingEffect& s =
992 static_cast<const GrLightingEffect&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000993 return INHERITED::isEqual(sBase) &&
994 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000995 fSurfaceScale == s.fSurfaceScale;
996}
997
998///////////////////////////////////////////////////////////////////////////////
999
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001000GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar kd)
1001 : INHERITED(texture, light, surfaceScale), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001002}
1003
1004const GrProgramStageFactory& GrDiffuseLightingEffect::getFactory() const {
1005 return GrTProgramStageFactory<GrDiffuseLightingEffect>::getInstance();
1006}
1007
1008bool GrDiffuseLightingEffect::isEqual(const GrCustomStage& sBase) const {
1009 const GrDiffuseLightingEffect& s =
1010 static_cast<const GrDiffuseLightingEffect&>(sBase);
1011 return INHERITED::isEqual(sBase) &&
1012 this->kd() == s.kd();
1013}
1014
1015///////////////////////////////////////////////////////////////////////////////
1016
1017GrGLLightingEffect::GrGLLightingEffect(const GrProgramStageFactory& factory,
1018 const GrCustomStage& stage)
1019 : GrGLProgramStage(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001020 , fImageIncrementUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001021 , fImageIncrementLocation(0)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001022 , fSurfaceScaleUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001023 , fSurfaceScaleLocation(0) {
1024 const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
1025 fLight = m.light()->createGLLight();
1026}
1027
1028GrGLLightingEffect::~GrGLLightingEffect() {
1029 delete fLight;
1030}
1031
bsalomon@google.com032b2212012-07-16 13:36:18 +00001032void GrGLLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1033 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1034 kVec2f_GrSLType,
1035 "uImageIncrement", stage);
1036 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1037 kFloat_GrSLType,
1038 "uSurfaceScale", stage);
1039 fLight->setupVariables(builder, stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001040}
1041
bsalomon@google.com032b2212012-07-16 13:36:18 +00001042void GrGLLightingEffect::emitVS(GrGLShaderBuilder* builder,
1043 const char* vertexCoords) {
1044 fLight->emitVS(&builder->fVSCode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001045}
1046
bsalomon@google.com032b2212012-07-16 13:36:18 +00001047void GrGLLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
1048 const GrGLInterface* gl,
1049 int programID) {
1050 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1051 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1052
1053 GR_GL_CALL_RET(gl, fSurfaceScaleLocation, GetUniformLocation(programID, surfScale));
1054 GR_GL_CALL_RET(gl, fImageIncrementLocation, GetUniformLocation(programID, imgInc));
1055 fLight->initUniforms(builder, gl, programID);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001056}
1057
bsalomon@google.com032b2212012-07-16 13:36:18 +00001058void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
1059 const char* outputColor,
1060 const char* inputColor,
1061 const char* samplerName) {
1062 SkString* code = &builder->fFSCode;
1063 SkString* funcs = &builder->fFSFunctions;
1064 fLight->emitFuncs(builder, funcs);
1065 this->emitLightFunc(builder, funcs);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001066 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 +00001067 funcs->appendf("\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001068 funcs->appendf("}\n");
1069 funcs->appendf("vec3 pointToNormal(float x, float y, float scale) {\n");
1070 funcs->appendf("\treturn normalize(vec3(-x * scale, -y * scale, 1));\n");
1071 funcs->appendf("}\n");
1072 funcs->append("\n\
1073vec3 interiorNormal(float m[9], float surfaceScale) {\n\
1074 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n\
1075 sobel(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n\
1076 surfaceScale);\n}\n");
1077
bsalomon@google.com032b2212012-07-16 13:36:18 +00001078 code->appendf("\t\tvec2 coord = %s;\n", builder->fSampleCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001079 code->appendf("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001080
1081 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1082 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1083
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001084 int index = 0;
1085 for (int dy = -1; dy <= 1; dy++) {
1086 for (int dx = -1; dx <= 1; dx++) {
1087 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001088 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001089 code->appendf("\t\tm[%d] = ", index++);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001090 builder->emitTextureLookup(samplerName, texCoords.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001091 code->appendf(".a;\n");
1092 }
1093 }
1094 code->appendf("\t\tvec3 surfaceToLight = ");
1095 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001096 arg.appendf("%s * m[4]", surfScale);
1097 fLight->emitSurfaceToLight(builder, code, arg.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001098 code->appendf(";\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001099 code->appendf("\t\t%s = light(interiorNormal(m, %s), surfaceToLight, ", outputColor, surfScale);
1100 fLight->emitLightColor(builder, code, "surfaceToLight");
1101 code->appendf(")%s;\n", builder->fModulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001102}
1103
1104GrGLProgramStage::StageKey GrGLLightingEffect::GenKey(
1105 const GrCustomStage& s) {
1106 return static_cast<const GrLightingEffect&>(s).light()->type();
1107}
1108
1109void GrGLLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001110 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001111 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001112 int stageNum) {
1113 const GrLightingEffect& effect =
1114 static_cast<const GrLightingEffect&>(data);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001115 GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
1116 float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
1117 GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture->width(), ySign / texture->height()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001118 GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001119 fLight->setData(gl, rt, effect.light());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001120}
1121
1122///////////////////////////////////////////////////////////////////////////////
1123
1124///////////////////////////////////////////////////////////////////////////////
1125
1126GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
1127 const GrCustomStage& stage)
1128 : INHERITED(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001129 , fKDUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001130 , fKDLocation(0) {
1131}
1132
bsalomon@google.com032b2212012-07-16 13:36:18 +00001133void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1134 INHERITED::setupVariables(builder, stage);
1135 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "uKD",
1136 stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001137}
1138
bsalomon@google.com032b2212012-07-16 13:36:18 +00001139void GrGLDiffuseLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
1140 const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001141 int programID) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001142 INHERITED::initUniforms(builder, gl, programID);
1143 const char* kd = builder->getUniformCStr(fKDUni);
1144 GR_GL_CALL_RET(gl, fKDLocation, GetUniformLocation(programID, kd));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001145}
1146
bsalomon@google.com032b2212012-07-16 13:36:18 +00001147void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
1148 const char* kd = builder->getUniformCStr(fKDUni);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001149 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001150 funcs->appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001151 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001152 funcs->appendf("}\n");
1153}
1154
1155void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001156 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001157 const GrRenderTarget* rt,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001158 int stageNum) {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001159 INHERITED::setData(gl, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001160 const GrDiffuseLightingEffect& effect =
1161 static_cast<const GrDiffuseLightingEffect&>(data);
1162 GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
1163}
1164
1165///////////////////////////////////////////////////////////////////////////////
1166
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001167GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess)
1168 : INHERITED(texture, light, surfaceScale),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001169 fKS(ks),
1170 fShininess(shininess) {
1171}
1172
1173const GrProgramStageFactory& GrSpecularLightingEffect::getFactory() const {
1174 return GrTProgramStageFactory<GrSpecularLightingEffect>::getInstance();
1175}
1176
1177bool GrSpecularLightingEffect::isEqual(const GrCustomStage& sBase) const {
1178 const GrSpecularLightingEffect& s =
1179 static_cast<const GrSpecularLightingEffect&>(sBase);
1180 return INHERITED::isEqual(sBase) &&
1181 this->ks() == s.ks() &&
1182 this->shininess() == s.shininess();
1183}
1184
1185///////////////////////////////////////////////////////////////////////////////
1186
1187GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProgramStageFactory& factory,
1188 const GrCustomStage& stage)
1189 : GrGLLightingEffect(factory, stage)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001190 , fKSUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001191 , fKSLocation(0)
bsalomon@google.com032b2212012-07-16 13:36:18 +00001192 , fShininessUni(kInvalidUniformHandle)
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001193 , fShininessLocation(0) {
1194}
1195
bsalomon@google.com032b2212012-07-16 13:36:18 +00001196void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
1197 INHERITED::setupVariables(builder, stage);
1198 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1199 kFloat_GrSLType, "uKS", stage);
1200 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1201 kFloat_GrSLType, "uShininess", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001202}
1203
bsalomon@google.com032b2212012-07-16 13:36:18 +00001204void GrGLSpecularLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
1205 const GrGLInterface* gl,
1206 int programID) {
1207 INHERITED::initUniforms(builder, gl, programID);
1208 const char* ks = builder->getUniformCStr(fKSUni);
1209 const char* shininess = builder->getUniformCStr(fShininessUni);
1210 GR_GL_CALL_RET(gl, fKSLocation, GetUniformLocation(programID, ks));
1211 GR_GL_CALL_RET(gl, fShininessLocation, GetUniformLocation(programID, shininess));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001212}
1213
bsalomon@google.com032b2212012-07-16 13:36:18 +00001214void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001215 funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
1216 funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1217
bsalomon@google.com032b2212012-07-16 13:36:18 +00001218 const char* ks = builder->getUniformCStr(fKSUni);
1219 const char* shininess = builder->getUniformCStr(fShininessUni);
1220 funcs->appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org0ec1eab2012-07-11 16:44:49 +00001221 funcs->appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001222 funcs->appendf("}\n");
1223}
1224
1225void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001226 const GrCustomStage& data,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001227 const GrRenderTarget* rt,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001228 int stageNum) {
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001229 INHERITED::setData(gl, data, rt, stageNum);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001230 const GrSpecularLightingEffect& effect =
1231 static_cast<const GrSpecularLightingEffect&>(data);
1232 GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
1233 GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
1234}
1235
1236///////////////////////////////////////////////////////////////////////////////
1237
bsalomon@google.com032b2212012-07-16 13:36:18 +00001238void GrGLLight::emitLightColor(const GrGLShaderBuilder* builder,
1239 SkString* out,
1240 const char *surfaceToLight) const {
1241 const char* color = builder->getUniformCStr(fColorUni);
1242 out->append(color);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001243}
1244
bsalomon@google.com032b2212012-07-16 13:36:18 +00001245void GrGLLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001246 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1247 kVec3f_GrSLType, "uLightColor", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001248}
1249
bsalomon@google.com032b2212012-07-16 13:36:18 +00001250void GrGLLight::initUniforms(const GrGLShaderBuilder* builder,
1251 const GrGLInterface* gl,
1252 int programID) {
1253 const char* color = builder->getUniformCStr(fColorUni);
1254 GR_GL_CALL_RET(gl, fColorLocation, GetUniformLocation(programID, color));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001255}
1256
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001257void GrGLLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001258 setUniformPoint3(gl, fColorLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001259}
1260
1261GrGLLight* SkDistantLight::createGLLight() const {
tomhudson@google.com300f5622012-07-20 14:15:22 +00001262 return SkNEW(GrGLDistantLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001263}
1264
1265///////////////////////////////////////////////////////////////////////////////
1266
bsalomon@google.com032b2212012-07-16 13:36:18 +00001267void GrGLDistantLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1268 INHERITED::setupVariables(builder, stage);
1269 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1270 "uLightDirection", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001271}
1272
bsalomon@google.com032b2212012-07-16 13:36:18 +00001273void GrGLDistantLight::initUniforms(const GrGLShaderBuilder* builder,
1274 const GrGLInterface* gl,
1275 int programID) {
1276 INHERITED::initUniforms(builder, gl, programID);
1277 const char* dir = builder->getUniformCStr(fDirectionUni);
1278 GR_GL_CALL_RET(gl, fDirectionLocation, GetUniformLocation(programID, dir));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001279}
1280
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001281void GrGLDistantLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1282 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001283 SkASSERT(light->type() == SkLight::kDistant_LightType);
1284 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001285 setUniformNormal3(gl, fDirectionLocation, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001286}
1287
bsalomon@google.com032b2212012-07-16 13:36:18 +00001288void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1289 SkString* out,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001290 const char* z) const {
bsalomon@google.com032b2212012-07-16 13:36:18 +00001291 const char* dir = builder->getUniformCStr(fDirectionUni);
1292 out->append(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001293}
1294
1295///////////////////////////////////////////////////////////////////////////////
1296
bsalomon@google.com032b2212012-07-16 13:36:18 +00001297void GrGLPointLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1298 INHERITED::setupVariables(builder, stage);
1299 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
1300 "uLightLocation", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001301}
1302
bsalomon@google.com032b2212012-07-16 13:36:18 +00001303void GrGLPointLight::initUniforms(const GrGLShaderBuilder* builder,
1304 const GrGLInterface* gl,
1305 int programID) {
1306 INHERITED::initUniforms(builder, gl, programID);
1307 const char* loc = builder->getUniformCStr(fLocationUni);
1308 GR_GL_CALL_RET(gl, fLocationLocation, GetUniformLocation(programID, loc));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001309}
1310
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001311void GrGLPointLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1312 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001313 SkASSERT(light->type() == SkLight::kPoint_LightType);
1314 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001315 setUniformPoint3FlipY(gl, fLocationLocation, pointLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001316}
1317
bsalomon@google.com032b2212012-07-16 13:36:18 +00001318void GrGLPointLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001319}
1320
bsalomon@google.com032b2212012-07-16 13:36:18 +00001321void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder, SkString* out, const char* z) const {
1322 const char* loc = builder->getUniformCStr(fLocationUni);
1323 out->appendf(
1324 "normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001325}
1326
1327///////////////////////////////////////////////////////////////////////////////
1328
bsalomon@google.com032b2212012-07-16 13:36:18 +00001329void GrGLSpotLight::setupVariables(GrGLShaderBuilder* builder, int stage) {
1330 INHERITED::setupVariables(builder, stage);
1331 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1332 kVec3f_GrSLType, "uLightLocation", stage);
1333 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1334 kFloat_GrSLType, "uExponent", stage);
1335 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1336 kFloat_GrSLType, "uCosInnerConeAngle", stage);
1337 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1338 kFloat_GrSLType, "uCosOuterConeAngle", stage);
1339 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1340 kFloat_GrSLType, "uConeScale", stage);
1341 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
1342 kVec3f_GrSLType, "uS", stage);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001343}
1344
bsalomon@google.com032b2212012-07-16 13:36:18 +00001345void GrGLSpotLight::initUniforms(const GrGLShaderBuilder* builder, const GrGLInterface* gl, int programID) {
1346 INHERITED::initUniforms(builder, gl, programID);
1347 const char* location = builder->getUniformCStr(fLocationUni);
1348 const char* exponent = builder->getUniformCStr(fExponentUni);
1349 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1350 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1351 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1352 const char* s = builder->getUniformCStr(fSUni);
1353 GR_GL_CALL_RET(gl, fLocationLocation, GetUniformLocation(programID, location));
1354 GR_GL_CALL_RET(gl, fExponentLocation, GetUniformLocation(programID, exponent));
1355 GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation, GetUniformLocation(programID, cosInner));
1356 GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation, GetUniformLocation(programID, cosOuter));
1357 GR_GL_CALL_RET(gl, fConeScaleLocation, GetUniformLocation(programID, coneScale));
1358 GR_GL_CALL_RET(gl, fSLocation, GetUniformLocation(programID, s));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001359}
1360
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001361void GrGLSpotLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
1362 INHERITED::setData(gl, rt, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001363 SkASSERT(light->type() == SkLight::kSpot_LightType);
1364 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001365 setUniformPoint3FlipY(gl, fLocationLocation, spotLight->location(), rt->height());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001366 GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
1367 GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
1368 GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
1369 GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +00001370 setUniformNormal3(gl, fSLocation, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001371}
1372
bsalomon@google.com032b2212012-07-16 13:36:18 +00001373void GrGLSpotLight::emitVS(SkString* out) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001374}
1375
bsalomon@google.com032b2212012-07-16 13:36:18 +00001376void GrGLSpotLight::emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const {
1377 const char* exponent = builder->getUniformCStr(fExponentUni);
1378 const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
1379 const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
1380 const char* coneScale = builder->getUniformCStr(fConeScaleUni);
1381 const char* s = builder->getUniformCStr(fSUni);
1382 const char* color = builder->getUniformCStr(fColorUni);
1383
1384 out->appendf("vec3 lightColor(vec3 surfaceToLight) {\n");
1385 out->appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1386 out->appendf("\tif (cosAngle < %s) {\n", cosOuter);
1387 out->appendf("\t\treturn vec3(0);\n");
1388 out->appendf("\t}\n");
1389 out->appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1390 out->appendf("\tif (cosAngle < %s) {\n", cosInner);
1391 out->appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n", color, cosOuter, coneScale);
1392 out->appendf("\t}\n");
1393 out->appendf("\treturn %s;\n", color);
1394 out->appendf("}\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001395}
1396
bsalomon@google.com032b2212012-07-16 13:36:18 +00001397void GrGLSpotLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
1398 SkString* out,
1399 const char* z) const {
1400 const char* location= builder->getUniformCStr(fLocationUni);
1401 out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001402}
1403
bsalomon@google.com032b2212012-07-16 13:36:18 +00001404void GrGLSpotLight::emitLightColor(const GrGLShaderBuilder* builder,
1405 SkString* out, const char *surfaceToLight) const {
1406 out->appendf("lightColor(%s)", surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001407}
1408
djsollen@google.com08337772012-06-26 14:33:13 +00001409SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1410 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1411 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1412 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1413 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1414 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1415SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END