blob: ecf9913d2a2cbd99998d9547f8d51cae8ede4dde [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.com17fc6512012-11-02 21:45:01 +000019#include "gl/GrGLEffectMatrix.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000020#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000021#include "GrTBackendEffectFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000022
23class GrGLDiffuseLightingEffect;
24class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000025
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000026// For brevity
27typedef GrGLUniformManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000028#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000029
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000030namespace {
31
32const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
33const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
34const SkScalar gOneHalf = SkFloatToScalar(0.5f);
35const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
36
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000037#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000038void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000039 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000040 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000041}
42
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000043void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000044 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000045}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000046#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000047
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000048// Shift matrix components to the left, as we advance pixels to the right.
49inline void shiftMatrixLeft(int m[9]) {
50 m[0] = m[1];
51 m[3] = m[4];
52 m[6] = m[7];
53 m[1] = m[2];
54 m[4] = m[5];
55 m[7] = m[8];
56}
57
58class DiffuseLightingType {
59public:
60 DiffuseLightingType(SkScalar kd)
61 : fKD(kd) {}
62 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
63 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
64 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
65 SkPoint3 color(lightColor * colorScale);
66 return SkPackARGB32(255,
67 SkScalarFloorToInt(color.fX),
68 SkScalarFloorToInt(color.fY),
69 SkScalarFloorToInt(color.fZ));
70 }
71private:
72 SkScalar fKD;
73};
74
75class SpecularLightingType {
76public:
77 SpecularLightingType(SkScalar ks, SkScalar shininess)
78 : fKS(ks), fShininess(shininess) {}
79 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
80 SkPoint3 halfDir(surfaceTolight);
81 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
82 halfDir.normalize();
83 SkScalar colorScale = SkScalarMul(fKS,
84 SkScalarPow(normal.dot(halfDir), fShininess));
85 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
86 SkPoint3 color(lightColor * colorScale);
87 return SkPackARGB32(SkScalarFloorToInt(color.maxComponent()),
88 SkScalarFloorToInt(color.fX),
89 SkScalarFloorToInt(color.fY),
90 SkScalarFloorToInt(color.fZ));
91 }
92private:
93 SkScalar fKS;
94 SkScalar fShininess;
95};
96
97inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
98 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
99}
100
101inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
102 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
103 SkScalarMul(-y, surfaceScale),
104 SK_Scalar1);
105 vector.normalize();
106 return vector;
107}
108
109inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
110 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
111 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
112 surfaceScale);
113}
114
115inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
116 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
117 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
118 surfaceScale);
119}
120
121inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
122 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
123 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
124 surfaceScale);
125}
126
127inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
128 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
129 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
130 surfaceScale);
131}
132
133
134inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
135 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
136 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
137 surfaceScale);
138}
139
140inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
141 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
142 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
143 surfaceScale);
144}
145
146inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
147 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
148 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
149 surfaceScale);
150}
151
152inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
153 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
154 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
155 surfaceScale);
156}
157
158inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
160 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
161 surfaceScale);
162}
163
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000164template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
165 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000166 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000167 int left = bounds.left(), right = bounds.right();
168 int bottom = bounds.bottom();
169 int y = bounds.top();
170 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000171 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000172 int x = left;
173 const SkPMColor* row1 = src.getAddr32(x, y);
174 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000175 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000176 m[4] = SkGetPackedA32(*row1++);
177 m[5] = SkGetPackedA32(*row1++);
178 m[7] = SkGetPackedA32(*row2++);
179 m[8] = SkGetPackedA32(*row2++);
180 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000181 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000182 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000183 {
184 shiftMatrixLeft(m);
185 m[5] = SkGetPackedA32(*row1++);
186 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000187 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000188 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000189 }
190 shiftMatrixLeft(m);
191 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000192 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000193 }
194
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000195 for (++y; y < bottom - 1; ++y) {
196 int x = left;
197 const SkPMColor* row0 = src.getAddr32(x, y - 1);
198 const SkPMColor* row1 = src.getAddr32(x, y);
199 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000200 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000201 m[1] = SkGetPackedA32(*row0++);
202 m[2] = SkGetPackedA32(*row0++);
203 m[4] = SkGetPackedA32(*row1++);
204 m[5] = SkGetPackedA32(*row1++);
205 m[7] = SkGetPackedA32(*row2++);
206 m[8] = SkGetPackedA32(*row2++);
207 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000208 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000209 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 shiftMatrixLeft(m);
211 m[2] = SkGetPackedA32(*row0++);
212 m[5] = SkGetPackedA32(*row1++);
213 m[8] = SkGetPackedA32(*row2++);
214 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000215 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 }
217 shiftMatrixLeft(m);
218 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000219 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000220 }
221
222 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000223 int x = left;
224 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
225 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000226 int m[9];
227 m[1] = SkGetPackedA32(*row0++);
228 m[2] = SkGetPackedA32(*row0++);
229 m[4] = SkGetPackedA32(*row1++);
230 m[5] = SkGetPackedA32(*row1++);
231 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000232 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000233 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000234 {
235 shiftMatrixLeft(m);
236 m[2] = SkGetPackedA32(*row0++);
237 m[5] = SkGetPackedA32(*row1++);
238 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000239 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 }
241 shiftMatrixLeft(m);
242 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000243 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000244 }
245}
246
247SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
248 SkPoint3 point;
249 point.fX = buffer.readScalar();
250 point.fY = buffer.readScalar();
251 point.fZ = buffer.readScalar();
252 return point;
253};
254
255void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
256 buffer.writeScalar(point.fX);
257 buffer.writeScalar(point.fY);
258 buffer.writeScalar(point.fZ);
259};
260
261class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
262public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000263 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000264 SkScalar kd, SkImageFilter* input, const SkIRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000265 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
266
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000267#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000268 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const SK_OVERRIDE;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000269#endif
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000270 SkScalar kd() const { return fKD; }
271
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000272protected:
273 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
274 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
275 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
276 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
277
278
279private:
280 typedef SkLightingImageFilter INHERITED;
281 SkScalar fKD;
282};
283
284class SkSpecularLightingImageFilter : public SkLightingImageFilter {
285public:
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000286 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const SkIRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000287 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
288
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000289#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000290 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const SK_OVERRIDE;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000291#endif
292
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000293 SkScalar ks() const { return fKS; }
294 SkScalar shininess() const { return fShininess; }
295
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000296protected:
297 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
298 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
299 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
300 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
301
302private:
303 typedef SkLightingImageFilter INHERITED;
304 SkScalar fKS;
305 SkScalar fShininess;
306};
307
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000308#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000309
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000310class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000311public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000312 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000313 virtual ~GrLightingEffect();
314
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000315 const SkLight* light() const { return fLight; }
316 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000317 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000318
319 virtual void getConstantColorComponents(GrColor* color,
320 uint32_t* validFlags) const SK_OVERRIDE {
321 // lighting shaders are complicated. We just throw up our hands.
322 *validFlags = 0;
323 }
324
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000325protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000326 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000327
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000328private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000329 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000330 const SkLight* fLight;
331 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000332 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000333};
334
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000335class GrDiffuseLightingEffect : public GrLightingEffect {
336public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000337 static GrEffectRef* Create(GrTexture* texture,
338 const SkLight* light,
339 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000340 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000341 SkScalar kd) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000342 AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
343 light,
344 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000345 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000346 kd)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000347 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000348 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000349
350 static const char* Name() { return "DiffuseLighting"; }
351
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000352 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000353
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000354 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000355 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000356
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000357private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000358 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000359
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000360 GrDiffuseLightingEffect(GrTexture* texture,
361 const SkLight* light,
362 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000363 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000364 SkScalar kd);
365
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000366 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000367 typedef GrLightingEffect INHERITED;
368 SkScalar fKD;
369};
370
371class GrSpecularLightingEffect : public GrLightingEffect {
372public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000373 static GrEffectRef* Create(GrTexture* texture,
374 const SkLight* light,
375 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000376 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000377 SkScalar ks,
378 SkScalar shininess) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000379 AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
380 light,
381 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000382 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000383 ks,
384 shininess)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000385 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000386 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000387 static const char* Name() { return "SpecularLighting"; }
388
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000389 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000390
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000391 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000392 SkScalar ks() const { return fKS; }
393 SkScalar shininess() const { return fShininess; }
394
395private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000396 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000397
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000398 GrSpecularLightingEffect(GrTexture* texture,
399 const SkLight* light,
400 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000401 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000402 SkScalar ks,
403 SkScalar shininess);
404
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000405 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000406 typedef GrLightingEffect INHERITED;
407 SkScalar fKS;
408 SkScalar fShininess;
409};
410
411///////////////////////////////////////////////////////////////////////////////
412
413class GrGLLight {
414public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000415 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000416
417 /**
418 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
419 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
420 */
421 void emitLightColorUniform(GrGLShaderBuilder*);
422
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000423 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000424 * These two functions are called from GrGLLightingEffect's emitCode() function.
425 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
426 * the light. The expression will be used in the FS. emitLightColor writes an expression into
427 * the FS that is the color of the light. Either function may add functions and/or uniforms to
428 * the FS. The default of emitLightColor appends the name of the constant light color uniform
429 * and so this function only needs to be overridden if the light color varies spatially.
430 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000431 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000432 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
433
434 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
435 // INHERITED::setData().
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000436 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000437 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000438
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000439protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000440 /**
441 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
442 * function.
443 */
444 UniformHandle lightColorUni() const { return fColorUni; }
445
446private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000447 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000448
449 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000450};
451
452///////////////////////////////////////////////////////////////////////////////
453
454class GrGLDistantLight : public GrGLLight {
455public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000456 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000457 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000458 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000459 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000460
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000461private:
462 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000463 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000464};
465
466///////////////////////////////////////////////////////////////////////////////
467
468class GrGLPointLight : public GrGLLight {
469public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000470 virtual ~GrGLPointLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000471 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000472 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000473 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000474
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000475private:
476 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000477 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000478};
479
480///////////////////////////////////////////////////////////////////////////////
481
482class GrGLSpotLight : public GrGLLight {
483public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000484 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000485 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000486 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000487 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000488 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000489
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490private:
491 typedef GrGLLight INHERITED;
492
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000493 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000494 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000496 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000497 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000498 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000499 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000500};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000501#else
502
503class GrGLLight;
504
505#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506
507};
508
509///////////////////////////////////////////////////////////////////////////////
510
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000511class SkLight : public SkFlattenable {
512public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000513 SK_DECLARE_INST_COUNT(SkLight)
514
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515 enum LightType {
516 kDistant_LightType,
517 kPoint_LightType,
518 kSpot_LightType,
519 };
520 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000521 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000522 virtual GrGLLight* createGLLight() const = 0;
523 virtual bool isEqual(const SkLight& other) const {
524 return fColor == other.fColor;
525 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000526 // Called to know whether the generated GrGLLight will require access to the fragment position.
527 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000528 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000529
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) {}
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000537 SkLight(SkFlattenableReadBuffer& buffer)
538 : INHERITED(buffer) {
539 fColor = readPoint3(buffer);
540 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000541 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000542 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000543 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000544 }
djsollen@google.com08337772012-06-26 14:33:13 +0000545
546private:
547 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000548 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000549};
550
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000551SK_DEFINE_INST_COUNT(SkLight)
552
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000553///////////////////////////////////////////////////////////////////////////////
554
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000555class SkDistantLight : public SkLight {
556public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000557 SkDistantLight(const SkPoint3& direction, SkColor color)
558 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000559 }
djsollen@google.com08337772012-06-26 14:33:13 +0000560
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000561 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
562 return fDirection;
563 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000564 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000565 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000567 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
568#if SK_SUPPORT_GPU
569 return SkNEW(GrGLDistantLight);
570#else
571 SkDEBUGFAIL("Should not call in GPU-less build");
572 return NULL;
573#endif
574 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000575 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
576
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000577 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
578 if (other.type() != kDistant_LightType) {
579 return false;
580 }
581
582 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
583 return INHERITED::isEqual(other) &&
584 fDirection == o.fDirection;
585 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586
587 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
588
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 }
djsollen@google.com08337772012-06-26 14:33:13 +0000593 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
594 fDirection = readPoint3(buffer);
595 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000596 virtual SkLight* transform(const SkMatrix& matrix) const {
597 return new SkDistantLight(direction(), color());
598 }
djsollen@google.com08337772012-06-26 14:33:13 +0000599 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
600 INHERITED::flatten(buffer);
601 writePoint3(fDirection, buffer);
602 }
603
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000604private:
djsollen@google.com08337772012-06-26 14:33:13 +0000605 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000606 SkPoint3 fDirection;
607};
608
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000609///////////////////////////////////////////////////////////////////////////////
610
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000611class SkPointLight : public SkLight {
612public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000613 SkPointLight(const SkPoint3& location, SkColor color)
614 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000615
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000616 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
617 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
618 fLocation.fY - SkIntToScalar(y),
619 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
620 direction.normalize();
621 return direction;
622 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000623 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000624 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625 const SkPoint3& location() const { return fLocation; }
626 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000627#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000628 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000629#else
630 SkDEBUGFAIL("Should not call in GPU-less build");
631 return NULL;
632#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000634 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000635 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000636 if (other.type() != kPoint_LightType) {
637 return false;
638 }
639 const SkPointLight& o = static_cast<const SkPointLight&>(other);
640 return INHERITED::isEqual(other) &&
641 fLocation == o.fLocation;
642 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000643 virtual SkLight* transform(const SkMatrix& matrix) const {
644 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
645 matrix.mapPoints(&location2, 1);
646 SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
647 return new SkPointLight(location, color());
648 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000649
650 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
651
djsollen@google.com08337772012-06-26 14:33:13 +0000652protected:
653 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
654 fLocation = readPoint3(buffer);
655 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000656 SkPointLight(const SkPoint3& location, const SkPoint3& color)
657 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000658 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
659 INHERITED::flatten(buffer);
660 writePoint3(fLocation, buffer);
661 }
662
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000663private:
djsollen@google.com08337772012-06-26 14:33:13 +0000664 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000665 SkPoint3 fLocation;
666};
667
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000668///////////////////////////////////////////////////////////////////////////////
669
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000670class SkSpotLight : public SkLight {
671public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000672 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
673 : INHERITED(color),
674 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000675 fTarget(target),
676 fSpecularExponent(specularExponent)
677 {
678 fS = target - location;
679 fS.normalize();
680 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
681 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
682 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
683 fConeScale = SkScalarInvert(antiAliasThreshold);
684 }
djsollen@google.com08337772012-06-26 14:33:13 +0000685
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000686 virtual SkLight* transform(const SkMatrix& matrix) const {
687 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
688 matrix.mapPoints(&location2, 1);
689 SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
690 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
691 matrix.mapPoints(&target2, 1);
692 SkPoint3 target(target2.fX, target2.fY, fTarget.fZ);
693 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, fS, color());
694 }
695
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
697 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
698 fLocation.fY - SkIntToScalar(y),
699 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
700 direction.normalize();
701 return direction;
702 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000703 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704 SkScalar cosAngle = -surfaceToLight.dot(fS);
705 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000706 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000707 }
708 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
709 if (cosAngle < fCosInnerConeAngle) {
710 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000711 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000713 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000714 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000715 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000716#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000717 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000718#else
719 SkDEBUGFAIL("Should not call in GPU-less build");
720 return NULL;
721#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000722 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000723 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000724 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000725 const SkPoint3& location() const { return fLocation; }
726 const SkPoint3& target() const { return fTarget; }
727 SkScalar specularExponent() const { return fSpecularExponent; }
728 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
729 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
730 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000731 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000732
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
734
djsollen@google.com08337772012-06-26 14:33:13 +0000735protected:
736 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
737 fLocation = readPoint3(buffer);
738 fTarget = readPoint3(buffer);
739 fSpecularExponent = buffer.readScalar();
740 fCosOuterConeAngle = buffer.readScalar();
741 fCosInnerConeAngle = buffer.readScalar();
742 fConeScale = buffer.readScalar();
743 fS = readPoint3(buffer);
744 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000745 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
746 : INHERITED(color),
747 fLocation(location),
748 fTarget(target),
749 fSpecularExponent(specularExponent),
750 fCosOuterConeAngle(cosOuterConeAngle),
751 fCosInnerConeAngle(cosInnerConeAngle),
752 fConeScale(coneScale),
753 fS(s)
754 {
755 }
djsollen@google.com08337772012-06-26 14:33:13 +0000756 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
757 INHERITED::flatten(buffer);
758 writePoint3(fLocation, buffer);
759 writePoint3(fTarget, buffer);
760 buffer.writeScalar(fSpecularExponent);
761 buffer.writeScalar(fCosOuterConeAngle);
762 buffer.writeScalar(fCosInnerConeAngle);
763 buffer.writeScalar(fConeScale);
764 writePoint3(fS, buffer);
765 }
766
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000767 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000768 if (other.type() != kSpot_LightType) {
769 return false;
770 }
771
772 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
773 return INHERITED::isEqual(other) &&
774 fLocation == o.fLocation &&
775 fTarget == o.fTarget &&
776 fSpecularExponent == o.fSpecularExponent &&
777 fCosOuterConeAngle == o.fCosOuterConeAngle;
778 }
779
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000780private:
djsollen@google.com08337772012-06-26 14:33:13 +0000781 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000782 SkPoint3 fLocation;
783 SkPoint3 fTarget;
784 SkScalar fSpecularExponent;
785 SkScalar fCosOuterConeAngle;
786 SkScalar fCosInnerConeAngle;
787 SkScalar fConeScale;
788 SkPoint3 fS;
789};
790
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000791///////////////////////////////////////////////////////////////////////////////
792
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000793SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input, const SkIRect* cropRect)
794 : INHERITED(input, cropRect),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000795 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000796 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
797{
798 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000799 // our caller knows that we take ownership of the light, so we don't
800 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000801}
802
803SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000804 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000805 SkScalar kd, SkImageFilter* input, const SkIRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000806 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000807 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000808 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000809}
810
811SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000812 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000813 SkScalar kd, SkImageFilter* input, const SkIRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000814 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000815 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000816 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000817}
818
819SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000820 const SkPoint3& location, const SkPoint3& target,
821 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000822 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000823 SkImageFilter* input, const SkIRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000824 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000825 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
826 cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000827 surfaceScale, kd, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000828}
829
830SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000831 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000832 SkScalar ks, SkScalar shininess, SkImageFilter* input, const SkIRect* cropRect) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000833 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000834 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000835 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000836}
837
838SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000839 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000840 SkScalar ks, SkScalar shininess, SkImageFilter* input, const SkIRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000841 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000842 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000843 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000844}
845
846SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000847 const SkPoint3& location, const SkPoint3& target,
848 SkScalar specularExponent, SkScalar cutoffAngle,
849 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000850 SkScalar ks, SkScalar shininess, SkImageFilter* input, const SkIRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000851 return SkNEW_ARGS(SkSpecularLightingImageFilter,
852 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000853 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000854}
855
856SkLightingImageFilter::~SkLightingImageFilter() {
857 fLight->unref();
858}
859
860SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
861 : INHERITED(buffer)
862{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000863 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000864 fSurfaceScale = buffer.readScalar();
865}
866
867void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
868 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000869 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000870 buffer.writeScalar(fSurfaceScale);
871}
872
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000873///////////////////////////////////////////////////////////////////////////////
874
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000875SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const SkIRect* cropRect = NULL)
876 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000877 fKD(kd)
878{
879}
880
881SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
882 : INHERITED(buffer)
883{
884 fKD = buffer.readScalar();
885}
886
887void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
888 this->INHERITED::flatten(buffer);
889 buffer.writeScalar(fKD);
890}
891
892bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
893 const SkBitmap& src,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000894 const SkMatrix& ctm,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000895 SkBitmap* dst,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000896 SkIPoint* offset) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000897 if (src.config() != SkBitmap::kARGB_8888_Config) {
898 return false;
899 }
900 SkAutoLockPixels alp(src);
901 if (!src.getPixels()) {
902 return false;
903 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000904
905 SkIRect bounds;
906 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000907 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000908 return false;
909 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000910
911 if (bounds.width() < 2 || bounds.height() < 2) {
912 return false;
913 }
914
915 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000916 dst->allocPixels();
917
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000918 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
919
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000920 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000921 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000922 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000923 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000924 break;
925 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000926 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000927 break;
928 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000929 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000930 break;
931 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000932
933 offset->fX += bounds.left();
934 offset->fY += bounds.top();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000935 return true;
936}
937
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000938#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000939bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000940 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000941 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000942 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000943 }
944 return true;
945}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000946#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000947
948///////////////////////////////////////////////////////////////////////////////
949
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000950SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const SkIRect* cropRect)
951 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000952 fKS(ks),
953 fShininess(shininess)
954{
955}
956
957SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
958 : INHERITED(buffer)
959{
960 fKS = buffer.readScalar();
961 fShininess = buffer.readScalar();
962}
963
964void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
965 this->INHERITED::flatten(buffer);
966 buffer.writeScalar(fKS);
967 buffer.writeScalar(fShininess);
968}
969
970bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
971 const SkBitmap& src,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000972 const SkMatrix& ctm,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000973 SkBitmap* dst,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000974 SkIPoint* offset) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000975 if (src.config() != SkBitmap::kARGB_8888_Config) {
976 return false;
977 }
978 SkAutoLockPixels alp(src);
979 if (!src.getPixels()) {
980 return false;
981 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000982
983 SkIRect bounds;
984 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000985 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000986 return false;
987 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000988
989 if (bounds.width() < 2 || bounds.height() < 2) {
990 return false;
991 }
992
993 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000994 dst->allocPixels();
995
996 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000997 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
998 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000999 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001000 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001001 break;
1002 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001003 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001004 break;
1005 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001006 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001007 break;
1008 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001009 offset->fX += bounds.left();
1010 offset->fY += bounds.top();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001011 return true;
1012}
1013
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001014#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001015bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001016 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001017 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001018 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001019 }
1020 return true;
1021}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001022#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001023
1024///////////////////////////////////////////////////////////////////////////////
1025
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001026#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001027
1028namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001029SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001030 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1031 SkScalarToFloat(random->nextSScalar1()),
1032 SkScalarToFloat(random->nextSScalar1()));
1033}
1034
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001035SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001036 int type = random->nextULessThan(3);
1037 switch (type) {
1038 case 0: {
1039 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1040 }
1041 case 1: {
1042 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1043 }
1044 case 2: {
1045 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1046 random_point3(random),
1047 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001048 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001049 random->nextU()));
1050 }
1051 default:
1052 GrCrash();
1053 return NULL;
1054 }
1055}
1056
1057}
1058
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001059class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001060public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001061 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001062 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001063 virtual ~GrGLLightingEffect();
1064
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001065 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001066 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001067 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001068 const char* outputColor,
1069 const char* inputColor,
1070 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001071
bsalomon@google.comc7818882013-03-20 19:19:53 +00001072 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001073
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001074 /**
1075 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1076 */
bsalomon@google.comc7818882013-03-20 19:19:53 +00001077 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001078
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001079protected:
1080 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1081
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001082private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001083 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001084
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001085 UniformHandle fImageIncrementUni;
1086 UniformHandle fSurfaceScaleUni;
1087 GrGLLight* fLight;
1088 GrGLEffectMatrix fEffectMatrix;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001089};
1090
1091///////////////////////////////////////////////////////////////////////////////
1092
1093class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1094public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001095 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001096 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001097 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001098 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001099
1100private:
1101 typedef GrGLLightingEffect INHERITED;
1102
bsalomon@google.com032b2212012-07-16 13:36:18 +00001103 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001104};
1105
1106///////////////////////////////////////////////////////////////////////////////
1107
1108class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1109public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001110 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001111 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001112 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001113 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001114
1115private:
1116 typedef GrGLLightingEffect INHERITED;
1117
bsalomon@google.com032b2212012-07-16 13:36:18 +00001118 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001119 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001120};
1121
1122///////////////////////////////////////////////////////////////////////////////
1123
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001124GrLightingEffect::GrLightingEffect(GrTexture* texture,
1125 const SkLight* light,
1126 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001127 const SkMatrix& matrix)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001128 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001129 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001130 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001131 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001132 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001133 if (light->requiresFragmentPosition()) {
1134 this->setWillReadFragmentPosition();
1135 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001136}
1137
1138GrLightingEffect::~GrLightingEffect() {
1139 fLight->unref();
1140}
1141
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001142bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001143 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001144 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001145 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001146 fSurfaceScale == s.fSurfaceScale;
1147}
1148
1149///////////////////////////////////////////////////////////////////////////////
1150
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001151GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1152 const SkLight* light,
1153 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001154 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001155 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001156 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001157}
1158
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001159const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1160 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001161}
1162
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001163bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001164 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001165 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001166 this->kd() == s.kd();
1167}
1168
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001169GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001170
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001171GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001172 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001173 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001174 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001175 SkScalar surfaceScale = random->nextSScalar1();
1176 SkScalar kd = random->nextUScalar1();
1177 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001178 SkMatrix matrix;
1179 for (int i = 0; i < 9; i++) {
1180 matrix[i] = random->nextUScalar1();
1181 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001182 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001183 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001184}
1185
1186
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001187///////////////////////////////////////////////////////////////////////////////
1188
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001189GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001190 const GrDrawEffect& drawEffect)
bsalomon@google.com374e7592012-10-23 17:30:45 +00001191 : INHERITED(factory)
bsalomon@google.comc7818882013-03-20 19:19:53 +00001192 , fEffectMatrix(drawEffect.castEffect<GrLightingEffect>().coordsType()) {
1193 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194 fLight = m.light()->createGLLight();
1195}
1196
1197GrGLLightingEffect::~GrGLLightingEffect() {
1198 delete fLight;
1199}
1200
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001201void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001202 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001203 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001204 const char* outputColor,
1205 const char* inputColor,
1206 const TextureSamplerArray& samplers) {
commit-bot@chromium.org7ab7ca42013-08-28 15:59:13 +00001207 SkString coords;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001208 fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001209
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001210 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001211 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001212 "ImageIncrement");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001213 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001214 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001215 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001216 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001217 SkString lightFunc;
1218 this->emitLightFunc(builder, &lightFunc);
1219 static const GrGLShaderVar gSobelArgs[] = {
1220 GrGLShaderVar("a", kFloat_GrSLType),
1221 GrGLShaderVar("b", kFloat_GrSLType),
1222 GrGLShaderVar("c", kFloat_GrSLType),
1223 GrGLShaderVar("d", kFloat_GrSLType),
1224 GrGLShaderVar("e", kFloat_GrSLType),
1225 GrGLShaderVar("f", kFloat_GrSLType),
1226 GrGLShaderVar("scale", kFloat_GrSLType),
1227 };
1228 SkString sobelFuncName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001229 builder->fsEmitFunction(kFloat_GrSLType,
1230 "sobel",
1231 SK_ARRAY_COUNT(gSobelArgs),
1232 gSobelArgs,
1233 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1234 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001235 static const GrGLShaderVar gPointToNormalArgs[] = {
1236 GrGLShaderVar("x", kFloat_GrSLType),
1237 GrGLShaderVar("y", kFloat_GrSLType),
1238 GrGLShaderVar("scale", kFloat_GrSLType),
1239 };
1240 SkString pointToNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001241 builder->fsEmitFunction(kVec3f_GrSLType,
1242 "pointToNormal",
1243 SK_ARRAY_COUNT(gPointToNormalArgs),
1244 gPointToNormalArgs,
1245 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1246 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001247
1248 static const GrGLShaderVar gInteriorNormalArgs[] = {
1249 GrGLShaderVar("m", kFloat_GrSLType, 9),
1250 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1251 };
1252 SkString interiorNormalBody;
1253 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1254 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1255 "\t surfaceScale);\n",
1256 pointToNormalName.c_str(),
1257 sobelFuncName.c_str(),
1258 sobelFuncName.c_str());
1259 SkString interiorNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001260 builder->fsEmitFunction(kVec3f_GrSLType,
1261 "interiorNormal",
1262 SK_ARRAY_COUNT(gInteriorNormalArgs),
1263 gInteriorNormalArgs,
1264 interiorNormalBody.c_str(),
1265 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001266
commit-bot@chromium.org7ab7ca42013-08-28 15:59:13 +00001267 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001268 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001269
1270 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1271 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1272
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001273 int index = 0;
1274 for (int dy = -1; dy <= 1; dy++) {
1275 for (int dx = -1; dx <= 1; dx++) {
1276 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001277 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001278 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001279 builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001280 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001281 }
1282 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001283 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001284 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001285 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001286 fLight->emitSurfaceToLight(builder, arg.c_str());
1287 builder->fsCodeAppend(";\n");
1288 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1289 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001290 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001291 builder->fsCodeAppend(");\n");
1292 SkString modulate;
1293 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1294 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001295}
1296
bsalomon@google.comc7818882013-03-20 19:19:53 +00001297GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001298 const GrGLCaps& caps) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001299 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1300 EffectKey key = lighting.light()->type();
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001301 key <<= GrGLEffectMatrix::kKeyBits;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001302 EffectKey matrixKey = GrGLEffectMatrix::GenKey(lighting.getMatrix(),
1303 drawEffect,
1304 lighting.coordsType(),
1305 lighting.texture(0));
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001306 return key | matrixKey;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001307}
1308
bsalomon@google.comc7818882013-03-20 19:19:53 +00001309void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1310 const GrDrawEffect& drawEffect) {
1311 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1312 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001313 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001314 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001315 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001316 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1317 fLight->setData(uman, transformedLight);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001318 fEffectMatrix.setData(uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001319 lighting.getMatrix(),
1320 drawEffect,
1321 lighting.texture(0));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001322}
1323
1324///////////////////////////////////////////////////////////////////////////////
1325
1326///////////////////////////////////////////////////////////////////////////////
1327
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001328GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001329 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001330 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001331}
1332
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001333void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001334 const char* kd;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001335 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001336 kFloat_GrSLType,
1337 "KD",
1338 &kd);
1339
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001340 static const GrGLShaderVar gLightArgs[] = {
1341 GrGLShaderVar("normal", kVec3f_GrSLType),
1342 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1343 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1344 };
1345 SkString lightBody;
1346 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1347 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001348 builder->fsEmitFunction(kVec4f_GrSLType,
1349 "light",
1350 SK_ARRAY_COUNT(gLightArgs),
1351 gLightArgs,
1352 lightBody.c_str(),
1353 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001354}
1355
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001356void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001357 const GrDrawEffect& drawEffect) {
1358 INHERITED::setData(uman, drawEffect);
1359 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1360 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001361}
1362
1363///////////////////////////////////////////////////////////////////////////////
1364
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001365GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1366 const SkLight* light,
1367 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001368 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001369 SkScalar ks,
1370 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001371 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001372 fKS(ks),
1373 fShininess(shininess) {
1374}
1375
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001376const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1377 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001378}
1379
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001380bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001381 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001382 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001383 this->ks() == s.ks() &&
1384 this->shininess() == s.shininess();
1385}
1386
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001387GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001388
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001389GrEffectRef* GrSpecularLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001390 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001391 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001392 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001393 SkScalar surfaceScale = random->nextSScalar1();
1394 SkScalar ks = random->nextUScalar1();
1395 SkScalar shininess = random->nextUScalar1();
1396 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001397 SkMatrix matrix;
1398 for (int i = 0; i < 9; i++) {
1399 matrix[i] = random->nextUScalar1();
1400 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001401 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001402 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001403}
1404
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001405///////////////////////////////////////////////////////////////////////////////
1406
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001407GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001408 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001409 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001410}
1411
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001412void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001413 const char* ks;
1414 const char* shininess;
1415
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001416 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001417 kFloat_GrSLType, "KS", &ks);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001418 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001419 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001420
1421 static const GrGLShaderVar gLightArgs[] = {
1422 GrGLShaderVar("normal", kVec3f_GrSLType),
1423 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1424 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1425 };
1426 SkString lightBody;
1427 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1428 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001429 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1430 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001431 builder->fsEmitFunction(kVec4f_GrSLType,
1432 "light",
1433 SK_ARRAY_COUNT(gLightArgs),
1434 gLightArgs,
1435 lightBody.c_str(),
1436 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001437}
1438
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001439void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001440 const GrDrawEffect& drawEffect) {
1441 INHERITED::setData(uman, drawEffect);
1442 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1443 uman.set1f(fKSUni, spec.ks());
1444 uman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001445}
1446
1447///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001448void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001449 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001450 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001451}
1452
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001453void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1454 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001455 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001456}
1457
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001458void GrGLLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001459 const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001460 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001461}
1462
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001463///////////////////////////////////////////////////////////////////////////////
1464
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001465void GrGLDistantLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001466 const SkLight* light) const {
1467 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001468 SkASSERT(light->type() == SkLight::kDistant_LightType);
1469 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001470 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001471}
1472
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001473void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001474 const char* dir;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001475 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001476 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001477 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001478}
1479
1480///////////////////////////////////////////////////////////////////////////////
1481
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001482void GrGLPointLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001483 const SkLight* light) const {
1484 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001485 SkASSERT(light->type() == SkLight::kPoint_LightType);
1486 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001487 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001488}
1489
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001490void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001491 const char* loc;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001492 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001493 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001494 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001495}
1496
1497///////////////////////////////////////////////////////////////////////////////
1498
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001499void GrGLSpotLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001500 const SkLight* light) const {
1501 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001502 SkASSERT(light->type() == SkLight::kSpot_LightType);
1503 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001504 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001505 uman.set1f(fExponentUni, spotLight->specularExponent());
1506 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1507 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1508 uman.set1f(fConeScaleUni, spotLight->coneScale());
1509 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001510}
1511
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001512void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001513 const char* location;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001514 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001515 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001516 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1517 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518}
1519
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001520void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1521 const char *surfaceToLight) {
1522
1523 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1524
1525 const char* exponent;
1526 const char* cosInner;
1527 const char* cosOuter;
1528 const char* coneScale;
1529 const char* s;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001530 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001531 kFloat_GrSLType, "Exponent", &exponent);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001532 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001533 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001534 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001535 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001536 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001537 kFloat_GrSLType, "ConeScale", &coneScale);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001538 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001539 kVec3f_GrSLType, "S", &s);
1540
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001541 static const GrGLShaderVar gLightColorArgs[] = {
1542 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1543 };
1544 SkString lightColorBody;
1545 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1546 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1547 lightColorBody.appendf("\t\treturn vec3(0);\n");
1548 lightColorBody.appendf("\t}\n");
1549 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1550 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1551 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1552 color, cosOuter, coneScale);
1553 lightColorBody.appendf("\t}\n");
1554 lightColorBody.appendf("\treturn %s;\n", color);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001555 builder->fsEmitFunction(kVec3f_GrSLType,
1556 "lightColor",
1557 SK_ARRAY_COUNT(gLightColorArgs),
1558 gLightColorArgs,
1559 lightColorBody.c_str(),
1560 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001561
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001562 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001563}
1564
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001565#endif
1566
djsollen@google.com08337772012-06-26 14:33:13 +00001567SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1568 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1569 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1570 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1571 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1572 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1573SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END