blob: 09ceef03ef47b380a9bad2a3fcb65bfff8ff397f [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"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000015#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000018#include "effects/GrSingleTextureEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000019#include "gl/GrGLEffect.h"
bsalomon@google.coma469c282012-10-24 18:28:34 +000020#include "GrEffect.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000021#include "GrTBackendEffectFactory.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000022
23class GrGLDiffuseLightingEffect;
24class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000025
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000026// For brevity
27typedef GrGLUniformManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000028#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000029
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000030namespace {
31
32const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
33const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000034const SkScalar gOneHalf = 0.5f;
35const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000036
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000037#if SK_SUPPORT_GPU
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000038void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000039 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
commit-bot@chromium.orgd3baf202013-11-07 22:06:08 +000040 uman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000041}
42
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000043void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
bsalomon@google.com706f6682012-10-23 14:53:55 +000044 setUniformPoint3(uman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000045}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000046#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000047
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000048// Shift matrix components to the left, as we advance pixels to the right.
49inline void shiftMatrixLeft(int m[9]) {
50 m[0] = m[1];
51 m[3] = m[4];
52 m[6] = m[7];
53 m[1] = m[2];
54 m[4] = m[5];
55 m[7] = m[8];
56}
57
58class DiffuseLightingType {
59public:
60 DiffuseLightingType(SkScalar kd)
61 : fKD(kd) {}
62 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
63 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
64 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
65 SkPoint3 color(lightColor * colorScale);
66 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000067 SkClampMax(SkScalarRoundToInt(color.fX), 255),
68 SkClampMax(SkScalarRoundToInt(color.fY), 255),
69 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000070 }
71private:
72 SkScalar fKD;
73};
74
75class SpecularLightingType {
76public:
77 SpecularLightingType(SkScalar ks, SkScalar shininess)
78 : fKS(ks), fShininess(shininess) {}
79 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
80 SkPoint3 halfDir(surfaceTolight);
81 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
82 halfDir.normalize();
83 SkScalar colorScale = SkScalarMul(fKS,
84 SkScalarPow(normal.dot(halfDir), fShininess));
85 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
86 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000087 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
88 SkClampMax(SkScalarRoundToInt(color.fX), 255),
89 SkClampMax(SkScalarRoundToInt(color.fY), 255),
90 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000091 }
92private:
93 SkScalar fKS;
94 SkScalar fShininess;
95};
96
97inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
98 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
99}
100
101inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
102 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
103 SkScalarMul(-y, surfaceScale),
104 SK_Scalar1);
105 vector.normalize();
106 return vector;
107}
108
109inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
110 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
111 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
112 surfaceScale);
113}
114
115inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
116 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
117 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
118 surfaceScale);
119}
120
121inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
122 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
123 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
124 surfaceScale);
125}
126
127inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
128 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
129 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
130 surfaceScale);
131}
132
133
134inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
135 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
136 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
137 surfaceScale);
138}
139
140inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
141 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
142 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
143 surfaceScale);
144}
145
146inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
147 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
148 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
149 surfaceScale);
150}
151
152inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
153 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
154 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
155 surfaceScale);
156}
157
158inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
160 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
161 surfaceScale);
162}
163
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000164template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
165 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000166 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000167 int left = bounds.left(), right = bounds.right();
168 int bottom = bounds.bottom();
169 int y = bounds.top();
170 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000171 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000172 int x = left;
173 const SkPMColor* row1 = src.getAddr32(x, y);
174 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000175 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000176 m[4] = SkGetPackedA32(*row1++);
177 m[5] = SkGetPackedA32(*row1++);
178 m[7] = SkGetPackedA32(*row2++);
179 m[8] = SkGetPackedA32(*row2++);
180 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000181 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000182 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000183 {
184 shiftMatrixLeft(m);
185 m[5] = SkGetPackedA32(*row1++);
186 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000187 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000188 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000189 }
190 shiftMatrixLeft(m);
191 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000192 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000193 }
194
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000195 for (++y; y < bottom - 1; ++y) {
196 int x = left;
197 const SkPMColor* row0 = src.getAddr32(x, y - 1);
198 const SkPMColor* row1 = src.getAddr32(x, y);
199 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000200 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000201 m[1] = SkGetPackedA32(*row0++);
202 m[2] = SkGetPackedA32(*row0++);
203 m[4] = SkGetPackedA32(*row1++);
204 m[5] = SkGetPackedA32(*row1++);
205 m[7] = SkGetPackedA32(*row2++);
206 m[8] = SkGetPackedA32(*row2++);
207 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000208 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000209 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 shiftMatrixLeft(m);
211 m[2] = SkGetPackedA32(*row0++);
212 m[5] = SkGetPackedA32(*row1++);
213 m[8] = SkGetPackedA32(*row2++);
214 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000215 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 }
217 shiftMatrixLeft(m);
218 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000219 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000220 }
221
222 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000223 int x = left;
224 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
225 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000226 int m[9];
227 m[1] = SkGetPackedA32(*row0++);
228 m[2] = SkGetPackedA32(*row0++);
229 m[4] = SkGetPackedA32(*row1++);
230 m[5] = SkGetPackedA32(*row1++);
231 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000232 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000233 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000234 {
235 shiftMatrixLeft(m);
236 m[2] = SkGetPackedA32(*row0++);
237 m[5] = SkGetPackedA32(*row1++);
238 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000239 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 }
241 shiftMatrixLeft(m);
242 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000243 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000244 }
245}
246
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000247SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 SkPoint3 point;
249 point.fX = buffer.readScalar();
250 point.fY = buffer.readScalar();
251 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000252 buffer.validate(SkScalarIsFinite(point.fX) &&
253 SkScalarIsFinite(point.fY) &&
254 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000255 return point;
256};
257
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000258void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000259 buffer.writeScalar(point.fX);
260 buffer.writeScalar(point.fY);
261 buffer.writeScalar(point.fZ);
262};
263
264class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
265public:
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000266 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000267 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000268 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000269 SkScalar kd() const { return fKD; }
270
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000272 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
273 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000274 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000275 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000276#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000277 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix, const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000278#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000279
280private:
281 typedef SkLightingImageFilter INHERITED;
282 SkScalar fKD;
283};
284
285class SkSpecularLightingImageFilter : public SkLightingImageFilter {
286public:
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000287 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000288 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
289
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000290 SkScalar ks() const { return fKS; }
291 SkScalar shininess() const { return fShininess; }
292
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000293protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000294 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
295 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000296 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000297 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000298#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000299 virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix, const SkIRect& bounds) const SK_OVERRIDE;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000300#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000301
302private:
303 typedef SkLightingImageFilter INHERITED;
304 SkScalar fKS;
305 SkScalar fShininess;
306};
307
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000308#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000309
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000310class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000311public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000312 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000313 virtual ~GrLightingEffect();
314
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000315 const SkLight* light() const { return fLight; }
316 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000317 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000318
319 virtual void getConstantColorComponents(GrColor* color,
320 uint32_t* validFlags) const SK_OVERRIDE {
321 // lighting shaders are complicated. We just throw up our hands.
322 *validFlags = 0;
323 }
324
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000325protected:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000326 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000327
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000328private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000329 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000330 const SkLight* fLight;
331 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000332 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000333};
334
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000335class GrDiffuseLightingEffect : public GrLightingEffect {
336public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000337 static GrEffectRef* Create(GrTexture* texture,
338 const SkLight* light,
339 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000340 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000341 SkScalar kd) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000342 AutoEffectUnref effect(SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
343 light,
344 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000345 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000346 kd)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000347 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000348 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000349
350 static const char* Name() { return "DiffuseLighting"; }
351
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000352 typedef GrGLDiffuseLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000353
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000354 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000355 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000356
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000357private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000358 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000359
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000360 GrDiffuseLightingEffect(GrTexture* texture,
361 const SkLight* light,
362 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000363 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000364 SkScalar kd);
365
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000366 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000367 typedef GrLightingEffect INHERITED;
368 SkScalar fKD;
369};
370
371class GrSpecularLightingEffect : public GrLightingEffect {
372public:
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000373 static GrEffectRef* Create(GrTexture* texture,
374 const SkLight* light,
375 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000376 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000377 SkScalar ks,
378 SkScalar shininess) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000379 AutoEffectUnref effect(SkNEW_ARGS(GrSpecularLightingEffect, (texture,
380 light,
381 surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000382 matrix,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000383 ks,
384 shininess)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000385 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000386 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000387 static const char* Name() { return "SpecularLighting"; }
388
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000389 typedef GrGLSpecularLightingEffect GLEffect;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000390
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000391 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000392 SkScalar ks() const { return fKS; }
393 SkScalar shininess() const { return fShininess; }
394
395private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000396 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000397
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000398 GrSpecularLightingEffect(GrTexture* texture,
399 const SkLight* light,
400 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000401 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000402 SkScalar ks,
403 SkScalar shininess);
404
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000405 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000406 typedef GrLightingEffect INHERITED;
407 SkScalar fKS;
408 SkScalar fShininess;
409};
410
411///////////////////////////////////////////////////////////////////////////////
412
413class GrGLLight {
414public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000415 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000416
417 /**
418 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
419 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
420 */
421 void emitLightColorUniform(GrGLShaderBuilder*);
422
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000423 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000424 * These two functions are called from GrGLLightingEffect's emitCode() function.
425 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
426 * the light. The expression will be used in the FS. emitLightColor writes an expression into
427 * the FS that is the color of the light. Either function may add functions and/or uniforms to
428 * the FS. The default of emitLightColor appends the name of the constant light color uniform
429 * and so this function only needs to be overridden if the light color varies spatially.
430 */
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000431 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000432 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
433
434 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
435 // INHERITED::setData().
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000436 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000437 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000438
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000439protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000440 /**
441 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
442 * function.
443 */
444 UniformHandle lightColorUni() const { return fColorUni; }
445
446private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000447 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000448
449 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000450};
451
452///////////////////////////////////////////////////////////////////////////////
453
454class GrGLDistantLight : public GrGLLight {
455public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000456 virtual ~GrGLDistantLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000457 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000458 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000459 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000460
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000461private:
462 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000463 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000464};
465
466///////////////////////////////////////////////////////////////////////////////
467
468class GrGLPointLight : public GrGLLight {
469public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000470 virtual ~GrGLPointLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000471 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000472 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000473 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000474
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000475private:
476 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000477 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000478};
479
480///////////////////////////////////////////////////////////////////////////////
481
482class GrGLSpotLight : public GrGLLight {
483public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000484 virtual ~GrGLSpotLight() {}
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000485 virtual void setData(const GrGLUniformManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000486 const SkLight* light) const SK_OVERRIDE;
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000487 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000488 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000489
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490private:
491 typedef GrGLLight INHERITED;
492
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000493 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000494 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000496 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000497 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000498 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000499 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000500};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000501#else
502
503class GrGLLight;
504
505#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506
507};
508
509///////////////////////////////////////////////////////////////////////////////
510
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000511class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000513 SK_DECLARE_INST_COUNT(SkLight)
514
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515 enum LightType {
516 kDistant_LightType,
517 kPoint_LightType,
518 kSpot_LightType,
519 };
520 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000521 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000522 virtual GrGLLight* createGLLight() const = 0;
523 virtual bool isEqual(const SkLight& other) const {
524 return fColor == other.fColor;
525 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000526 // Called to know whether the generated GrGLLight will require access to the fragment position.
527 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000528 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000529
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000530 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000531 void flattenLight(SkWriteBuffer& buffer) const;
532 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000533
djsollen@google.com08337772012-06-26 14:33:13 +0000534protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000535 SkLight(SkColor color)
536 : fColor(SkIntToScalar(SkColorGetR(color)),
537 SkIntToScalar(SkColorGetG(color)),
538 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000539 SkLight(const SkPoint3& color)
540 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000541 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000542 fColor = readPoint3(buffer);
543 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000544
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000545 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000546
djsollen@google.com08337772012-06-26 14:33:13 +0000547
548private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000549 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000550 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000551};
552
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000553///////////////////////////////////////////////////////////////////////////////
554
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000555class SkDistantLight : public SkLight {
556public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000557 SkDistantLight(const SkPoint3& direction, SkColor color)
558 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000559 }
djsollen@google.com08337772012-06-26 14:33:13 +0000560
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000561 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
562 return fDirection;
563 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000564 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000565 virtual LightType type() const { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566 const SkPoint3& direction() const { return fDirection; }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000567 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
568#if SK_SUPPORT_GPU
569 return SkNEW(GrGLDistantLight);
570#else
571 SkDEBUGFAIL("Should not call in GPU-less build");
572 return NULL;
573#endif
574 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000575 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
576
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000577 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
578 if (other.type() != kDistant_LightType) {
579 return false;
580 }
581
582 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
583 return INHERITED::isEqual(other) &&
584 fDirection == o.fDirection;
585 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000587 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000588 fDirection = readPoint3(buffer);
589 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000590
djsollen@google.com08337772012-06-26 14:33:13 +0000591protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000592 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
593 : INHERITED(color), fDirection(direction) {
594 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000595 virtual SkLight* transform(const SkMatrix& matrix) const {
596 return new SkDistantLight(direction(), color());
597 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000598 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000599 writePoint3(fDirection, buffer);
600 }
601
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000602private:
djsollen@google.com08337772012-06-26 14:33:13 +0000603 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000604 SkPoint3 fDirection;
605};
606
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000607///////////////////////////////////////////////////////////////////////////////
608
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000609class SkPointLight : public SkLight {
610public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000611 SkPointLight(const SkPoint3& location, SkColor color)
612 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000613
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000614 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
615 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
616 fLocation.fY - SkIntToScalar(y),
617 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
618 direction.normalize();
619 return direction;
620 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000621 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000622 virtual LightType type() const { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000623 const SkPoint3& location() const { return fLocation; }
624 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000625#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000626 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000627#else
628 SkDEBUGFAIL("Should not call in GPU-less build");
629 return NULL;
630#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000631 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000632 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000633 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000634 if (other.type() != kPoint_LightType) {
635 return false;
636 }
637 const SkPointLight& o = static_cast<const SkPointLight&>(other);
638 return INHERITED::isEqual(other) &&
639 fLocation == o.fLocation;
640 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000641 virtual SkLight* transform(const SkMatrix& matrix) const {
642 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
643 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000644 // Use X scale and Y scale on Z and average the result
645 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
646 matrix.mapVectors(&locationZ, 1);
647 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000648 return new SkPointLight(location, color());
649 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000650
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000651 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000652 fLocation = readPoint3(buffer);
653 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000654
655protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000656 SkPointLight(const SkPoint3& location, const SkPoint3& color)
657 : INHERITED(color), fLocation(location) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000658 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000659 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));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000680 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000681 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);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000688 // Use X scale and Y scale on Z and average the result
689 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
690 matrix.mapVectors(&locationZ, 1);
691 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000692 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
693 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000694 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
695 matrix.mapVectors(&targetZ, 1);
696 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
697 SkPoint3 s = target - location;
698 s.normalize();
699 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000700 }
701
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000702 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
703 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
704 fLocation.fY - SkIntToScalar(y),
705 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
706 direction.normalize();
707 return direction;
708 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000709 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000710 SkScalar cosAngle = -surfaceToLight.dot(fS);
711 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000712 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000713 }
714 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
715 if (cosAngle < fCosInnerConeAngle) {
716 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000717 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000718 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000719 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000720 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000721 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000722#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000723 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000724#else
725 SkDEBUGFAIL("Should not call in GPU-less build");
726 return NULL;
727#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000728 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000729 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
djsollen@google.com08337772012-06-26 14:33:13 +0000730 virtual LightType type() const { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000731 const SkPoint3& location() const { return fLocation; }
732 const SkPoint3& target() const { return fTarget; }
733 SkScalar specularExponent() const { return fSpecularExponent; }
734 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
735 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
736 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000737 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000738
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000739 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000740 fLocation = readPoint3(buffer);
741 fTarget = readPoint3(buffer);
742 fSpecularExponent = buffer.readScalar();
743 fCosOuterConeAngle = buffer.readScalar();
744 fCosInnerConeAngle = buffer.readScalar();
745 fConeScale = buffer.readScalar();
746 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000747 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
748 SkScalarIsFinite(fCosOuterConeAngle) &&
749 SkScalarIsFinite(fCosInnerConeAngle) &&
750 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000751 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000752protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000753 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
754 : INHERITED(color),
755 fLocation(location),
756 fTarget(target),
757 fSpecularExponent(specularExponent),
758 fCosOuterConeAngle(cosOuterConeAngle),
759 fCosInnerConeAngle(cosInnerConeAngle),
760 fConeScale(coneScale),
761 fS(s)
762 {
763 }
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000764 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
djsollen@google.com08337772012-06-26 14:33:13 +0000765 writePoint3(fLocation, buffer);
766 writePoint3(fTarget, buffer);
767 buffer.writeScalar(fSpecularExponent);
768 buffer.writeScalar(fCosOuterConeAngle);
769 buffer.writeScalar(fCosInnerConeAngle);
770 buffer.writeScalar(fConeScale);
771 writePoint3(fS, buffer);
772 }
773
senorblanco@chromium.orgbd9fad62012-07-11 16:25:37 +0000774 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000775 if (other.type() != kSpot_LightType) {
776 return false;
777 }
778
779 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
780 return INHERITED::isEqual(other) &&
781 fLocation == o.fLocation &&
782 fTarget == o.fTarget &&
783 fSpecularExponent == o.fSpecularExponent &&
784 fCosOuterConeAngle == o.fCosOuterConeAngle;
785 }
786
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000787private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000788 static const SkScalar kSpecularExponentMin;
789 static const SkScalar kSpecularExponentMax;
790
djsollen@google.com08337772012-06-26 14:33:13 +0000791 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000792 SkPoint3 fLocation;
793 SkPoint3 fTarget;
794 SkScalar fSpecularExponent;
795 SkScalar fCosOuterConeAngle;
796 SkScalar fCosInnerConeAngle;
797 SkScalar fConeScale;
798 SkPoint3 fS;
799};
800
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000801// According to the spec, the specular term should be in the range [1, 128] :
802// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000803const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
804const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000805
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000806///////////////////////////////////////////////////////////////////////////////
807
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000808void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000809 // Write type first, then baseclass, then subclass.
810 buffer.writeInt(this->type());
811 writePoint3(fColor, buffer);
812 this->onFlattenLight(buffer);
813}
814
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000815/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000816 // Read type first.
817 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
818 switch (type) {
819 // Each of these constructors must first call SkLight's, so we'll read the baseclass
820 // then subclass, same order as flattenLight.
821 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
822 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
823 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
824 default:
825 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000826 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000827 return NULL;
828 }
829}
830///////////////////////////////////////////////////////////////////////////////
831
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000832SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000833 : INHERITED(input, cropRect),
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000834 fLight(light),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000835 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
836{
837 SkASSERT(fLight);
reed@google.com51f38662012-06-27 14:24:29 +0000838 // our caller knows that we take ownership of the light, so we don't
839 // need to call ref() here.
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000840}
841
842SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000843 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000844 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000845 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000846 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000847 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848}
849
850SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000851 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000852 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000853 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000854 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000855 input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000856}
857
858SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000859 const SkPoint3& location, const SkPoint3& target,
860 SkScalar specularExponent, SkScalar cutoffAngle,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000861 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000862 SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000863 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000864 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
865 cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000866 surfaceScale, kd, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867}
868
869SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000870 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000871 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000872 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000873 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000874 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000875}
876
877SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000878 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000879 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000880 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco@chromium.org254eae22012-10-05 17:38:00 +0000881 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000882 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000883}
884
885SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000886 const SkPoint3& location, const SkPoint3& target,
887 SkScalar specularExponent, SkScalar cutoffAngle,
888 SkColor lightColor, SkScalar surfaceScale,
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000889 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
tomhudson@google.com300f5622012-07-20 14:15:22 +0000890 return SkNEW_ARGS(SkSpecularLightingImageFilter,
891 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000892 surfaceScale, ks, shininess, input, cropRect));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000893}
894
895SkLightingImageFilter::~SkLightingImageFilter() {
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000896 SkSafeUnref(fLight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000897}
898
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000899SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000900 : INHERITED(1, buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000901 fLight = SkLight::UnflattenLight(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902 fSurfaceScale = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000903 buffer.validate(SkScalarIsFinite(fSurfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904}
905
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000906void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000907 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000908 fLight->flattenLight(buffer);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000909 buffer.writeScalar(fSurfaceScale);
910}
911
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000912///////////////////////////////////////////////////////////////////////////////
913
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000914SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000915 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000916 // According to the spec, kd can be any non-negative number :
917 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
918 fKD(kd < 0 ? 0 : kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000919{
920}
921
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000922SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 : INHERITED(buffer)
924{
925 fKD = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000926 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000927}
928
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000929void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000930 this->INHERITED::flatten(buffer);
931 buffer.writeScalar(fKD);
932}
933
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000934bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
935 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000936 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000937 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000938 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000939 SkImageFilter* input = getInput(0);
940 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000941 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000942 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000943 return false;
944 }
945
commit-bot@chromium.orge24ad232014-02-16 22:03:38 +0000946 if (src.colorType() != kPMColor_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000947 return false;
948 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000949 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000950 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000951 return false;
952 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000953
954 if (bounds.width() < 2 || bounds.height() < 2) {
955 return false;
956 }
957
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000958 SkAutoLockPixels alp(src);
959 if (!src.getPixels()) {
960 return false;
961 }
962
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000963 dst->setConfig(src.config(), bounds.width(), bounds.height());
reed@google.com9ebcac52014-01-24 18:53:42 +0000964 if (!dst->allocPixels()) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000965 return false;
966 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000967
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000968 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000969
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000970 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000971 offset->fX = bounds.left();
972 offset->fY = bounds.top();
973 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000974 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000975 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000976 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000977 break;
978 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000979 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980 break;
981 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000982 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000983 break;
984 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000985
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000986 return true;
987}
988
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000989#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000990bool SkDiffuseLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +0000991 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000992 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000993 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000994 }
995 return true;
996}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000997#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000998
999///////////////////////////////////////////////////////////////////////////////
1000
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +00001001SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001002 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001003 // According to the spec, ks can be any non-negative number :
1004 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
1005 fKS(ks < 0 ? 0 : ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001006 fShininess(shininess)
1007{
1008}
1009
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001010SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001011 : INHERITED(buffer)
1012{
1013 fKS = buffer.readScalar();
1014 fShininess = buffer.readScalar();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001015 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001016 SkScalarIsFinite(fShininess));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001017}
1018
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001019void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001020 this->INHERITED::flatten(buffer);
1021 buffer.writeScalar(fKS);
1022 buffer.writeScalar(fShininess);
1023}
1024
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001025bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1026 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001027 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001028 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001029 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001030 SkImageFilter* input = getInput(0);
1031 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001032 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001033 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001034 return false;
1035 }
1036
commit-bot@chromium.orge24ad232014-02-16 22:03:38 +00001037 if (src.colorType() != kPMColor_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001038 return false;
1039 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001040
1041 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001042 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001043 return false;
1044 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001045
1046 if (bounds.width() < 2 || bounds.height() < 2) {
1047 return false;
1048 }
1049
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001050 SkAutoLockPixels alp(src);
1051 if (!src.getPixels()) {
1052 return false;
1053 }
1054
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001055 dst->setConfig(src.config(), bounds.width(), bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001056 dst->allocPixels();
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001057 if (!dst->getPixels()) {
1058 return false;
1059 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001060
1061 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001062 offset->fX = bounds.left();
1063 offset->fY = bounds.top();
1064 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001065 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001066 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001067 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001068 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001069 break;
1070 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001071 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001072 break;
1073 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001074 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001075 break;
1076 }
1077 return true;
1078}
1079
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001080#if SK_SUPPORT_GPU
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +00001081bool SkSpecularLightingImageFilter::asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkMatrix& matrix, const SkIRect&) const {
bsalomon@google.com021fc732012-10-25 12:47:42 +00001082 if (effect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001083 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001084 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001085 }
1086 return true;
1087}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001088#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001089
1090///////////////////////////////////////////////////////////////////////////////
1091
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001092#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001093
1094namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001095SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001096 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1097 SkScalarToFloat(random->nextSScalar1()),
1098 SkScalarToFloat(random->nextSScalar1()));
1099}
1100
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001101SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001102 int type = random->nextULessThan(3);
1103 switch (type) {
1104 case 0: {
1105 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1106 }
1107 case 1: {
1108 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1109 }
1110 case 2: {
1111 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1112 random_point3(random),
1113 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001114 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001115 random->nextU()));
1116 }
1117 default:
1118 GrCrash();
1119 return NULL;
1120 }
1121}
1122
1123}
1124
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001125class GrGLLightingEffect : public GrGLEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001126public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001127 GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001128 const GrDrawEffect& effect);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001129 virtual ~GrGLLightingEffect();
1130
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001131 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001132 const GrDrawEffect&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001133 EffectKey,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001134 const char* outputColor,
1135 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001136 const TransformedCoordsArray&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001137 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001138
bsalomon@google.comc7818882013-03-20 19:19:53 +00001139 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001140
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001141 /**
1142 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1143 */
bsalomon@google.comc7818882013-03-20 19:19:53 +00001144 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001145
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001146protected:
1147 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1148
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001149private:
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001150 typedef GrGLEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001151
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001152 UniformHandle fImageIncrementUni;
1153 UniformHandle fSurfaceScaleUni;
1154 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001155};
1156
1157///////////////////////////////////////////////////////////////////////////////
1158
1159class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1160public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001161 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001162 const GrDrawEffect& drawEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001163 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001164 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001165
1166private:
1167 typedef GrGLLightingEffect INHERITED;
1168
bsalomon@google.com032b2212012-07-16 13:36:18 +00001169 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001170};
1171
1172///////////////////////////////////////////////////////////////////////////////
1173
1174class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1175public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001176 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001177 const GrDrawEffect& effect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001178 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
bsalomon@google.comc7818882013-03-20 19:19:53 +00001179 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001180
1181private:
1182 typedef GrGLLightingEffect INHERITED;
1183
bsalomon@google.com032b2212012-07-16 13:36:18 +00001184 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001185 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001186};
1187
1188///////////////////////////////////////////////////////////////////////////////
1189
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001190GrLightingEffect::GrLightingEffect(GrTexture* texture,
1191 const SkLight* light,
1192 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001193 const SkMatrix& matrix)
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001194 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001195 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001196 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001197 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001198 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001199 if (light->requiresFragmentPosition()) {
1200 this->setWillReadFragmentPosition();
1201 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001202}
1203
1204GrLightingEffect::~GrLightingEffect() {
1205 fLight->unref();
1206}
1207
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001208bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001209 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001210 return this->texture(0) == s.texture(0) &&
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001211 fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001212 fSurfaceScale == s.fSurfaceScale;
1213}
1214
1215///////////////////////////////////////////////////////////////////////////////
1216
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001217GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1218 const SkLight* light,
1219 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001220 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001221 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001222 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001223}
1224
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001225const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1226 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001227}
1228
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001229bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001230 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001231 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001232 this->kd() == s.kd();
1233}
1234
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001235GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001236
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001237GrEffectRef* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001238 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001239 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001240 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001241 SkScalar surfaceScale = random->nextSScalar1();
1242 SkScalar kd = random->nextUScalar1();
1243 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001244 SkMatrix matrix;
1245 for (int i = 0; i < 9; i++) {
1246 matrix[i] = random->nextUScalar1();
1247 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001248 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001249 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001250}
1251
1252
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001253///////////////////////////////////////////////////////////////////////////////
1254
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001255GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001256 const GrDrawEffect& drawEffect)
bsalomon@google.com77af6802013-10-02 13:04:56 +00001257 : INHERITED(factory) {
bsalomon@google.comc7818882013-03-20 19:19:53 +00001258 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001259 fLight = m.light()->createGLLight();
1260}
1261
1262GrGLLightingEffect::~GrGLLightingEffect() {
1263 delete fLight;
1264}
1265
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001266void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001267 const GrDrawEffect&,
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001268 EffectKey key,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001269 const char* outputColor,
1270 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001271 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001272 const TextureSamplerArray& samplers) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001273 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001274
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001275 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001276 kVec2f_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001277 "ImageIncrement");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001278 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com032b2212012-07-16 13:36:18 +00001279 kFloat_GrSLType,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001280 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001281 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001282 SkString lightFunc;
1283 this->emitLightFunc(builder, &lightFunc);
1284 static const GrGLShaderVar gSobelArgs[] = {
1285 GrGLShaderVar("a", kFloat_GrSLType),
1286 GrGLShaderVar("b", kFloat_GrSLType),
1287 GrGLShaderVar("c", kFloat_GrSLType),
1288 GrGLShaderVar("d", kFloat_GrSLType),
1289 GrGLShaderVar("e", kFloat_GrSLType),
1290 GrGLShaderVar("f", kFloat_GrSLType),
1291 GrGLShaderVar("scale", kFloat_GrSLType),
1292 };
1293 SkString sobelFuncName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001294 builder->fsEmitFunction(kFloat_GrSLType,
1295 "sobel",
1296 SK_ARRAY_COUNT(gSobelArgs),
1297 gSobelArgs,
1298 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1299 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001300 static const GrGLShaderVar gPointToNormalArgs[] = {
1301 GrGLShaderVar("x", kFloat_GrSLType),
1302 GrGLShaderVar("y", kFloat_GrSLType),
1303 GrGLShaderVar("scale", kFloat_GrSLType),
1304 };
1305 SkString pointToNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001306 builder->fsEmitFunction(kVec3f_GrSLType,
1307 "pointToNormal",
1308 SK_ARRAY_COUNT(gPointToNormalArgs),
1309 gPointToNormalArgs,
1310 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1311 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001312
1313 static const GrGLShaderVar gInteriorNormalArgs[] = {
1314 GrGLShaderVar("m", kFloat_GrSLType, 9),
1315 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1316 };
1317 SkString interiorNormalBody;
1318 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1319 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1320 "\t surfaceScale);\n",
1321 pointToNormalName.c_str(),
1322 sobelFuncName.c_str(),
1323 sobelFuncName.c_str());
1324 SkString interiorNormalName;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001325 builder->fsEmitFunction(kVec3f_GrSLType,
1326 "interiorNormal",
1327 SK_ARRAY_COUNT(gInteriorNormalArgs),
1328 gInteriorNormalArgs,
1329 interiorNormalBody.c_str(),
1330 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001331
bsalomon@google.com77af6802013-10-02 13:04:56 +00001332 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001333 builder->fsCodeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001334
1335 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1336 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1337
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001338 int index = 0;
1339 for (int dy = -1; dy <= 1; dy++) {
1340 for (int dx = -1; dx <= 1; dx++) {
1341 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001342 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001343 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001344 builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001345 builder->fsCodeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001346 }
1347 }
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001348 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001349 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001350 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001351 fLight->emitSurfaceToLight(builder, arg.c_str());
1352 builder->fsCodeAppend(";\n");
1353 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1354 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001355 fLight->emitLightColor(builder, "surfaceToLight");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001356 builder->fsCodeAppend(");\n");
1357 SkString modulate;
1358 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1359 builder->fsCodeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001360}
1361
bsalomon@google.comc7818882013-03-20 19:19:53 +00001362GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +00001363 const GrGLCaps& caps) {
bsalomon@google.com77af6802013-10-02 13:04:56 +00001364 return drawEffect.castEffect<GrLightingEffect>().light()->type();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001365}
1366
bsalomon@google.comc7818882013-03-20 19:19:53 +00001367void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
1368 const GrDrawEffect& drawEffect) {
1369 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1370 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001371 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001372 uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
bsalomon@google.comc7818882013-03-20 19:19:53 +00001373 uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001374 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1375 fLight->setData(uman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001376}
1377
1378///////////////////////////////////////////////////////////////////////////////
1379
1380///////////////////////////////////////////////////////////////////////////////
1381
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001382GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001383 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001384 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001385}
1386
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001387void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001388 const char* kd;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001389 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001390 kFloat_GrSLType,
1391 "KD",
1392 &kd);
1393
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001394 static const GrGLShaderVar gLightArgs[] = {
1395 GrGLShaderVar("normal", kVec3f_GrSLType),
1396 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1397 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1398 };
1399 SkString lightBody;
1400 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1401 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001402 builder->fsEmitFunction(kVec4f_GrSLType,
1403 "light",
1404 SK_ARRAY_COUNT(gLightArgs),
1405 gLightArgs,
1406 lightBody.c_str(),
1407 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001408}
1409
bsalomon@google.com28a15fb2012-10-26 17:53:18 +00001410void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001411 const GrDrawEffect& drawEffect) {
1412 INHERITED::setData(uman, drawEffect);
1413 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1414 uman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001415}
1416
1417///////////////////////////////////////////////////////////////////////////////
1418
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001419GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1420 const SkLight* light,
1421 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001422 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001423 SkScalar ks,
1424 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001425 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001426 fKS(ks),
1427 fShininess(shininess) {
1428}
1429
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001430const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1431 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001432}
1433
bsalomon@google.com8a252f72013-01-22 20:35:13 +00001434bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +00001435 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001436 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001437 this->ks() == s.ks() &&
1438 this->shininess() == s.shininess();
1439}
1440
bsalomon@google.comf271cc72012-10-24 19:35:13 +00001441GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001442
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001443GrEffectRef* GrSpecularLightingEffect::TestCreate(SkRandom* random,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001444 GrContext* context,
bsalomon@google.comc26d94f2013-03-25 18:19:00 +00001445 const GrDrawTargetCaps&,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001446 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001447 SkScalar surfaceScale = random->nextSScalar1();
1448 SkScalar ks = random->nextUScalar1();
1449 SkScalar shininess = random->nextUScalar1();
1450 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001451 SkMatrix matrix;
1452 for (int i = 0; i < 9; i++) {
1453 matrix[i] = random->nextUScalar1();
1454 }
bsalomon@google.com0ac6af42013-01-16 15:16:18 +00001455 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001456 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001457}
1458
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001459///////////////////////////////////////////////////////////////////////////////
1460
bsalomon@google.com396e61f2012-10-25 19:00:29 +00001461GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001462 const GrDrawEffect& drawEffect)
commit-bot@chromium.org7425c122013-08-14 18:14:19 +00001463 : INHERITED(factory, drawEffect) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001464}
1465
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001466void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001467 const char* ks;
1468 const char* shininess;
1469
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001470 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001471 kFloat_GrSLType, "KS", &ks);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001472 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001473 kFloat_GrSLType, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001474
1475 static const GrGLShaderVar gLightArgs[] = {
1476 GrGLShaderVar("normal", kVec3f_GrSLType),
1477 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1478 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1479 };
1480 SkString lightBody;
1481 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1482 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001483 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1484 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001485 builder->fsEmitFunction(kVec4f_GrSLType,
1486 "light",
1487 SK_ARRAY_COUNT(gLightArgs),
1488 gLightArgs,
1489 lightBody.c_str(),
1490 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001491}
1492
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001493void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
bsalomon@google.comc7818882013-03-20 19:19:53 +00001494 const GrDrawEffect& drawEffect) {
1495 INHERITED::setData(uman, drawEffect);
1496 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1497 uman.set1f(fKSUni, spec.ks());
1498 uman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001499}
1500
1501///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001502void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001503 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001504 kVec3f_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001505}
1506
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001507void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1508 const char *surfaceToLight) {
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001509 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001510}
1511
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001512void GrGLLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001513 const SkLight* light) const {
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001514 setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001515}
1516
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001517///////////////////////////////////////////////////////////////////////////////
1518
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001519void GrGLDistantLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001520 const SkLight* light) const {
1521 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001522 SkASSERT(light->type() == SkLight::kDistant_LightType);
1523 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001524 setUniformNormal3(uman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525}
1526
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001527void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001528 const char* dir;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001529 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001530 "LightDirection", &dir);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001531 builder->fsCodeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001532}
1533
1534///////////////////////////////////////////////////////////////////////////////
1535
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001536void GrGLPointLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001537 const SkLight* light) const {
1538 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001539 SkASSERT(light->type() == SkLight::kPoint_LightType);
1540 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001541 setUniformPoint3(uman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001542}
1543
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001544void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001545 const char* loc;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001546 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001547 "LightLocation", &loc);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001548 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001549}
1550
1551///////////////////////////////////////////////////////////////////////////////
1552
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001553void GrGLSpotLight::setData(const GrGLUniformManager& uman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001554 const SkLight* light) const {
1555 INHERITED::setData(uman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001556 SkASSERT(light->type() == SkLight::kSpot_LightType);
1557 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001558 setUniformPoint3(uman, fLocationUni, spotLight->location());
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +00001559 uman.set1f(fExponentUni, spotLight->specularExponent());
1560 uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1561 uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1562 uman.set1f(fConeScaleUni, spotLight->coneScale());
1563 setUniformNormal3(uman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001564}
1565
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001566void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001567 const char* location;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001568 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001569 kVec3f_GrSLType, "LightLocation", &location);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001570 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1571 location, builder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001572}
1573
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001574void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1575 const char *surfaceToLight) {
1576
1577 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1578
1579 const char* exponent;
1580 const char* cosInner;
1581 const char* cosOuter;
1582 const char* coneScale;
1583 const char* s;
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001584 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001585 kFloat_GrSLType, "Exponent", &exponent);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001586 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001587 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001588 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001589 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001590 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001591 kFloat_GrSLType, "ConeScale", &coneScale);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001592 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001593 kVec3f_GrSLType, "S", &s);
1594
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001595 static const GrGLShaderVar gLightColorArgs[] = {
1596 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1597 };
1598 SkString lightColorBody;
1599 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1600 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1601 lightColorBody.appendf("\t\treturn vec3(0);\n");
1602 lightColorBody.appendf("\t}\n");
1603 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1604 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1605 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1606 color, cosOuter, coneScale);
1607 lightColorBody.appendf("\t}\n");
1608 lightColorBody.appendf("\treturn %s;\n", color);
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001609 builder->fsEmitFunction(kVec3f_GrSLType,
1610 "lightColor",
1611 SK_ARRAY_COUNT(gLightColorArgs),
1612 gLightColorArgs,
1613 lightColorBody.c_str(),
1614 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001615
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001616 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001617}
1618
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001619#endif
1620
djsollen@google.com08337772012-06-26 14:33:13 +00001621SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1622 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1623 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001624SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END