blob: 4f05d2569e23b023d27feef227873e9a331ce0d2 [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkFlattenableBuffers.h"
12#include "SkOrderedReadBuffer.h"
13#include "SkOrderedWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000015
16#if SK_SUPPORT_GPU
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000017#include "effects/GrSingleTextureEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000018#include "gl/GrGLEffect.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000019#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000020#include "GrTBackendEffectFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000021
22class GrGLDiffuseLightingEffect;
23class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000024
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000025// For brevity
26typedef GrGLUniformManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000027#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000028
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000029namespace {
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
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000036#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000037void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000038 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000039 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000040}
41
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000042void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000043 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000044}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000045#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000046
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000047// Shift matrix components to the left, as we advance pixels to the right.
48inline void shiftMatrixLeft(int m[9]) {
49 m[0] = m[1];
50 m[3] = m[4];
51 m[6] = m[7];
52 m[1] = m[2];
53 m[4] = m[5];
54 m[7] = m[8];
55}
56
57class DiffuseLightingType {
58public:
59 DiffuseLightingType(SkScalar kd)
60 : fKD(kd) {}
61 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
62 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
63 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
64 SkPoint3 color(lightColor * colorScale);
65 return SkPackARGB32(255,
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000066 SkClampMax(SkScalarFloorToInt(color.fX), 255),
67 SkClampMax(SkScalarFloorToInt(color.fY), 255),
68 SkClampMax(SkScalarFloorToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000069 }
70private:
71 SkScalar fKD;
72};
73
74class SpecularLightingType {
75public:
76 SpecularLightingType(SkScalar ks, SkScalar shininess)
77 : fKS(ks), fShininess(shininess) {}
78 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
79 SkPoint3 halfDir(surfaceTolight);
80 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
81 halfDir.normalize();
82 SkScalar colorScale = SkScalarMul(fKS,
83 SkScalarPow(normal.dot(halfDir), fShininess));
84 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
85 SkPoint3 color(lightColor * colorScale);
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000086 return SkPackARGB32(SkClampMax(SkScalarFloorToInt(color.maxComponent()), 255),
87 SkClampMax(SkScalarFloorToInt(color.fX), 255),
88 SkClampMax(SkScalarFloorToInt(color.fY), 255),
89 SkClampMax(SkScalarFloorToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000090 }
91private:
92 SkScalar fKS;
93 SkScalar fShininess;
94};
95
96inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
97 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
98}
99
100inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
101 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
102 SkScalarMul(-y, surfaceScale),
103 SK_Scalar1);
104 vector.normalize();
105 return vector;
106}
107
108inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
109 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
110 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
111 surfaceScale);
112}
113
114inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
116 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
117 surfaceScale);
118}
119
120inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
122 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
123 surfaceScale);
124}
125
126inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
128 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
129 surfaceScale);
130}
131
132
133inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
134 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
135 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
136 surfaceScale);
137}
138
139inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
141 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
142 surfaceScale);
143}
144
145inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
147 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
148 surfaceScale);
149}
150
151inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
153 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
159 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
160 surfaceScale);
161}
162
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000163template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
164 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000165 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000166 int left = bounds.left(), right = bounds.right();
167 int bottom = bounds.bottom();
168 int y = bounds.top();
169 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000170 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000171 int x = left;
172 const SkPMColor* row1 = src.getAddr32(x, y);
173 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000174 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000175 m[4] = SkGetPackedA32(*row1++);
176 m[5] = SkGetPackedA32(*row1++);
177 m[7] = SkGetPackedA32(*row2++);
178 m[8] = SkGetPackedA32(*row2++);
179 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000180 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000181 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000182 {
183 shiftMatrixLeft(m);
184 m[5] = SkGetPackedA32(*row1++);
185 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000186 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000187 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 }
189 shiftMatrixLeft(m);
190 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000191 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000192 }
193
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000194 for (++y; y < bottom - 1; ++y) {
195 int x = left;
196 const SkPMColor* row0 = src.getAddr32(x, y - 1);
197 const SkPMColor* row1 = src.getAddr32(x, y);
198 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000199 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000200 m[1] = SkGetPackedA32(*row0++);
201 m[2] = SkGetPackedA32(*row0++);
202 m[4] = SkGetPackedA32(*row1++);
203 m[5] = SkGetPackedA32(*row1++);
204 m[7] = SkGetPackedA32(*row2++);
205 m[8] = SkGetPackedA32(*row2++);
206 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000207 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000208 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000209 shiftMatrixLeft(m);
210 m[2] = SkGetPackedA32(*row0++);
211 m[5] = SkGetPackedA32(*row1++);
212 m[8] = SkGetPackedA32(*row2++);
213 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000214 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000215 }
216 shiftMatrixLeft(m);
217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000218 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000219 }
220
221 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000222 int x = left;
223 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
224 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000225 int m[9];
226 m[1] = SkGetPackedA32(*row0++);
227 m[2] = SkGetPackedA32(*row0++);
228 m[4] = SkGetPackedA32(*row1++);
229 m[5] = SkGetPackedA32(*row1++);
230 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000231 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000232 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 {
234 shiftMatrixLeft(m);
235 m[2] = SkGetPackedA32(*row0++);
236 m[5] = SkGetPackedA32(*row1++);
237 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000238 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 }
240 shiftMatrixLeft(m);
241 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000242 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000243 }
244}
245
246SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
247 SkPoint3 point;
248 point.fX = buffer.readScalar();
249 point.fY = buffer.readScalar();
250 point.fZ = buffer.readScalar();
251 return point;
252};
253
254void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
255 buffer.writeScalar(point.fX);
256 buffer.writeScalar(point.fY);
257 buffer.writeScalar(point.fZ);
258};
259
260class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
261public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000262 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000263 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000265 SkScalar kd() const { return fKD; }
266
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000267protected:
268 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
269 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
270 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
271 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000272#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000273 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix, const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000274#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000275
276private:
277 typedef SkLightingImageFilter INHERITED;
278 SkScalar fKD;
279};
280
281class SkSpecularLightingImageFilter : public SkLightingImageFilter {
282public:
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000283 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000284 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
285
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000286 SkScalar ks() const { return fKS; }
287 SkScalar shininess() const { return fShininess; }
288
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289protected:
290 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
291 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
292 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
293 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000294#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000295 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix, const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000296#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297
298private:
299 typedef SkLightingImageFilter INHERITED;
300 SkScalar fKS;
301 SkScalar fShininess;
302};
303
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000304#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000305
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000306class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000307public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000308 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000309 virtual ~GrLightingEffect();
310
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000311 const SkLight* light() const { return fLight; }
312 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000313 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000314
315 virtual void getConstantColorComponents(GrColor* color,
316 uint32_t* validFlags) const SK_OVERRIDE {
317 // lighting shaders are complicated. We just throw up our hands.
318 *validFlags = 0;
319 }
320
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000321protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000322 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000323
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000324private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000325 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000326 const SkLight* fLight;
327 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000328 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000329};
330
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000331class GrDiffuseLightingEffect : public GrLightingEffect {
332public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000333 static GrEffectRef* Create(GrTexture* texture,
334 const SkLight* light,
335 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000336 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000337 SkScalar kd) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000338 AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
339 light,
340 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000341 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000342 kd)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000343 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000344 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000345
346 static const char* Name() { return "DiffuseLighting"; }
347
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000348 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000349
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000350 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000351 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000352
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000353private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000354 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000355
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000356 GrDiffuseLightingEffect(GrTexture* texture,
357 const SkLight* light,
358 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000359 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000360 SkScalar kd);
361
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000362 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000363 typedef GrLightingEffect INHERITED;
364 SkScalar fKD;
365};
366
367class GrSpecularLightingEffect : public GrLightingEffect {
368public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000369 static GrEffectRef* Create(GrTexture* texture,
370 const SkLight* light,
371 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000372 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000373 SkScalar ks,
374 SkScalar shininess) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000375 AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
376 light,
377 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000378 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000379 ks,
380 shininess)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000381 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000382 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000383 static const char* Name() { return "SpecularLighting"; }
384
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000385 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000386
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000387 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000388 SkScalar ks() const { return fKS; }
389 SkScalar shininess() const { return fShininess; }
390
391private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000392 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000393
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000394 GrSpecularLightingEffect(GrTexture* texture,
395 const SkLight* light,
396 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000397 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000398 SkScalar ks,
399 SkScalar shininess);
400
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000401 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000402 typedef GrLightingEffect INHERITED;
403 SkScalar fKS;
404 SkScalar fShininess;
405};
406
407///////////////////////////////////////////////////////////////////////////////
408
409class GrGLLight {
410public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000411 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000412
413 /**
414 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
415 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
416 */
417 void emitLightColorUniform(GrGLShaderBuilder*);
418
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000419 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000420 * These two functions are called from GrGLLightingEffect's emitCode() function.
421 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
422 * the light. The expression will be used in the FS. emitLightColor writes an expression into
423 * the FS that is the color of the light. Either function may add functions and/or uniforms to
424 * the FS. The default of emitLightColor appends the name of the constant light color uniform
425 * and so this function only needs to be overridden if the light color varies spatially.
426 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000427 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000428 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
429
430 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
431 // INHERITED::setData().
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000432 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000433 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000434
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000435protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000436 /**
437 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
438 * function.
439 */
440 UniformHandle lightColorUni() const { return fColorUni; }
441
442private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000443 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000444
445 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000446};
447
448///////////////////////////////////////////////////////////////////////////////
449
450class GrGLDistantLight : public GrGLLight {
451public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000452 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000453 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000454 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000455 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000456
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000457private:
458 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000459 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000460};
461
462///////////////////////////////////////////////////////////////////////////////
463
464class GrGLPointLight : public GrGLLight {
465public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000466 virtual ~GrGLPointLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000467 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000468 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000469 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000470
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000471private:
472 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000473 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000474};
475
476///////////////////////////////////////////////////////////////////////////////
477
478class GrGLSpotLight : public GrGLLight {
479public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000480 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000481 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000482 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000483 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000484 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000485
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000486private:
487 typedef GrGLLight INHERITED;
488
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000489 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000490 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000491 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000492 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000493 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000494 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000497#else
498
499class GrGLLight;
500
501#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000502
503};
504
505///////////////////////////////////////////////////////////////////////////////
506
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000507class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000508public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000509 SK_DECLARE_INST_COUNT(SkLight)
510
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000511 enum LightType {
512 kDistant_LightType,
513 kPoint_LightType,
514 kSpot_LightType,
515 };
516 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000517 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518 virtual GrGLLight* createGLLight() const = 0;
519 virtual bool isEqual(const SkLight& other) const {
520 return fColor == other.fColor;
521 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000522 // Called to know whether the generated GrGLLight will require access to the fragment position.
523 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000524 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000526 // Defined below SkLight's subclasses.
527 void flattenLight(SkFlattenableWriteBuffer& buffer) const;
528 static SkLight* UnflattenLight(SkFlattenableReadBuffer& buffer);
529
djsollen@google.com08337772012-06-26 14:33:13 +0000530protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000531 SkLight(SkColor color)
532 : fColor(SkIntToScalar(SkColorGetR(color)),
533 SkIntToScalar(SkColorGetG(color)),
534 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000535 SkLight(const SkPoint3& color)
536 : fColor(color) {}
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000537 SkLight(SkFlattenableReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000538 fColor = readPoint3(buffer);
539 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000540
541 virtual void onFlattenLight(SkFlattenableWriteBuffer& buffer) const = 0;
542
djsollen@google.com08337772012-06-26 14:33:13 +0000543
544private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000545 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000546 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000547};
548
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000549SK_DEFINE_INST_COUNT(SkLight)
550
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000551///////////////////////////////////////////////////////////////////////////////
552
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000553class SkDistantLight : public SkLight {
554public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000555 SkDistantLight(const SkPoint3& direction, SkColor color)
556 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000557 }
djsollen@google.com08337772012-06-26 14:33:13 +0000558
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000559 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
560 return fDirection;
561 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000562 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000563 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000564 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000565 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
566#if SK_SUPPORT_GPU
567 return SkNEW(GrGLDistantLight);
568#else
569 SkDEBUGFAIL("Should not call in GPU-less build");
570 return NULL;
571#endif
572 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000573 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
574
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000575 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
576 if (other.type() != kDistant_LightType) {
577 return false;
578 }
579
580 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
581 return INHERITED::isEqual(other) &&
582 fDirection == o.fDirection;
583 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000584
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000585 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
586 fDirection = readPoint3(buffer);
587 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000588
djsollen@google.com08337772012-06-26 14:33:13 +0000589protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000590 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
591 : INHERITED(color), fDirection(direction) {
592 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000593 virtual SkLight* transform(const SkMatrix& matrix) const {
594 return new SkDistantLight(direction(), color());
595 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000596 virtual void onFlattenLight(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000597 writePoint3(fDirection, buffer);
598 }
599
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000600private:
djsollen@google.com08337772012-06-26 14:33:13 +0000601 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000602 SkPoint3 fDirection;
603};
604
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000605///////////////////////////////////////////////////////////////////////////////
606
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000607class SkPointLight : public SkLight {
608public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000609 SkPointLight(const SkPoint3& location, SkColor color)
610 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000611
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000612 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
613 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
614 fLocation.fY - SkIntToScalar(y),
615 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
616 direction.normalize();
617 return direction;
618 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000619 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000620 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000621 const SkPoint3& location() const { return fLocation; }
622 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000623#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000624 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000625#else
626 SkDEBUGFAIL("Should not call in GPU-less build");
627 return NULL;
628#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000629 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000630 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000631 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632 if (other.type() != kPoint_LightType) {
633 return false;
634 }
635 const SkPointLight& o = static_cast<const SkPointLight&>(other);
636 return INHERITED::isEqual(other) &&
637 fLocation == o.fLocation;
638 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000639 virtual SkLight* transform(const SkMatrix& matrix) const {
640 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
641 matrix.mapPoints(&location2, 1);
642 SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
643 return new SkPointLight(location, color());
644 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000645
djsollen@google.com08337772012-06-26 14:33:13 +0000646 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
647 fLocation = readPoint3(buffer);
648 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000649
650protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000651 SkPointLight(const SkPoint3& location, const SkPoint3& color)
652 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000653 virtual void onFlattenLight(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000654 writePoint3(fLocation, buffer);
655 }
656
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000657private:
djsollen@google.com08337772012-06-26 14:33:13 +0000658 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000659 SkPoint3 fLocation;
660};
661
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662///////////////////////////////////////////////////////////////////////////////
663
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000664class SkSpotLight : public SkLight {
665public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000666 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
667 : INHERITED(color),
668 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000669 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000670 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000671 {
672 fS = target - location;
673 fS.normalize();
674 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
675 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
676 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
677 fConeScale = SkScalarInvert(antiAliasThreshold);
678 }
djsollen@google.com08337772012-06-26 14:33:13 +0000679
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000680 virtual SkLight* transform(const SkMatrix& matrix) const {
681 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
682 matrix.mapPoints(&location2, 1);
683 SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
684 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
685 matrix.mapPoints(&target2, 1);
686 SkPoint3 target(target2.fX, target2.fY, fTarget.fZ);
687 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, fS, color());
688 }
689
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000690 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
691 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
692 fLocation.fY - SkIntToScalar(y),
693 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
694 direction.normalize();
695 return direction;
696 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000697 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698 SkScalar cosAngle = -surfaceToLight.dot(fS);
699 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000700 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701 }
702 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
703 if (cosAngle < fCosInnerConeAngle) {
704 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000705 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000706 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000707 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000708 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000709 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000710#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000711 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000712#else
713 SkDEBUGFAIL("Should not call in GPU-less build");
714 return NULL;
715#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000716 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000717 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000718 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000719 const SkPoint3& location() const { return fLocation; }
720 const SkPoint3& target() const { return fTarget; }
721 SkScalar specularExponent() const { return fSpecularExponent; }
722 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
723 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
724 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000725 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000726
djsollen@google.com08337772012-06-26 14:33:13 +0000727 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
728 fLocation = readPoint3(buffer);
729 fTarget = readPoint3(buffer);
730 fSpecularExponent = buffer.readScalar();
731 fCosOuterConeAngle = buffer.readScalar();
732 fCosInnerConeAngle = buffer.readScalar();
733 fConeScale = buffer.readScalar();
734 fS = readPoint3(buffer);
735 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000736protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000737 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
738 : INHERITED(color),
739 fLocation(location),
740 fTarget(target),
741 fSpecularExponent(specularExponent),
742 fCosOuterConeAngle(cosOuterConeAngle),
743 fCosInnerConeAngle(cosInnerConeAngle),
744 fConeScale(coneScale),
745 fS(s)
746 {
747 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000748 virtual void onFlattenLight(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000749 writePoint3(fLocation, buffer);
750 writePoint3(fTarget, buffer);
751 buffer.writeScalar(fSpecularExponent);
752 buffer.writeScalar(fCosOuterConeAngle);
753 buffer.writeScalar(fCosInnerConeAngle);
754 buffer.writeScalar(fConeScale);
755 writePoint3(fS, buffer);
756 }
757
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000758 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000759 if (other.type() != kSpot_LightType) {
760 return false;
761 }
762
763 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
764 return INHERITED::isEqual(other) &&
765 fLocation == o.fLocation &&
766 fTarget == o.fTarget &&
767 fSpecularExponent == o.fSpecularExponent &&
768 fCosOuterConeAngle == o.fCosOuterConeAngle;
769 }
770
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000771private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000772 static const SkScalar kSpecularExponentMin;
773 static const SkScalar kSpecularExponentMax;
774
djsollen@google.com08337772012-06-26 14:33:13 +0000775 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000776 SkPoint3 fLocation;
777 SkPoint3 fTarget;
778 SkScalar fSpecularExponent;
779 SkScalar fCosOuterConeAngle;
780 SkScalar fCosInnerConeAngle;
781 SkScalar fConeScale;
782 SkPoint3 fS;
783};
784
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000785// According to the spec, the specular term should be in the range [1, 128] :
786// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
787const SkScalar SkSpotLight::kSpecularExponentMin = SkFloatToScalar(1.0f);
788const SkScalar SkSpotLight::kSpecularExponentMax = SkFloatToScalar(128.0f);
789
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000790///////////////////////////////////////////////////////////////////////////////
791
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000792void SkLight::flattenLight(SkFlattenableWriteBuffer& buffer) const {
793 // Write type first, then baseclass, then subclass.
794 buffer.writeInt(this->type());
795 writePoint3(fColor, buffer);
796 this->onFlattenLight(buffer);
797}
798
799/*static*/ SkLight* SkLight::UnflattenLight(SkFlattenableReadBuffer& buffer) {
800 // Read type first.
801 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
802 switch (type) {
803 // Each of these constructors must first call SkLight's, so we'll read the baseclass
804 // then subclass, same order as flattenLight.
805 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
806 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
807 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
808 default:
809 SkDEBUGFAIL("Unknown LightType.");
810 return NULL;
811 }
812}
813///////////////////////////////////////////////////////////////////////////////
814
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000815SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000816 : INHERITED(input, cropRect),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000817 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000818 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
819{
820 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000821 // our caller knows that we take ownership of the light, so we don't
822 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000823}
824
825SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000826 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000827 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000828 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000829 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000830 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000831}
832
833SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000834 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000835 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000836 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000837 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000838 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000839}
840
841SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000842 const SkPoint3& location, const SkPoint3& target,
843 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000844 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000845 SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000846 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000847 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
848 cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000849 surfaceScale, kd, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850}
851
852SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000853 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000854 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000855 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000856 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000857 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000858}
859
860SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000861 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000862 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000863 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000864 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000865 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000866}
867
868SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000869 const SkPoint3& location, const SkPoint3& target,
870 SkScalar specularExponent, SkScalar cutoffAngle,
871 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000872 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000873 return SkNEW_ARGS(SkSpecularLightingImageFilter,
874 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000875 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000876}
877
878SkLightingImageFilter::~SkLightingImageFilter() {
879 fLight->unref();
880}
881
882SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000883 : INHERITED(buffer) {
884 fLight = SkLight::UnflattenLight(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000885 fSurfaceScale = buffer.readScalar();
886}
887
888void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
889 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000890 fLight->flattenLight(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000891 buffer.writeScalar(fSurfaceScale);
892}
893
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000894///////////////////////////////////////////////////////////////////////////////
895
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000896SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000897 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000898 fKD(kd)
899{
900}
901
902SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
903 : INHERITED(buffer)
904{
905 fKD = buffer.readScalar();
906}
907
908void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
909 this->INHERITED::flatten(buffer);
910 buffer.writeScalar(fKD);
911}
912
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000913bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
914 const SkBitmap& source,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000915 const SkMatrix& ctm,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000916 SkBitmap* dst,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000917 SkIPoint* offset) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000918 SkImageFilter* input = getInput(0);
919 SkBitmap src = source;
920 if (input && !input->filterImage(proxy, source, ctm, &src, offset)) {
921 return false;
922 }
923
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000924 if (src.config() != SkBitmap::kARGB_8888_Config) {
925 return false;
926 }
927 SkAutoLockPixels alp(src);
928 if (!src.getPixels()) {
929 return false;
930 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000931
932 SkIRect bounds;
933 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000934 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000935 return false;
936 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000937
938 if (bounds.width() < 2 || bounds.height() < 2) {
939 return false;
940 }
941
942 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000943 dst->allocPixels();
944
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000945 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
946
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000947 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000948 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000949 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000950 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000951 break;
952 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000953 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000954 break;
955 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000956 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000957 break;
958 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000959
960 offset->fX += bounds.left();
961 offset->fY += bounds.top();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000962 return true;
963}
964
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000965#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000966bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000967 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000968 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000969 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000970 }
971 return true;
972}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000973#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000974
975///////////////////////////////////////////////////////////////////////////////
976
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000977SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000978 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000979 fKS(ks),
980 fShininess(shininess)
981{
982}
983
984SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
985 : INHERITED(buffer)
986{
987 fKS = buffer.readScalar();
988 fShininess = buffer.readScalar();
989}
990
991void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
992 this->INHERITED::flatten(buffer);
993 buffer.writeScalar(fKS);
994 buffer.writeScalar(fShininess);
995}
996
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000997bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
998 const SkBitmap& source,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000999 const SkMatrix& ctm,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001000 SkBitmap* dst,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001001 SkIPoint* offset) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001002 SkImageFilter* input = getInput(0);
1003 SkBitmap src = source;
1004 if (input && !input->filterImage(proxy, source, ctm, &src, offset)) {
1005 return false;
1006 }
1007
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001008 if (src.config() != SkBitmap::kARGB_8888_Config) {
1009 return false;
1010 }
1011 SkAutoLockPixels alp(src);
1012 if (!src.getPixels()) {
1013 return false;
1014 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001015
1016 SkIRect bounds;
1017 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001018 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001019 return false;
1020 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001021
1022 if (bounds.width() < 2 || bounds.height() < 2) {
1023 return false;
1024 }
1025
1026 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001027 dst->allocPixels();
1028
1029 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001030 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
1031 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001032 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001033 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001034 break;
1035 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001036 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001037 break;
1038 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001039 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001040 break;
1041 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001042 offset->fX += bounds.left();
1043 offset->fY += bounds.top();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001044 return true;
1045}
1046
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001047#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +00001048bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001049 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001050 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001051 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001052 }
1053 return true;
1054}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001055#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001056
1057///////////////////////////////////////////////////////////////////////////////
1058
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001059#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001060
1061namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001062SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001063 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1064 SkScalarToFloat(random->nextSScalar1()),
1065 SkScalarToFloat(random->nextSScalar1()));
1066}
1067
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001068SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001069 int type = random->nextULessThan(3);
1070 switch (type) {
1071 case 0: {
1072 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1073 }
1074 case 1: {
1075 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1076 }
1077 case 2: {
1078 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1079 random_point3(random),
1080 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001081 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001082 random->nextU()));
1083 }
1084 default:
1085 GrCrash();
1086 return NULL;
1087 }
1088}
1089
1090}
1091
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001092class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001093public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001094 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001095 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001096 virtual ~GrGLLightingEffect();
1097
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001098 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001099 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001100 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001101 const char* outputColor,
1102 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001103 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001104 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001105
bsalomon@google.comc7818882013-03-20 19:19:53 +00001106 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001107
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001108 /**
1109 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1110 */
bsalomon@google.comc7818882013-03-20 19:19:53 +00001111 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001112
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001113protected:
1114 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1115
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001116private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001117 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001118
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001119 UniformHandle fImageIncrementUni;
1120 UniformHandle fSurfaceScaleUni;
1121 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001122};
1123
1124///////////////////////////////////////////////////////////////////////////////
1125
1126class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1127public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001128 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001129 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001130 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001131 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001132
1133private:
1134 typedef GrGLLightingEffect INHERITED;
1135
bsalomon@google.com032b2212012-07-16 13:36:18 +00001136 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001137};
1138
1139///////////////////////////////////////////////////////////////////////////////
1140
1141class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1142public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001143 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001144 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001145 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001146 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001147
1148private:
1149 typedef GrGLLightingEffect INHERITED;
1150
bsalomon@google.com032b2212012-07-16 13:36:18 +00001151 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001152 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001153};
1154
1155///////////////////////////////////////////////////////////////////////////////
1156
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001157GrLightingEffect::GrLightingEffect(GrTexture* texture,
1158 const SkLight* light,
1159 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001160 const SkMatrix& matrix)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001161 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001162 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001163 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001164 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001165 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001166 if (light->requiresFragmentPosition()) {
1167 this->setWillReadFragmentPosition();
1168 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001169}
1170
1171GrLightingEffect::~GrLightingEffect() {
1172 fLight->unref();
1173}
1174
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001175bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001176 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001177 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001178 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001179 fSurfaceScale == s.fSurfaceScale;
1180}
1181
1182///////////////////////////////////////////////////////////////////////////////
1183
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001184GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1185 const SkLight* light,
1186 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001187 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001188 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001189 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001190}
1191
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001192const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1193 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194}
1195
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001196bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001197 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001198 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001199 this->kd() == s.kd();
1200}
1201
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001202GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001203
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001204GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001205 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001206 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001207 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001208 SkScalar surfaceScale = random->nextSScalar1();
1209 SkScalar kd = random->nextUScalar1();
1210 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001211 SkMatrix matrix;
1212 for (int i = 0; i < 9; i++) {
1213 matrix[i] = random->nextUScalar1();
1214 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001215 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001216 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001217}
1218
1219
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001220///////////////////////////////////////////////////////////////////////////////
1221
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001222GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001223 const GrDrawEffect& drawEffect)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001224 : INHERITED(factory) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001225 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001226 fLight = m.light()->createGLLight();
1227}
1228
1229GrGLLightingEffect::~GrGLLightingEffect() {
1230 delete fLight;
1231}
1232
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001233void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001234 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001235 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001236 const char* outputColor,
1237 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001238 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001239 const TextureSamplerArray& samplers) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001240 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001241
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001242 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001243 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001244 "ImageIncrement");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001245 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001246 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001247 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001248 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001249 SkString lightFunc;
1250 this->emitLightFunc(builder, &lightFunc);
1251 static const GrGLShaderVar gSobelArgs[] = {
1252 GrGLShaderVar("a", kFloat_GrSLType),
1253 GrGLShaderVar("b", kFloat_GrSLType),
1254 GrGLShaderVar("c", kFloat_GrSLType),
1255 GrGLShaderVar("d", kFloat_GrSLType),
1256 GrGLShaderVar("e", kFloat_GrSLType),
1257 GrGLShaderVar("f", kFloat_GrSLType),
1258 GrGLShaderVar("scale", kFloat_GrSLType),
1259 };
1260 SkString sobelFuncName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001261 builder->fsEmitFunction(kFloat_GrSLType,
1262 "sobel",
1263 SK_ARRAY_COUNT(gSobelArgs),
1264 gSobelArgs,
1265 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1266 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001267 static const GrGLShaderVar gPointToNormalArgs[] = {
1268 GrGLShaderVar("x", kFloat_GrSLType),
1269 GrGLShaderVar("y", kFloat_GrSLType),
1270 GrGLShaderVar("scale", kFloat_GrSLType),
1271 };
1272 SkString pointToNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001273 builder->fsEmitFunction(kVec3f_GrSLType,
1274 "pointToNormal",
1275 SK_ARRAY_COUNT(gPointToNormalArgs),
1276 gPointToNormalArgs,
1277 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1278 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001279
1280 static const GrGLShaderVar gInteriorNormalArgs[] = {
1281 GrGLShaderVar("m", kFloat_GrSLType, 9),
1282 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1283 };
1284 SkString interiorNormalBody;
1285 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1286 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1287 "\t surfaceScale);\n",
1288 pointToNormalName.c_str(),
1289 sobelFuncName.c_str(),
1290 sobelFuncName.c_str());
1291 SkString interiorNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001292 builder->fsEmitFunction(kVec3f_GrSLType,
1293 "interiorNormal",
1294 SK_ARRAY_COUNT(gInteriorNormalArgs),
1295 gInteriorNormalArgs,
1296 interiorNormalBody.c_str(),
1297 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001298
bsalomon@google.com77af6802013-10-02 13:04:56 +00001299 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001300 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001301
1302 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1303 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1304
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001305 int index = 0;
1306 for (int dy = -1; dy <= 1; dy++) {
1307 for (int dx = -1; dx <= 1; dx++) {
1308 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001309 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001310 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001311 builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001312 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001313 }
1314 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001315 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001316 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001317 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001318 fLight->emitSurfaceToLight(builder, arg.c_str());
1319 builder->fsCodeAppend(";\n");
1320 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1321 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001322 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001323 builder->fsCodeAppend(");\n");
1324 SkString modulate;
1325 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1326 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001327}
1328
bsalomon@google.comc7818882013-03-20 19:19:53 +00001329GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001330 const GrGLCaps& caps) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001331 return drawEffect.castEffect<GrLightingEffect>().light()->type();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001332}
1333
bsalomon@google.comc7818882013-03-20 19:19:53 +00001334void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1335 const GrDrawEffect& drawEffect) {
1336 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1337 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001338 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001339 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001340 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001341 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1342 fLight->setData(uman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001343}
1344
1345///////////////////////////////////////////////////////////////////////////////
1346
1347///////////////////////////////////////////////////////////////////////////////
1348
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001349GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001350 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001351 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001352}
1353
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001354void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001355 const char* kd;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001356 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001357 kFloat_GrSLType,
1358 "KD",
1359 &kd);
1360
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001361 static const GrGLShaderVar gLightArgs[] = {
1362 GrGLShaderVar("normal", kVec3f_GrSLType),
1363 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1364 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1365 };
1366 SkString lightBody;
1367 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1368 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001369 builder->fsEmitFunction(kVec4f_GrSLType,
1370 "light",
1371 SK_ARRAY_COUNT(gLightArgs),
1372 gLightArgs,
1373 lightBody.c_str(),
1374 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001375}
1376
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001377void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001378 const GrDrawEffect& drawEffect) {
1379 INHERITED::setData(uman, drawEffect);
1380 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1381 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001382}
1383
1384///////////////////////////////////////////////////////////////////////////////
1385
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001386GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1387 const SkLight* light,
1388 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001389 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001390 SkScalar ks,
1391 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001392 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001393 fKS(ks),
1394 fShininess(shininess) {
1395}
1396
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001397const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1398 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001399}
1400
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001401bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001402 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001403 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001404 this->ks() == s.ks() &&
1405 this->shininess() == s.shininess();
1406}
1407
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001408GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001409
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001410GrEffectRef* GrSpecularLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001411 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001412 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001413 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001414 SkScalar surfaceScale = random->nextSScalar1();
1415 SkScalar ks = random->nextUScalar1();
1416 SkScalar shininess = random->nextUScalar1();
1417 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001418 SkMatrix matrix;
1419 for (int i = 0; i < 9; i++) {
1420 matrix[i] = random->nextUScalar1();
1421 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001422 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001423 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001424}
1425
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001426///////////////////////////////////////////////////////////////////////////////
1427
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001428GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001429 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001430 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001431}
1432
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001433void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001434 const char* ks;
1435 const char* shininess;
1436
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001437 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001438 kFloat_GrSLType, "KS", &ks);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001439 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001440 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001441
1442 static const GrGLShaderVar gLightArgs[] = {
1443 GrGLShaderVar("normal", kVec3f_GrSLType),
1444 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1445 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1446 };
1447 SkString lightBody;
1448 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1449 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001450 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1451 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001452 builder->fsEmitFunction(kVec4f_GrSLType,
1453 "light",
1454 SK_ARRAY_COUNT(gLightArgs),
1455 gLightArgs,
1456 lightBody.c_str(),
1457 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001458}
1459
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001460void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001461 const GrDrawEffect& drawEffect) {
1462 INHERITED::setData(uman, drawEffect);
1463 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1464 uman.set1f(fKSUni, spec.ks());
1465 uman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001466}
1467
1468///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001469void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001470 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001471 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001472}
1473
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001474void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1475 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001476 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001477}
1478
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001479void GrGLLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001480 const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001481 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001482}
1483
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001484///////////////////////////////////////////////////////////////////////////////
1485
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001486void GrGLDistantLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001487 const SkLight* light) const {
1488 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001489 SkASSERT(light->type() == SkLight::kDistant_LightType);
1490 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001491 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001492}
1493
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001494void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001495 const char* dir;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001496 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001497 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001498 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001499}
1500
1501///////////////////////////////////////////////////////////////////////////////
1502
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001503void GrGLPointLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001504 const SkLight* light) const {
1505 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001506 SkASSERT(light->type() == SkLight::kPoint_LightType);
1507 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001508 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001509}
1510
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001511void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001512 const char* loc;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001513 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001514 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001515 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001516}
1517
1518///////////////////////////////////////////////////////////////////////////////
1519
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001520void GrGLSpotLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001521 const SkLight* light) const {
1522 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001523 SkASSERT(light->type() == SkLight::kSpot_LightType);
1524 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001525 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001526 uman.set1f(fExponentUni, spotLight->specularExponent());
1527 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1528 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1529 uman.set1f(fConeScaleUni, spotLight->coneScale());
1530 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001531}
1532
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001533void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001534 const char* location;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001535 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001536 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001537 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1538 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001539}
1540
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001541void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1542 const char *surfaceToLight) {
1543
1544 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1545
1546 const char* exponent;
1547 const char* cosInner;
1548 const char* cosOuter;
1549 const char* coneScale;
1550 const char* s;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001551 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001552 kFloat_GrSLType, "Exponent", &exponent);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001553 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001554 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001555 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001556 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001557 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001558 kFloat_GrSLType, "ConeScale", &coneScale);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001559 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001560 kVec3f_GrSLType, "S", &s);
1561
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001562 static const GrGLShaderVar gLightColorArgs[] = {
1563 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1564 };
1565 SkString lightColorBody;
1566 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1567 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1568 lightColorBody.appendf("\t\treturn vec3(0);\n");
1569 lightColorBody.appendf("\t}\n");
1570 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1571 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1572 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1573 color, cosOuter, coneScale);
1574 lightColorBody.appendf("\t}\n");
1575 lightColorBody.appendf("\treturn %s;\n", color);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001576 builder->fsEmitFunction(kVec3f_GrSLType,
1577 "lightColor",
1578 SK_ARRAY_COUNT(gLightColorArgs),
1579 gLightColorArgs,
1580 lightColorBody.c_str(),
1581 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001582
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001583 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001584}
1585
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001586#endif
1587
djsollen@google.com08337772012-06-26 14:33:13 +00001588SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1589 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1590 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001591SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END