blob: c28b317e225c41bfcd04a338b3b59c789b1831db [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkFlattenableBuffers.h"
12#include "SkOrderedReadBuffer.h"
13#include "SkOrderedWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000015
16#if SK_SUPPORT_GPU
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000017#include "effects/GrSingleTextureEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000018#include "gl/GrGLEffect.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000019#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000020#include "GrTBackendEffectFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000021
22class GrGLDiffuseLightingEffect;
23class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000024
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000025// For brevity
26typedef GrGLUniformManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000027#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000028
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000029namespace {
30
31const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
32const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
33const SkScalar gOneHalf = SkFloatToScalar(0.5f);
34const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
35
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000036#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000037void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000038 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000039 uman.set3fv(uni, 0, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000040}
41
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000042void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000043 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000044}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000045#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000046
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000047// Shift matrix components to the left, as we advance pixels to the right.
48inline void shiftMatrixLeft(int m[9]) {
49 m[0] = m[1];
50 m[3] = m[4];
51 m[6] = m[7];
52 m[1] = m[2];
53 m[4] = m[5];
54 m[7] = m[8];
55}
56
57class DiffuseLightingType {
58public:
59 DiffuseLightingType(SkScalar kd)
60 : fKD(kd) {}
61 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
62 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
63 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
64 SkPoint3 color(lightColor * colorScale);
65 return SkPackARGB32(255,
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000066 SkClampMax(SkScalarFloorToInt(color.fX), 255),
67 SkClampMax(SkScalarFloorToInt(color.fY), 255),
68 SkClampMax(SkScalarFloorToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000069 }
70private:
71 SkScalar fKD;
72};
73
74class SpecularLightingType {
75public:
76 SpecularLightingType(SkScalar ks, SkScalar shininess)
77 : fKS(ks), fShininess(shininess) {}
78 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
79 SkPoint3 halfDir(surfaceTolight);
80 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
81 halfDir.normalize();
82 SkScalar colorScale = SkScalarMul(fKS,
83 SkScalarPow(normal.dot(halfDir), fShininess));
84 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
85 SkPoint3 color(lightColor * colorScale);
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000086 return SkPackARGB32(SkClampMax(SkScalarFloorToInt(color.maxComponent()), 255),
87 SkClampMax(SkScalarFloorToInt(color.fX), 255),
88 SkClampMax(SkScalarFloorToInt(color.fY), 255),
89 SkClampMax(SkScalarFloorToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000090 }
91private:
92 SkScalar fKS;
93 SkScalar fShininess;
94};
95
96inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
97 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
98}
99
100inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
101 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
102 SkScalarMul(-y, surfaceScale),
103 SK_Scalar1);
104 vector.normalize();
105 return vector;
106}
107
108inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
109 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
110 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
111 surfaceScale);
112}
113
114inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
116 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
117 surfaceScale);
118}
119
120inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
122 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
123 surfaceScale);
124}
125
126inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
128 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
129 surfaceScale);
130}
131
132
133inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
134 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
135 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
136 surfaceScale);
137}
138
139inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
141 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
142 surfaceScale);
143}
144
145inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
147 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
148 surfaceScale);
149}
150
151inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
153 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
159 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
160 surfaceScale);
161}
162
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000163template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
164 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000165 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000166 int left = bounds.left(), right = bounds.right();
167 int bottom = bounds.bottom();
168 int y = bounds.top();
169 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000170 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000171 int x = left;
172 const SkPMColor* row1 = src.getAddr32(x, y);
173 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000174 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000175 m[4] = SkGetPackedA32(*row1++);
176 m[5] = SkGetPackedA32(*row1++);
177 m[7] = SkGetPackedA32(*row2++);
178 m[8] = SkGetPackedA32(*row2++);
179 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000180 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000181 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000182 {
183 shiftMatrixLeft(m);
184 m[5] = SkGetPackedA32(*row1++);
185 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000186 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000187 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 }
189 shiftMatrixLeft(m);
190 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000191 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000192 }
193
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000194 for (++y; y < bottom - 1; ++y) {
195 int x = left;
196 const SkPMColor* row0 = src.getAddr32(x, y - 1);
197 const SkPMColor* row1 = src.getAddr32(x, y);
198 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000199 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000200 m[1] = SkGetPackedA32(*row0++);
201 m[2] = SkGetPackedA32(*row0++);
202 m[4] = SkGetPackedA32(*row1++);
203 m[5] = SkGetPackedA32(*row1++);
204 m[7] = SkGetPackedA32(*row2++);
205 m[8] = SkGetPackedA32(*row2++);
206 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000207 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000208 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000209 shiftMatrixLeft(m);
210 m[2] = SkGetPackedA32(*row0++);
211 m[5] = SkGetPackedA32(*row1++);
212 m[8] = SkGetPackedA32(*row2++);
213 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000214 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000215 }
216 shiftMatrixLeft(m);
217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000218 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000219 }
220
221 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000222 int x = left;
223 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
224 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000225 int m[9];
226 m[1] = SkGetPackedA32(*row0++);
227 m[2] = SkGetPackedA32(*row0++);
228 m[4] = SkGetPackedA32(*row1++);
229 m[5] = SkGetPackedA32(*row1++);
230 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000231 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000232 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 {
234 shiftMatrixLeft(m);
235 m[2] = SkGetPackedA32(*row0++);
236 m[5] = SkGetPackedA32(*row1++);
237 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000238 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 }
240 shiftMatrixLeft(m);
241 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000242 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000243 }
244}
245
246SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) {
247 SkPoint3 point;
248 point.fX = buffer.readScalar();
249 point.fY = buffer.readScalar();
250 point.fZ = buffer.readScalar();
251 return point;
252};
253
254void writePoint3(const SkPoint3& point, SkFlattenableWriteBuffer& buffer) {
255 buffer.writeScalar(point.fX);
256 buffer.writeScalar(point.fY);
257 buffer.writeScalar(point.fZ);
258};
259
260class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
261public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000262 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000263 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
265
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000266#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000267 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const SK_OVERRIDE;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000268#endif
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000269 SkScalar kd() const { return fKD; }
270
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271protected:
272 explicit SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer);
273 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
274 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
275 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
276
277
278private:
279 typedef SkLightingImageFilter INHERITED;
280 SkScalar fKD;
281};
282
283class SkSpecularLightingImageFilter : public SkLightingImageFilter {
284public:
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000285 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
287
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000288#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000289 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const SK_OVERRIDE;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000290#endif
291
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000292 SkScalar ks() const { return fKS; }
293 SkScalar shininess() const { return fShininess; }
294
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000295protected:
296 explicit SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer);
297 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE;
298 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
299 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
300
301private:
302 typedef SkLightingImageFilter INHERITED;
303 SkScalar fKS;
304 SkScalar fShininess;
305};
306
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000307#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000308
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000309class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000310public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000311 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000312 virtual ~GrLightingEffect();
313
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000314 const SkLight* light() const { return fLight; }
315 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000316 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000317
318 virtual void getConstantColorComponents(GrColor* color,
319 uint32_t* validFlags) const SK_OVERRIDE {
320 // lighting shaders are complicated. We just throw up our hands.
321 *validFlags = 0;
322 }
323
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000324protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000325 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000326
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000327private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000328 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000329 const SkLight* fLight;
330 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000331 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000332};
333
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000334class GrDiffuseLightingEffect : public GrLightingEffect {
335public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000336 static GrEffectRef* Create(GrTexture* texture,
337 const SkLight* light,
338 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000339 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000340 SkScalar kd) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000341 AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
342 light,
343 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000344 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000345 kd)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000346 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000347 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000348
349 static const char* Name() { return "DiffuseLighting"; }
350
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000351 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000352
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000353 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000354 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000355
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000356private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000357 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000358
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000359 GrDiffuseLightingEffect(GrTexture* texture,
360 const SkLight* light,
361 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000362 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000363 SkScalar kd);
364
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000365 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000366 typedef GrLightingEffect INHERITED;
367 SkScalar fKD;
368};
369
370class GrSpecularLightingEffect : public GrLightingEffect {
371public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000372 static GrEffectRef* Create(GrTexture* texture,
373 const SkLight* light,
374 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000375 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000376 SkScalar ks,
377 SkScalar shininess) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000378 AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
379 light,
380 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000381 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000382 ks,
383 shininess)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000384 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000385 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000386 static const char* Name() { return "SpecularLighting"; }
387
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000388 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000389
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000390 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000391 SkScalar ks() const { return fKS; }
392 SkScalar shininess() const { return fShininess; }
393
394private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000395 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000396
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000397 GrSpecularLightingEffect(GrTexture* texture,
398 const SkLight* light,
399 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000400 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000401 SkScalar ks,
402 SkScalar shininess);
403
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000404 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000405 typedef GrLightingEffect INHERITED;
406 SkScalar fKS;
407 SkScalar fShininess;
408};
409
410///////////////////////////////////////////////////////////////////////////////
411
412class GrGLLight {
413public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000414 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000415
416 /**
417 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
418 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
419 */
420 void emitLightColorUniform(GrGLShaderBuilder*);
421
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000422 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000423 * These two functions are called from GrGLLightingEffect's emitCode() function.
424 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
425 * the light. The expression will be used in the FS. emitLightColor writes an expression into
426 * the FS that is the color of the light. Either function may add functions and/or uniforms to
427 * the FS. The default of emitLightColor appends the name of the constant light color uniform
428 * and so this function only needs to be overridden if the light color varies spatially.
429 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000430 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000431 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
432
433 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
434 // INHERITED::setData().
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000435 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000436 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000437
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000438protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000439 /**
440 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
441 * function.
442 */
443 UniformHandle lightColorUni() const { return fColorUni; }
444
445private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000446 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000447
448 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000449};
450
451///////////////////////////////////////////////////////////////////////////////
452
453class GrGLDistantLight : public GrGLLight {
454public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000455 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000456 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000457 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000458 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000459
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000460private:
461 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000462 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000463};
464
465///////////////////////////////////////////////////////////////////////////////
466
467class GrGLPointLight : public GrGLLight {
468public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000469 virtual ~GrGLPointLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000470 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000471 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000472 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000473
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000474private:
475 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000476 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000477};
478
479///////////////////////////////////////////////////////////////////////////////
480
481class GrGLSpotLight : public GrGLLight {
482public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000483 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000484 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000485 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000486 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000487 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000488
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000489private:
490 typedef GrGLLight INHERITED;
491
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000492 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000493 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000494 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000496 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000497 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000498 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000499};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000500#else
501
502class GrGLLight;
503
504#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000505
506};
507
508///////////////////////////////////////////////////////////////////////////////
509
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000510class SkLight : public SkFlattenable {
511public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000512 SK_DECLARE_INST_COUNT(SkLight)
513
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000514 enum LightType {
515 kDistant_LightType,
516 kPoint_LightType,
517 kSpot_LightType,
518 };
519 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000520 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000521 virtual GrGLLight* createGLLight() const = 0;
522 virtual bool isEqual(const SkLight& other) const {
523 return fColor == other.fColor;
524 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000525 // Called to know whether the generated GrGLLight will require access to the fragment position.
526 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000527 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000528
djsollen@google.com08337772012-06-26 14:33:13 +0000529protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000530 SkLight(SkColor color)
531 : fColor(SkIntToScalar(SkColorGetR(color)),
532 SkIntToScalar(SkColorGetG(color)),
533 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000534 SkLight(const SkPoint3& color)
535 : fColor(color) {}
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000536 SkLight(SkFlattenableReadBuffer& buffer)
537 : INHERITED(buffer) {
538 fColor = readPoint3(buffer);
539 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000540 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000541 INHERITED::flatten(buffer);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000542 writePoint3(fColor, buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000543 }
djsollen@google.com08337772012-06-26 14:33:13 +0000544
545private:
546 typedef SkFlattenable INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000547 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000548};
549
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000550SK_DEFINE_INST_COUNT(SkLight)
551
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000552///////////////////////////////////////////////////////////////////////////////
553
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000554class SkDistantLight : public SkLight {
555public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000556 SkDistantLight(const SkPoint3& direction, SkColor color)
557 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000558 }
djsollen@google.com08337772012-06-26 14:33:13 +0000559
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
561 return fDirection;
562 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000563 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000564 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000566 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
567#if SK_SUPPORT_GPU
568 return SkNEW(GrGLDistantLight);
569#else
570 SkDEBUGFAIL("Should not call in GPU-less build");
571 return NULL;
572#endif
573 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000574 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
575
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000576 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
577 if (other.type() != kDistant_LightType) {
578 return false;
579 }
580
581 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
582 return INHERITED::isEqual(other) &&
583 fDirection == o.fDirection;
584 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000585
586 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDistantLight)
587
djsollen@google.com08337772012-06-26 14:33:13 +0000588protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000589 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
590 : INHERITED(color), fDirection(direction) {
591 }
djsollen@google.com08337772012-06-26 14:33:13 +0000592 SkDistantLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
593 fDirection = readPoint3(buffer);
594 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000595 virtual SkLight* transform(const SkMatrix& matrix) const {
596 return new SkDistantLight(direction(), color());
597 }
djsollen@google.com08337772012-06-26 14:33:13 +0000598 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
599 INHERITED::flatten(buffer);
600 writePoint3(fDirection, buffer);
601 }
602
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000603private:
djsollen@google.com08337772012-06-26 14:33:13 +0000604 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000605 SkPoint3 fDirection;
606};
607
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000608///////////////////////////////////////////////////////////////////////////////
609
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000610class SkPointLight : public SkLight {
611public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000612 SkPointLight(const SkPoint3& location, SkColor color)
613 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000614
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000615 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
616 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
617 fLocation.fY - SkIntToScalar(y),
618 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
619 direction.normalize();
620 return direction;
621 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000622 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000623 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000624 const SkPoint3& location() const { return fLocation; }
625 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000626#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000627 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000628#else
629 SkDEBUGFAIL("Should not call in GPU-less build");
630 return NULL;
631#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000633 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000634 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000635 if (other.type() != kPoint_LightType) {
636 return false;
637 }
638 const SkPointLight& o = static_cast<const SkPointLight&>(other);
639 return INHERITED::isEqual(other) &&
640 fLocation == o.fLocation;
641 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000642 virtual SkLight* transform(const SkMatrix& matrix) const {
643 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
644 matrix.mapPoints(&location2, 1);
645 SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
646 return new SkPointLight(location, color());
647 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000648
649 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPointLight)
650
djsollen@google.com08337772012-06-26 14:33:13 +0000651protected:
652 SkPointLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
653 fLocation = readPoint3(buffer);
654 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000655 SkPointLight(const SkPoint3& location, const SkPoint3& color)
656 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000657 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
658 INHERITED::flatten(buffer);
659 writePoint3(fLocation, buffer);
660 }
661
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000662private:
djsollen@google.com08337772012-06-26 14:33:13 +0000663 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000664 SkPoint3 fLocation;
665};
666
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000667///////////////////////////////////////////////////////////////////////////////
668
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000669class SkSpotLight : public SkLight {
670public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000671 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
672 : INHERITED(color),
673 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000674 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000675 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000676 {
677 fS = target - location;
678 fS.normalize();
679 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
680 const SkScalar antiAliasThreshold = SkFloatToScalar(0.016f);
681 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
682 fConeScale = SkScalarInvert(antiAliasThreshold);
683 }
djsollen@google.com08337772012-06-26 14:33:13 +0000684
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000685 virtual SkLight* transform(const SkMatrix& matrix) const {
686 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
687 matrix.mapPoints(&location2, 1);
688 SkPoint3 location(location2.fX, location2.fY, fLocation.fZ);
689 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
690 matrix.mapPoints(&target2, 1);
691 SkPoint3 target(target2.fX, target2.fY, fTarget.fZ);
692 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, fS, color());
693 }
694
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
696 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
697 fLocation.fY - SkIntToScalar(y),
698 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
699 direction.normalize();
700 return direction;
701 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000702 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703 SkScalar cosAngle = -surfaceToLight.dot(fS);
704 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000705 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000706 }
707 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
708 if (cosAngle < fCosInnerConeAngle) {
709 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000710 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000711 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000712 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000713 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000714 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000715#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000716 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000717#else
718 SkDEBUGFAIL("Should not call in GPU-less build");
719 return NULL;
720#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000721 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000722 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000723 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000724 const SkPoint3& location() const { return fLocation; }
725 const SkPoint3& target() const { return fTarget; }
726 SkScalar specularExponent() const { return fSpecularExponent; }
727 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
728 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
729 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000730 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000731
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000732 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotLight)
733
djsollen@google.com08337772012-06-26 14:33:13 +0000734protected:
735 SkSpotLight(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
736 fLocation = readPoint3(buffer);
737 fTarget = readPoint3(buffer);
738 fSpecularExponent = buffer.readScalar();
739 fCosOuterConeAngle = buffer.readScalar();
740 fCosInnerConeAngle = buffer.readScalar();
741 fConeScale = buffer.readScalar();
742 fS = readPoint3(buffer);
743 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000744 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
745 : INHERITED(color),
746 fLocation(location),
747 fTarget(target),
748 fSpecularExponent(specularExponent),
749 fCosOuterConeAngle(cosOuterConeAngle),
750 fCosInnerConeAngle(cosInnerConeAngle),
751 fConeScale(coneScale),
752 fS(s)
753 {
754 }
djsollen@google.com08337772012-06-26 14:33:13 +0000755 virtual void flatten(SkFlattenableWriteBuffer& buffer) const {
756 INHERITED::flatten(buffer);
757 writePoint3(fLocation, buffer);
758 writePoint3(fTarget, buffer);
759 buffer.writeScalar(fSpecularExponent);
760 buffer.writeScalar(fCosOuterConeAngle);
761 buffer.writeScalar(fCosInnerConeAngle);
762 buffer.writeScalar(fConeScale);
763 writePoint3(fS, buffer);
764 }
765
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000766 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000767 if (other.type() != kSpot_LightType) {
768 return false;
769 }
770
771 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
772 return INHERITED::isEqual(other) &&
773 fLocation == o.fLocation &&
774 fTarget == o.fTarget &&
775 fSpecularExponent == o.fSpecularExponent &&
776 fCosOuterConeAngle == o.fCosOuterConeAngle;
777 }
778
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000780 static const SkScalar kSpecularExponentMin;
781 static const SkScalar kSpecularExponentMax;
782
djsollen@google.com08337772012-06-26 14:33:13 +0000783 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784 SkPoint3 fLocation;
785 SkPoint3 fTarget;
786 SkScalar fSpecularExponent;
787 SkScalar fCosOuterConeAngle;
788 SkScalar fCosInnerConeAngle;
789 SkScalar fConeScale;
790 SkPoint3 fS;
791};
792
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000793// According to the spec, the specular term should be in the range [1, 128] :
794// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
795const SkScalar SkSpotLight::kSpecularExponentMin = SkFloatToScalar(1.0f);
796const SkScalar SkSpotLight::kSpecularExponentMax = SkFloatToScalar(128.0f);
797
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000798///////////////////////////////////////////////////////////////////////////////
799
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000800SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000801 : INHERITED(input, cropRect),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000802 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000803 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
804{
805 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000806 // our caller knows that we take ownership of the light, so we don't
807 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000808}
809
810SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000811 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000812 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000813 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000814 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000815 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000816}
817
818SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000819 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000820 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000821 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000822 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000823 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000824}
825
826SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000827 const SkPoint3& location, const SkPoint3& target,
828 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000829 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000830 SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000831 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000832 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
833 cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000834 surfaceScale, kd, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000835}
836
837SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000838 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000839 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000840 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000841 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000842 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000843}
844
845SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000846 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000847 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000848 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000849 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000850 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851}
852
853SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000854 const SkPoint3& location, const SkPoint3& target,
855 SkScalar specularExponent, SkScalar cutoffAngle,
856 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000857 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000858 return SkNEW_ARGS(SkSpecularLightingImageFilter,
859 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000860 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000861}
862
863SkLightingImageFilter::~SkLightingImageFilter() {
864 fLight->unref();
865}
866
867SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer)
868 : INHERITED(buffer)
869{
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000870 fLight = buffer.readFlattenableT<SkLight>();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000871 fSurfaceScale = buffer.readScalar();
872}
873
874void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
875 this->INHERITED::flatten(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000876 buffer.writeFlattenable(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000877 buffer.writeScalar(fSurfaceScale);
878}
879
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000880///////////////////////////////////////////////////////////////////////////////
881
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000882SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000883 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000884 fKD(kd)
885{
886}
887
888SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuffer& buffer)
889 : INHERITED(buffer)
890{
891 fKD = buffer.readScalar();
892}
893
894void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
895 this->INHERITED::flatten(buffer);
896 buffer.writeScalar(fKD);
897}
898
899bool SkDiffuseLightingImageFilter::onFilterImage(Proxy*,
900 const SkBitmap& src,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000901 const SkMatrix& ctm,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902 SkBitmap* dst,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000903 SkIPoint* offset) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904 if (src.config() != SkBitmap::kARGB_8888_Config) {
905 return false;
906 }
907 SkAutoLockPixels alp(src);
908 if (!src.getPixels()) {
909 return false;
910 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000911
912 SkIRect bounds;
913 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000914 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000915 return false;
916 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000917
918 if (bounds.width() < 2 || bounds.height() < 2) {
919 return false;
920 }
921
922 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 dst->allocPixels();
924
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000925 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
926
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000927 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000928 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000929 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000930 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000931 break;
932 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000933 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000934 break;
935 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000936 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000937 break;
938 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000939
940 offset->fX += bounds.left();
941 offset->fY += bounds.top();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000942 return true;
943}
944
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000945#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000946bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000947 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000948 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000949 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000950 }
951 return true;
952}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000953#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000954
955///////////////////////////////////////////////////////////////////////////////
956
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000957SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000958 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000959 fKS(ks),
960 fShininess(shininess)
961{
962}
963
964SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBuffer& buffer)
965 : INHERITED(buffer)
966{
967 fKS = buffer.readScalar();
968 fShininess = buffer.readScalar();
969}
970
971void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
972 this->INHERITED::flatten(buffer);
973 buffer.writeScalar(fKS);
974 buffer.writeScalar(fShininess);
975}
976
977bool SkSpecularLightingImageFilter::onFilterImage(Proxy*,
978 const SkBitmap& src,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000979 const SkMatrix& ctm,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980 SkBitmap* dst,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000981 SkIPoint* offset) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000982 if (src.config() != SkBitmap::kARGB_8888_Config) {
983 return false;
984 }
985 SkAutoLockPixels alp(src);
986 if (!src.getPixels()) {
987 return false;
988 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000989
990 SkIRect bounds;
991 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000992 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000993 return false;
994 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000995
996 if (bounds.width() < 2 || bounds.height() < 2) {
997 return false;
998 }
999
1000 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001001 dst->allocPixels();
1002
1003 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001004 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
1005 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001006 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001007 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001008 break;
1009 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001010 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001011 break;
1012 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001013 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001014 break;
1015 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001016 offset->fX += bounds.left();
1017 offset->fY += bounds.top();
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001018 return true;
1019}
1020
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001021#if SK_SUPPORT_GPU
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001022bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001023 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001024 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001025 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001026 }
1027 return true;
1028}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001029#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001030
1031///////////////////////////////////////////////////////////////////////////////
1032
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001033#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001034
1035namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001036SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001037 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1038 SkScalarToFloat(random->nextSScalar1()),
1039 SkScalarToFloat(random->nextSScalar1()));
1040}
1041
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001042SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001043 int type = random->nextULessThan(3);
1044 switch (type) {
1045 case 0: {
1046 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1047 }
1048 case 1: {
1049 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1050 }
1051 case 2: {
1052 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1053 random_point3(random),
1054 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001055 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001056 random->nextU()));
1057 }
1058 default:
1059 GrCrash();
1060 return NULL;
1061 }
1062}
1063
1064}
1065
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001066class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001067public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001068 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001069 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001070 virtual ~GrGLLightingEffect();
1071
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001072 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001073 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001074 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001075 const char* outputColor,
1076 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001077 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001078 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001079
bsalomon@google.comc7818882013-03-20 19:19:53 +00001080 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001081
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001082 /**
1083 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1084 */
bsalomon@google.comc7818882013-03-20 19:19:53 +00001085 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001086
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001087protected:
1088 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1089
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001090private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001091 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001092
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001093 UniformHandle fImageIncrementUni;
1094 UniformHandle fSurfaceScaleUni;
1095 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001096};
1097
1098///////////////////////////////////////////////////////////////////////////////
1099
1100class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1101public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001102 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001103 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001104 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001105 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001106
1107private:
1108 typedef GrGLLightingEffect INHERITED;
1109
bsalomon@google.com032b2212012-07-16 13:36:18 +00001110 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001111};
1112
1113///////////////////////////////////////////////////////////////////////////////
1114
1115class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1116public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001117 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001118 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001119 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001120 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001121
1122private:
1123 typedef GrGLLightingEffect INHERITED;
1124
bsalomon@google.com032b2212012-07-16 13:36:18 +00001125 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001126 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001127};
1128
1129///////////////////////////////////////////////////////////////////////////////
1130
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001131GrLightingEffect::GrLightingEffect(GrTexture* texture,
1132 const SkLight* light,
1133 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001134 const SkMatrix& matrix)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001135 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001136 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001137 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001138 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001139 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001140 if (light->requiresFragmentPosition()) {
1141 this->setWillReadFragmentPosition();
1142 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001143}
1144
1145GrLightingEffect::~GrLightingEffect() {
1146 fLight->unref();
1147}
1148
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001149bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001150 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001151 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001152 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001153 fSurfaceScale == s.fSurfaceScale;
1154}
1155
1156///////////////////////////////////////////////////////////////////////////////
1157
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001158GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1159 const SkLight* light,
1160 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001161 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001162 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001163 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001164}
1165
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001166const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1167 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001168}
1169
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001170bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001171 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001172 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001173 this->kd() == s.kd();
1174}
1175
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001176GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001177
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001178GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001179 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001180 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001181 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001182 SkScalar surfaceScale = random->nextSScalar1();
1183 SkScalar kd = random->nextUScalar1();
1184 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001185 SkMatrix matrix;
1186 for (int i = 0; i < 9; i++) {
1187 matrix[i] = random->nextUScalar1();
1188 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001189 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001190 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001191}
1192
1193
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001194///////////////////////////////////////////////////////////////////////////////
1195
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001196GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001197 const GrDrawEffect& drawEffect)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001198 : INHERITED(factory) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001199 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001200 fLight = m.light()->createGLLight();
1201}
1202
1203GrGLLightingEffect::~GrGLLightingEffect() {
1204 delete fLight;
1205}
1206
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001207void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001208 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001209 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001210 const char* outputColor,
1211 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001212 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001213 const TextureSamplerArray& samplers) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001214 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001215
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001216 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001217 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001218 "ImageIncrement");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001219 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001220 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001221 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001222 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001223 SkString lightFunc;
1224 this->emitLightFunc(builder, &lightFunc);
1225 static const GrGLShaderVar gSobelArgs[] = {
1226 GrGLShaderVar("a", kFloat_GrSLType),
1227 GrGLShaderVar("b", kFloat_GrSLType),
1228 GrGLShaderVar("c", kFloat_GrSLType),
1229 GrGLShaderVar("d", kFloat_GrSLType),
1230 GrGLShaderVar("e", kFloat_GrSLType),
1231 GrGLShaderVar("f", kFloat_GrSLType),
1232 GrGLShaderVar("scale", kFloat_GrSLType),
1233 };
1234 SkString sobelFuncName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001235 builder->fsEmitFunction(kFloat_GrSLType,
1236 "sobel",
1237 SK_ARRAY_COUNT(gSobelArgs),
1238 gSobelArgs,
1239 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1240 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001241 static const GrGLShaderVar gPointToNormalArgs[] = {
1242 GrGLShaderVar("x", kFloat_GrSLType),
1243 GrGLShaderVar("y", kFloat_GrSLType),
1244 GrGLShaderVar("scale", kFloat_GrSLType),
1245 };
1246 SkString pointToNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001247 builder->fsEmitFunction(kVec3f_GrSLType,
1248 "pointToNormal",
1249 SK_ARRAY_COUNT(gPointToNormalArgs),
1250 gPointToNormalArgs,
1251 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1252 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001253
1254 static const GrGLShaderVar gInteriorNormalArgs[] = {
1255 GrGLShaderVar("m", kFloat_GrSLType, 9),
1256 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1257 };
1258 SkString interiorNormalBody;
1259 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1260 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1261 "\t surfaceScale);\n",
1262 pointToNormalName.c_str(),
1263 sobelFuncName.c_str(),
1264 sobelFuncName.c_str());
1265 SkString interiorNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001266 builder->fsEmitFunction(kVec3f_GrSLType,
1267 "interiorNormal",
1268 SK_ARRAY_COUNT(gInteriorNormalArgs),
1269 gInteriorNormalArgs,
1270 interiorNormalBody.c_str(),
1271 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001272
bsalomon@google.com77af6802013-10-02 13:04:56 +00001273 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001274 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001275
1276 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1277 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1278
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001279 int index = 0;
1280 for (int dy = -1; dy <= 1; dy++) {
1281 for (int dx = -1; dx <= 1; dx++) {
1282 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001283 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001284 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001285 builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001286 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001287 }
1288 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001289 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001290 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001291 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001292 fLight->emitSurfaceToLight(builder, arg.c_str());
1293 builder->fsCodeAppend(";\n");
1294 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1295 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001296 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001297 builder->fsCodeAppend(");\n");
1298 SkString modulate;
1299 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1300 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001301}
1302
bsalomon@google.comc7818882013-03-20 19:19:53 +00001303GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001304 const GrGLCaps& caps) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001305 return drawEffect.castEffect<GrLightingEffect>().light()->type();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001306}
1307
bsalomon@google.comc7818882013-03-20 19:19:53 +00001308void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1309 const GrDrawEffect& drawEffect) {
1310 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1311 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001312 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001313 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001314 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001315 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1316 fLight->setData(uman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001317}
1318
1319///////////////////////////////////////////////////////////////////////////////
1320
1321///////////////////////////////////////////////////////////////////////////////
1322
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001323GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001324 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001325 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001326}
1327
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001328void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001329 const char* kd;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001330 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001331 kFloat_GrSLType,
1332 "KD",
1333 &kd);
1334
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001335 static const GrGLShaderVar gLightArgs[] = {
1336 GrGLShaderVar("normal", kVec3f_GrSLType),
1337 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1338 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1339 };
1340 SkString lightBody;
1341 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1342 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001343 builder->fsEmitFunction(kVec4f_GrSLType,
1344 "light",
1345 SK_ARRAY_COUNT(gLightArgs),
1346 gLightArgs,
1347 lightBody.c_str(),
1348 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001349}
1350
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001351void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001352 const GrDrawEffect& drawEffect) {
1353 INHERITED::setData(uman, drawEffect);
1354 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1355 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001356}
1357
1358///////////////////////////////////////////////////////////////////////////////
1359
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001360GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1361 const SkLight* light,
1362 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001363 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001364 SkScalar ks,
1365 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001366 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001367 fKS(ks),
1368 fShininess(shininess) {
1369}
1370
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001371const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1372 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001373}
1374
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001375bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001376 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001377 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001378 this->ks() == s.ks() &&
1379 this->shininess() == s.shininess();
1380}
1381
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001382GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001383
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001384GrEffectRef* GrSpecularLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001385 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001386 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001387 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001388 SkScalar surfaceScale = random->nextSScalar1();
1389 SkScalar ks = random->nextUScalar1();
1390 SkScalar shininess = random->nextUScalar1();
1391 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001392 SkMatrix matrix;
1393 for (int i = 0; i < 9; i++) {
1394 matrix[i] = random->nextUScalar1();
1395 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001396 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001397 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001398}
1399
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001400///////////////////////////////////////////////////////////////////////////////
1401
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001402GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001403 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001404 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001405}
1406
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001407void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001408 const char* ks;
1409 const char* shininess;
1410
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001411 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001412 kFloat_GrSLType, "KS", &ks);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001413 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001414 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001415
1416 static const GrGLShaderVar gLightArgs[] = {
1417 GrGLShaderVar("normal", kVec3f_GrSLType),
1418 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1419 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1420 };
1421 SkString lightBody;
1422 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1423 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001424 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1425 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001426 builder->fsEmitFunction(kVec4f_GrSLType,
1427 "light",
1428 SK_ARRAY_COUNT(gLightArgs),
1429 gLightArgs,
1430 lightBody.c_str(),
1431 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001432}
1433
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001434void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001435 const GrDrawEffect& drawEffect) {
1436 INHERITED::setData(uman, drawEffect);
1437 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1438 uman.set1f(fKSUni, spec.ks());
1439 uman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001440}
1441
1442///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001443void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001444 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001445 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001446}
1447
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001448void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1449 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001450 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001451}
1452
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001453void GrGLLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001454 const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001455 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001456}
1457
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001458///////////////////////////////////////////////////////////////////////////////
1459
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001460void GrGLDistantLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001461 const SkLight* light) const {
1462 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001463 SkASSERT(light->type() == SkLight::kDistant_LightType);
1464 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001465 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001466}
1467
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001468void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001469 const char* dir;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001470 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001471 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001472 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001473}
1474
1475///////////////////////////////////////////////////////////////////////////////
1476
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001477void GrGLPointLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001478 const SkLight* light) const {
1479 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001480 SkASSERT(light->type() == SkLight::kPoint_LightType);
1481 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001482 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001483}
1484
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001485void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001486 const char* loc;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001487 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001488 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001489 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001490}
1491
1492///////////////////////////////////////////////////////////////////////////////
1493
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001494void GrGLSpotLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001495 const SkLight* light) const {
1496 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001497 SkASSERT(light->type() == SkLight::kSpot_LightType);
1498 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001499 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001500 uman.set1f(fExponentUni, spotLight->specularExponent());
1501 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1502 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1503 uman.set1f(fConeScaleUni, spotLight->coneScale());
1504 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001505}
1506
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001507void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001508 const char* location;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001509 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001510 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001511 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1512 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001513}
1514
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001515void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1516 const char *surfaceToLight) {
1517
1518 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1519
1520 const char* exponent;
1521 const char* cosInner;
1522 const char* cosOuter;
1523 const char* coneScale;
1524 const char* s;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001525 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001526 kFloat_GrSLType, "Exponent", &exponent);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001527 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001528 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001529 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001530 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001531 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001532 kFloat_GrSLType, "ConeScale", &coneScale);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001533 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001534 kVec3f_GrSLType, "S", &s);
1535
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001536 static const GrGLShaderVar gLightColorArgs[] = {
1537 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1538 };
1539 SkString lightColorBody;
1540 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1541 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1542 lightColorBody.appendf("\t\treturn vec3(0);\n");
1543 lightColorBody.appendf("\t}\n");
1544 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1545 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1546 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1547 color, cosOuter, coneScale);
1548 lightColorBody.appendf("\t}\n");
1549 lightColorBody.appendf("\treturn %s;\n", color);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001550 builder->fsEmitFunction(kVec3f_GrSLType,
1551 "lightColor",
1552 SK_ARRAY_COUNT(gLightColorArgs),
1553 gLightColorArgs,
1554 lightColorBody.c_str(),
1555 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001556
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001557 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001558}
1559
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001560#endif
1561
djsollen@google.com08337772012-06-26 14:33:13 +00001562SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1563 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1564 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1565 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDistantLight)
1566 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPointLight)
1567 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotLight)
1568SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END