blob: 240a6939ae8f5c92817ef679cb3ffff4e70d7ec6 [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"
robertphillips3d32d762015-07-13 13:16:44 -070011#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000013#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070014#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000015
16#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070017#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070018#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080019#include "GrFragmentProcessor.h"
20#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070021#include "GrPaint.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000022#include "effects/GrSingleTextureEffect.h"
wangyix6af0c932015-07-22 10:21:17 -070023#include "gl/GrGLFragmentProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070024#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000025
26class GrGLDiffuseLightingEffect;
27class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000028
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000029// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070030typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000031#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000032
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000033namespace {
34
reed80ea19c2015-05-12 10:37:34 -070035const SkScalar gOneThird = SkIntToScalar(1) / 3;
36const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000037const SkScalar gOneHalf = 0.5f;
38const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000039
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000040#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070041void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
42 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000043 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070044 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000045}
46
joshualittb0a8a372014-09-23 09:50:21 -070047void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
48 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070049 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000050}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000051#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000052
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000053// Shift matrix components to the left, as we advance pixels to the right.
54inline void shiftMatrixLeft(int m[9]) {
55 m[0] = m[1];
56 m[3] = m[4];
57 m[6] = m[7];
58 m[1] = m[2];
59 m[4] = m[5];
60 m[7] = m[8];
61}
62
jvanverth992c7612015-07-17 07:22:30 -070063static inline void fast_normalize(SkPoint3* vector) {
64 // add a tiny bit so we don't have to worry about divide-by-zero
65 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
66 SkScalar scale = sk_float_rsqrt(magSq);
67 vector->fX *= scale;
68 vector->fY *= scale;
69 vector->fZ *= scale;
70}
71
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000072class DiffuseLightingType {
73public:
74 DiffuseLightingType(SkScalar kd)
75 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070076 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
77 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000078 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
79 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070080 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000081 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000082 SkClampMax(SkScalarRoundToInt(color.fX), 255),
83 SkClampMax(SkScalarRoundToInt(color.fY), 255),
84 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 }
86private:
87 SkScalar fKD;
88};
89
robertphillips3d32d762015-07-13 13:16:44 -070090static SkScalar max_component(const SkPoint3& p) {
91 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
92}
93
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000094class SpecularLightingType {
95public:
96 SpecularLightingType(SkScalar ks, SkScalar shininess)
97 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070098 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
99 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000100 SkPoint3 halfDir(surfaceTolight);
101 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700102 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000103 SkScalar colorScale = SkScalarMul(fKS,
104 SkScalarPow(normal.dot(halfDir), fShininess));
105 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700106 SkPoint3 color = lightColor.makeScale(colorScale);
107 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000108 SkClampMax(SkScalarRoundToInt(color.fX), 255),
109 SkClampMax(SkScalarRoundToInt(color.fY), 255),
110 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000111 }
112private:
113 SkScalar fKS;
114 SkScalar fShininess;
115};
116
117inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
118 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
119}
120
121inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700122 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
123 SkScalarMul(-y, surfaceScale),
124 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700125 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000126 return vector;
127}
128
129inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
130 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
131 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
132 surfaceScale);
133}
134
135inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
137 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
138 surfaceScale);
139}
140
141inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
142 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
143 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
144 surfaceScale);
145}
146
147inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
148 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
149 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
150 surfaceScale);
151}
152
153
154inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
155 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
156 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
157 surfaceScale);
158}
159
160inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
161 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
162 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
163 surfaceScale);
164}
165
166inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
167 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
168 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
169 surfaceScale);
170}
171
172inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
173 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
174 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
175 surfaceScale);
176}
177
178inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
179 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
180 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
181 surfaceScale);
182}
183
robertphillips2f0dbc72015-08-20 05:15:06 -0700184template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType,
185 const SkImageFilterLight* light,
186 const SkBitmap& src,
187 SkBitmap* dst,
188 SkScalar surfaceScale,
189 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000190 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000192 int left = bounds.left(), right = bounds.right();
193 int bottom = bounds.bottom();
194 int y = bounds.top();
195 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000196 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000197 int x = left;
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[4] = SkGetPackedA32(*row1++);
202 m[5] = SkGetPackedA32(*row1++);
203 m[7] = SkGetPackedA32(*row2++);
204 m[8] = SkGetPackedA32(*row2++);
205 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700206 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
207 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000208 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000209 {
210 shiftMatrixLeft(m);
211 m[5] = SkGetPackedA32(*row1++);
212 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000213 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700214 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
215 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 }
217 shiftMatrixLeft(m);
218 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700219 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
220 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 }
222
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000223 for (++y; y < bottom - 1; ++y) {
224 int x = left;
225 const SkPMColor* row0 = src.getAddr32(x, y - 1);
226 const SkPMColor* row1 = src.getAddr32(x, y);
227 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000228 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000229 m[1] = SkGetPackedA32(*row0++);
230 m[2] = SkGetPackedA32(*row0++);
231 m[4] = SkGetPackedA32(*row1++);
232 m[5] = SkGetPackedA32(*row1++);
233 m[7] = SkGetPackedA32(*row2++);
234 m[8] = SkGetPackedA32(*row2++);
235 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700236 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
237 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000238 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 shiftMatrixLeft(m);
240 m[2] = SkGetPackedA32(*row0++);
241 m[5] = SkGetPackedA32(*row1++);
242 m[8] = SkGetPackedA32(*row2++);
243 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700244 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
245 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000246 }
247 shiftMatrixLeft(m);
248 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700249 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
250 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000251 }
252
253 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000254 int x = left;
255 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
256 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000257 int m[9];
258 m[1] = SkGetPackedA32(*row0++);
259 m[2] = SkGetPackedA32(*row0++);
260 m[4] = SkGetPackedA32(*row1++);
261 m[5] = SkGetPackedA32(*row1++);
262 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700263 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
264 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000265 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000266 {
267 shiftMatrixLeft(m);
268 m[2] = SkGetPackedA32(*row0++);
269 m[5] = SkGetPackedA32(*row1++);
270 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700271 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
272 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000273 }
274 shiftMatrixLeft(m);
275 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700276 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
277 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000278 }
279}
280
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000281SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000282 SkPoint3 point;
283 point.fX = buffer.readScalar();
284 point.fY = buffer.readScalar();
285 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000286 buffer.validate(SkScalarIsFinite(point.fX) &&
287 SkScalarIsFinite(point.fY) &&
288 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289 return point;
290};
291
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000292void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000293 buffer.writeScalar(point.fX);
294 buffer.writeScalar(point.fY);
295 buffer.writeScalar(point.fZ);
296};
297
senorblancod0d37ca2015-04-02 04:54:56 -0700298enum BoundaryMode {
299 kTopLeft_BoundaryMode,
300 kTop_BoundaryMode,
301 kTopRight_BoundaryMode,
302 kLeft_BoundaryMode,
303 kInterior_BoundaryMode,
304 kRight_BoundaryMode,
305 kBottomLeft_BoundaryMode,
306 kBottom_BoundaryMode,
307 kBottomRight_BoundaryMode,
308
309 kBoundaryModeCount,
310};
311
312class SkLightingImageFilterInternal : public SkLightingImageFilter {
313protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700314 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700315 SkScalar surfaceScale,
316 SkImageFilter* input,
317 const CropRect* cropRect)
318 : INHERITED(light, surfaceScale, input, cropRect) {}
319
320#if SK_SUPPORT_GPU
321 bool canFilterImageGPU() const override { return true; }
322 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
323 SkBitmap* result, SkIPoint* offset) const override;
joshualitt5f10b5c2015-07-09 10:24:35 -0700324 virtual GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*,
325 GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700326 const SkMatrix&,
327 const SkIRect& bounds,
328 BoundaryMode boundaryMode) const = 0;
329#endif
330private:
331#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700332 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700333 GrTexture* src,
334 GrTexture* dst,
335 const SkMatrix& matrix,
336 const GrClip& clip,
337 const SkRect& dstRect,
338 BoundaryMode boundaryMode,
339 const SkIRect& bounds) const;
340#endif
341 typedef SkLightingImageFilter INHERITED;
342};
343
344#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700345void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700346 GrTexture* src,
347 GrTexture* dst,
348 const SkMatrix& matrix,
349 const GrClip& clip,
350 const SkRect& dstRect,
351 BoundaryMode boundaryMode,
352 const SkIRect& bounds) const {
353 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700354 GrPaint paint;
joshualitt5f10b5c2015-07-09 10:24:35 -0700355 GrFragmentProcessor* fp = this->getFragmentProcessor(paint.getProcessorDataManager(), src,
356 matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700357 paint.addColorFragmentProcessor(fp)->unref();
robertphillipsea461502015-05-26 11:38:03 -0700358 drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
359 dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700360}
361
362bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
363 const SkBitmap& src,
364 const Context& ctx,
365 SkBitmap* result,
366 SkIPoint* offset) const {
367 SkBitmap input = src;
368 SkIPoint srcOffset = SkIPoint::Make(0, 0);
369 if (this->getInput(0) &&
370 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
371 return false;
372 }
373 SkIRect bounds;
374 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
375 return false;
376 }
377 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
378 SkIntToScalar(bounds.height()));
379 GrTexture* srcTexture = input.getTexture();
380 GrContext* context = srcTexture->getContext();
381
382 GrSurfaceDesc desc;
383 desc.fFlags = kRenderTarget_GrSurfaceFlag,
384 desc.fWidth = bounds.width();
385 desc.fHeight = bounds.height();
386 desc.fConfig = kRGBA_8888_GrPixelConfig;
387
bsalomoneae62002015-07-31 13:59:30 -0700388 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700389 if (!dst) {
390 return false;
391 }
392
393 // setup new clip
394 GrClip clip(dstRect);
395
396 offset->fX = bounds.left();
397 offset->fY = bounds.top();
398 SkMatrix matrix(ctx.ctm());
399 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
400 bounds.offset(-srcOffset);
401 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
402 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
403 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
404 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
405 SkRect interior = dstRect.makeInset(1, 1);
406 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
407 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
408 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
409 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700410
411 GrDrawContext* drawContext = context->drawContext();
412 if (!drawContext) {
413 return false;
414 }
415
416 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700417 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700418 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
419 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700420 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700421 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
422 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700423 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700424 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
425 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700426 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700427 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
428 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
429 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700430 WrapTexture(dst, bounds.width(), bounds.height(), result);
431 return true;
432}
433#endif
434
435class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000436public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700437 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
438 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700439 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700440
robertphillipsf3f5bad2014-12-19 13:49:15 -0800441 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000442 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000443 SkScalar kd() const { return fKD; }
444
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000445protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700446 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700447 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700448 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700449 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
450 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000451#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700452 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700453 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000454#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000455
456private:
reed9fa60da2014-08-21 07:59:51 -0700457 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700458 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000459 SkScalar fKD;
460};
461
senorblancod0d37ca2015-04-02 04:54:56 -0700462class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000463public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700464 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700465 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700466
robertphillipsf3f5bad2014-12-19 13:49:15 -0800467 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000468 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
469
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000470 SkScalar ks() const { return fKS; }
471 SkScalar shininess() const { return fShininess; }
472
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000473protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700474 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700475 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700476 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700477 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
478 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000479#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700480 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700481 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000482#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483
484private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485 SkScalar fKS;
486 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700487 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700488 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000489};
490
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000491#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000493class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700495 GrLightingEffect(GrProcessorDataManager*, GrTexture* texture, const SkImageFilterLight* light,
joshualitt5f10b5c2015-07-09 10:24:35 -0700496 SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000497 virtual ~GrLightingEffect();
498
robertphillips2f0dbc72015-08-20 05:15:06 -0700499 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000500 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000501 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700502 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000503
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000504protected:
mtklein36352bf2015-03-25 18:17:31 -0700505 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000506
mtklein36352bf2015-03-25 18:17:31 -0700507 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700508 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800509 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700510 }
511
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000512private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700513 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000514 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000515 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700516 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700517
518 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000519};
520
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000521class GrDiffuseLightingEffect : public GrLightingEffect {
522public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700523 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
524 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700525 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700526 SkScalar surfaceScale,
527 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700528 SkScalar kd,
529 BoundaryMode boundaryMode) {
halcanary385fe4d2015-08-26 13:07:48 -0700530 return new GrDiffuseLightingEffect(procDataManager, texture, light, surfaceScale, matrix,
531 kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000532 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000533
mtklein36352bf2015-03-25 18:17:31 -0700534 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000535
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000537
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000538private:
wangyixb1daa862015-08-18 11:29:31 -0700539 GrGLFragmentProcessor* onCreateGLInstance() const override;
540
wangyix4b3050b2015-08-04 07:59:37 -0700541 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
542
mtklein36352bf2015-03-25 18:17:31 -0700543 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000544
joshualitt5f10b5c2015-07-09 10:24:35 -0700545 GrDiffuseLightingEffect(GrProcessorDataManager*,
546 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700547 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000548 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000549 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700550 SkScalar kd,
551 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000552
joshualittb0a8a372014-09-23 09:50:21 -0700553 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000554 typedef GrLightingEffect INHERITED;
555 SkScalar fKD;
556};
557
558class GrSpecularLightingEffect : public GrLightingEffect {
559public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700560 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
561 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700562 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700563 SkScalar surfaceScale,
564 const SkMatrix& matrix,
565 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700566 SkScalar shininess,
567 BoundaryMode boundaryMode) {
halcanary385fe4d2015-08-26 13:07:48 -0700568 return new GrSpecularLightingEffect(procDataManager, texture, light, surfaceScale, matrix,
569 ks, shininess, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000570 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000571
mtklein36352bf2015-03-25 18:17:31 -0700572 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000573
wangyixb1daa862015-08-18 11:29:31 -0700574 GrGLFragmentProcessor* onCreateGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800575
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000576 SkScalar ks() const { return fKS; }
577 SkScalar shininess() const { return fShininess; }
578
579private:
wangyix4b3050b2015-08-04 07:59:37 -0700580 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
581
mtklein36352bf2015-03-25 18:17:31 -0700582 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000583
joshualitt5f10b5c2015-07-09 10:24:35 -0700584 GrSpecularLightingEffect(GrProcessorDataManager*,
585 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700586 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000587 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000588 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000589 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700590 SkScalar shininess,
591 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000592
joshualittb0a8a372014-09-23 09:50:21 -0700593 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000594 typedef GrLightingEffect INHERITED;
595 SkScalar fKS;
596 SkScalar fShininess;
597};
598
599///////////////////////////////////////////////////////////////////////////////
600
601class GrGLLight {
602public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000603 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000604
605 /**
606 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
607 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
608 */
joshualitt15988992014-10-09 15:04:05 -0700609 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000610
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000611 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000612 * These two functions are called from GrGLLightingEffect's emitCode() function.
613 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
614 * the light. The expression will be used in the FS. emitLightColor writes an expression into
615 * the FS that is the color of the light. Either function may add functions and/or uniforms to
616 * the FS. The default of emitLightColor appends the name of the constant light color uniform
617 * and so this function only needs to be overridden if the light color varies spatially.
618 */
joshualitt15988992014-10-09 15:04:05 -0700619 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
620 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000621
622 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
623 // INHERITED::setData().
robertphillips2f0dbc72015-08-20 05:15:06 -0700624 virtual void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000626protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000627 /**
628 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
629 * function.
630 */
631 UniformHandle lightColorUni() const { return fColorUni; }
632
633private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000634 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000635
636 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000637};
638
639///////////////////////////////////////////////////////////////////////////////
640
641class GrGLDistantLight : public GrGLLight {
642public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000643 virtual ~GrGLDistantLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700644 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700645 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000646
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000647private:
648 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000649 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000650};
651
652///////////////////////////////////////////////////////////////////////////////
653
654class GrGLPointLight : public GrGLLight {
655public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000656 virtual ~GrGLPointLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700657 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700658 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000659
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000660private:
661 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000662 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000663};
664
665///////////////////////////////////////////////////////////////////////////////
666
667class GrGLSpotLight : public GrGLLight {
668public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000669 virtual ~GrGLSpotLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700670 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700671 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
672 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000673
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000674private:
675 typedef GrGLLight INHERITED;
676
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000677 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000678 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000679 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000680 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000681 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000682 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000683 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000684};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000685#else
686
687class GrGLLight;
688
689#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000690
691};
692
693///////////////////////////////////////////////////////////////////////////////
694
robertphillips2f0dbc72015-08-20 05:15:06 -0700695class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696public:
mtklein2766c002015-06-26 11:45:03 -0700697
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000698
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000699 enum LightType {
700 kDistant_LightType,
701 kPoint_LightType,
702 kSpot_LightType,
703 };
704 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000705 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000706 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700707 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000708 return fColor == other.fColor;
709 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000710 // Called to know whether the generated GrGLLight will require access to the fragment position.
711 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700712 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000713
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000714 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000715 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700716 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000717
djsollen@google.com08337772012-06-26 14:33:13 +0000718protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700719 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700720 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
721 SkIntToScalar(SkColorGetG(color)),
722 SkIntToScalar(SkColorGetB(color)));
723 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700724 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000725 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700726 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000727 fColor = readPoint3(buffer);
728 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000729
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000730 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000731
djsollen@google.com08337772012-06-26 14:33:13 +0000732
733private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000734 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000735 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000736};
737
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000738///////////////////////////////////////////////////////////////////////////////
739
robertphillips2f0dbc72015-08-20 05:15:06 -0700740class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000741public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000742 SkDistantLight(const SkPoint3& direction, SkColor color)
743 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000744 }
djsollen@google.com08337772012-06-26 14:33:13 +0000745
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000746 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
747 return fDirection;
748 };
robertphillips3d32d762015-07-13 13:16:44 -0700749 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700750 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000751 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700752 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000753#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700754 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000755#else
756 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700757 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000758#endif
759 }
mtklein36352bf2015-03-25 18:17:31 -0700760 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000761
robertphillips2f0dbc72015-08-20 05:15:06 -0700762 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000763 if (other.type() != kDistant_LightType) {
764 return false;
765 }
766
767 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
768 return INHERITED::isEqual(other) &&
769 fDirection == o.fDirection;
770 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000771
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000772 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000773 fDirection = readPoint3(buffer);
774 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000775
djsollen@google.com08337772012-06-26 14:33:13 +0000776protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000777 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
778 : INHERITED(color), fDirection(direction) {
779 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700780 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000781 return new SkDistantLight(direction(), color());
782 }
mtklein36352bf2015-03-25 18:17:31 -0700783 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000784 writePoint3(fDirection, buffer);
785 }
786
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000787private:
788 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700789
790 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000791};
792
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000793///////////////////////////////////////////////////////////////////////////////
794
robertphillips2f0dbc72015-08-20 05:15:06 -0700795class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000796public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000797 SkPointLight(const SkPoint3& location, SkColor color)
798 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000799
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000800 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700801 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
802 fLocation.fY - SkIntToScalar(y),
803 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
804 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700805 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000806 return direction;
807 };
robertphillips3d32d762015-07-13 13:16:44 -0700808 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700809 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000810 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700811 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000812#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700813 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000814#else
815 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700816 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000817#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000818 }
mtklein36352bf2015-03-25 18:17:31 -0700819 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700820 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000821 if (other.type() != kPoint_LightType) {
822 return false;
823 }
824 const SkPointLight& o = static_cast<const SkPointLight&>(other);
825 return INHERITED::isEqual(other) &&
826 fLocation == o.fLocation;
827 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700828 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000829 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
830 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000831 // Use X scale and Y scale on Z and average the result
832 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
833 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700834 SkPoint3 location = SkPoint3::Make(location2.fX,
835 location2.fY,
836 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000837 return new SkPointLight(location, color());
838 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000839
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000840 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000841 fLocation = readPoint3(buffer);
842 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000843
844protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000845 SkPointLight(const SkPoint3& location, const SkPoint3& color)
846 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700847 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000848 writePoint3(fLocation, buffer);
849 }
850
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851private:
852 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700853
854 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000855};
856
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000857///////////////////////////////////////////////////////////////////////////////
858
robertphillips2f0dbc72015-08-20 05:15:06 -0700859class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000860public:
senorblancod0d37ca2015-04-02 04:54:56 -0700861 SkSpotLight(const SkPoint3& location,
862 const SkPoint3& target,
863 SkScalar specularExponent,
864 SkScalar cutoffAngle,
865 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000866 : INHERITED(color),
867 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000868 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000869 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000870 {
871 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700872 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000873 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000874 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000875 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
876 fConeScale = SkScalarInvert(antiAliasThreshold);
877 }
djsollen@google.com08337772012-06-26 14:33:13 +0000878
robertphillips2f0dbc72015-08-20 05:15:06 -0700879 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000880 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
881 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000882 // Use X scale and Y scale on Z and average the result
883 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
884 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700885 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
886 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000887 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
888 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000889 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
890 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700891 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
892 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000893 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700894 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700895 return new SkSpotLight(location,
896 target,
897 fSpecularExponent,
898 fCosOuterConeAngle,
899 fCosInnerConeAngle,
900 fConeScale,
901 s,
902 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000903 }
904
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000905 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700906 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
907 fLocation.fY - SkIntToScalar(y),
908 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
909 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700910 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 return direction;
912 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000913 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000914 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700915 SkScalar scale = 0;
916 if (cosAngle >= fCosOuterConeAngle) {
917 scale = SkScalarPow(cosAngle, fSpecularExponent);
918 if (cosAngle < fCosInnerConeAngle) {
919 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
920 scale *= fConeScale;
921 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000922 }
robertphillips3d32d762015-07-13 13:16:44 -0700923 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000924 }
mtklein36352bf2015-03-25 18:17:31 -0700925 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000926#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700927 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000928#else
929 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700930 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000931#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000932 }
mtklein36352bf2015-03-25 18:17:31 -0700933 bool requiresFragmentPosition() const override { return true; }
934 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000935 const SkPoint3& location() const { return fLocation; }
936 const SkPoint3& target() const { return fTarget; }
937 SkScalar specularExponent() const { return fSpecularExponent; }
938 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
939 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
940 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000941 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000942
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000943 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000944 fLocation = readPoint3(buffer);
945 fTarget = readPoint3(buffer);
946 fSpecularExponent = buffer.readScalar();
947 fCosOuterConeAngle = buffer.readScalar();
948 fCosInnerConeAngle = buffer.readScalar();
949 fConeScale = buffer.readScalar();
950 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000951 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
952 SkScalarIsFinite(fCosOuterConeAngle) &&
953 SkScalarIsFinite(fCosInnerConeAngle) &&
954 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000955 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000956protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700957 SkSpotLight(const SkPoint3& location,
958 const SkPoint3& target,
959 SkScalar specularExponent,
960 SkScalar cosOuterConeAngle,
961 SkScalar cosInnerConeAngle,
962 SkScalar coneScale,
963 const SkPoint3& s,
964 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000965 : INHERITED(color),
966 fLocation(location),
967 fTarget(target),
968 fSpecularExponent(specularExponent),
969 fCosOuterConeAngle(cosOuterConeAngle),
970 fCosInnerConeAngle(cosInnerConeAngle),
971 fConeScale(coneScale),
972 fS(s)
973 {
974 }
mtklein36352bf2015-03-25 18:17:31 -0700975 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000976 writePoint3(fLocation, buffer);
977 writePoint3(fTarget, buffer);
978 buffer.writeScalar(fSpecularExponent);
979 buffer.writeScalar(fCosOuterConeAngle);
980 buffer.writeScalar(fCosInnerConeAngle);
981 buffer.writeScalar(fConeScale);
982 writePoint3(fS, buffer);
983 }
984
robertphillips2f0dbc72015-08-20 05:15:06 -0700985 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000986 if (other.type() != kSpot_LightType) {
987 return false;
988 }
989
990 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
991 return INHERITED::isEqual(other) &&
992 fLocation == o.fLocation &&
993 fTarget == o.fTarget &&
994 fSpecularExponent == o.fSpecularExponent &&
995 fCosOuterConeAngle == o.fCosOuterConeAngle;
996 }
997
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000998private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000999 static const SkScalar kSpecularExponentMin;
1000 static const SkScalar kSpecularExponentMax;
1001
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001002 SkPoint3 fLocation;
1003 SkPoint3 fTarget;
1004 SkScalar fSpecularExponent;
1005 SkScalar fCosOuterConeAngle;
1006 SkScalar fCosInnerConeAngle;
1007 SkScalar fConeScale;
1008 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001009
1010 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001011};
1012
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001013// According to the spec, the specular term should be in the range [1, 128] :
1014// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001015const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1016const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001017
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001018///////////////////////////////////////////////////////////////////////////////
1019
robertphillips2f0dbc72015-08-20 05:15:06 -07001020void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001021 // Write type first, then baseclass, then subclass.
1022 buffer.writeInt(this->type());
1023 writePoint3(fColor, buffer);
1024 this->onFlattenLight(buffer);
1025}
1026
robertphillips2f0dbc72015-08-20 05:15:06 -07001027/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001028 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001029 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001030 switch (type) {
1031 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1032 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001033 case SkImageFilterLight::kDistant_LightType:
1034 return new SkDistantLight(buffer);
1035 case SkImageFilterLight::kPoint_LightType:
1036 return new SkPointLight(buffer);
1037 case SkImageFilterLight::kSpot_LightType:
1038 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001039 default:
1040 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001041 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001042 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001043 }
1044}
1045///////////////////////////////////////////////////////////////////////////////
1046
robertphillips2f0dbc72015-08-20 05:15:06 -07001047SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001048 SkImageFilter* input, const CropRect* cropRect)
1049 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001050 , fLight(SkRef(light))
1051 , fSurfaceScale(surfaceScale / 255)
1052{}
1053
1054SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1055 SkColor lightColor,
1056 SkScalar surfaceScale,
1057 SkScalar kd,
1058 SkImageFilter* input,
1059 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001060 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001061 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001062}
1063
reed9fa60da2014-08-21 07:59:51 -07001064SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1065 SkColor lightColor,
1066 SkScalar surfaceScale,
1067 SkScalar kd,
1068 SkImageFilter* input,
1069 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001070 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001071 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001072}
1073
reed9fa60da2014-08-21 07:59:51 -07001074SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1075 const SkPoint3& target,
1076 SkScalar specularExponent,
1077 SkScalar cutoffAngle,
1078 SkColor lightColor,
1079 SkScalar surfaceScale,
1080 SkScalar kd,
1081 SkImageFilter* input,
1082 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001083 SkAutoTUnref<SkImageFilterLight> light(
1084 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001085 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001086}
1087
reed9fa60da2014-08-21 07:59:51 -07001088SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1089 SkColor lightColor,
1090 SkScalar surfaceScale,
1091 SkScalar ks,
1092 SkScalar shine,
1093 SkImageFilter* input,
1094 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001095 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001096 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001097}
1098
reed9fa60da2014-08-21 07:59:51 -07001099SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1100 SkColor lightColor,
1101 SkScalar surfaceScale,
1102 SkScalar ks,
1103 SkScalar shine,
1104 SkImageFilter* input,
1105 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001106 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001107 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001108}
1109
reed9fa60da2014-08-21 07:59:51 -07001110SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1111 const SkPoint3& target,
1112 SkScalar specularExponent,
1113 SkScalar cutoffAngle,
1114 SkColor lightColor,
1115 SkScalar surfaceScale,
1116 SkScalar ks,
1117 SkScalar shine,
1118 SkImageFilter* input,
1119 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001120 SkAutoTUnref<SkImageFilterLight> light(
1121 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001122 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001123}
1124
reed9fa60da2014-08-21 07:59:51 -07001125SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001126
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001127void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001128 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001129 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001130 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001131}
1132
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001133///////////////////////////////////////////////////////////////////////////////
1134
robertphillips2f0dbc72015-08-20 05:15:06 -07001135SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1136 SkScalar surfaceScale,
1137 SkScalar kd,
1138 SkImageFilter* input,
1139 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001140 if (nullptr == light) {
1141 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001142 }
1143 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001144 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001145 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001146 // According to the spec, kd can be any non-negative number :
1147 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001148 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001149 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001150 }
halcanary385fe4d2015-08-26 13:07:48 -07001151 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001152}
1153
robertphillips2f0dbc72015-08-20 05:15:06 -07001154SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001155 SkScalar surfaceScale,
1156 SkScalar kd,
1157 SkImageFilter* input,
1158 const CropRect* cropRect)
1159 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001160 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001161{
1162}
1163
reed9fa60da2014-08-21 07:59:51 -07001164SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1165 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001166 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001167 SkScalar surfaceScale = buffer.readScalar();
1168 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001169 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001170}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001171
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001172void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001173 this->INHERITED::flatten(buffer);
1174 buffer.writeScalar(fKD);
1175}
1176
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001177bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1178 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001179 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001180 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001181 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001182 SkImageFilter* input = getInput(0);
1183 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001184 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001185 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001186 return false;
1187 }
1188
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001189 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001190 return false;
1191 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001192 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001193 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001194 return false;
1195 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001196
1197 if (bounds.width() < 2 || bounds.height() < 2) {
1198 return false;
1199 }
1200
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001201 SkAutoLockPixels alp(src);
1202 if (!src.getPixels()) {
1203 return false;
1204 }
1205
reed84825042014-09-02 12:50:45 -07001206 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001207 return false;
1208 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001209
senorblanco7b7ecfc2015-08-26 14:26:40 -07001210 SkMatrix matrix(ctx.ctm());
1211 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1212 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001213
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001214 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001215 offset->fX = bounds.left();
1216 offset->fY = bounds.top();
1217 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001218 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001219 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001220 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1221 transformedLight,
1222 src,
1223 dst,
1224 surfaceScale(),
1225 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001226 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001227 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001228 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1229 transformedLight,
1230 src,
1231 dst,
1232 surfaceScale(),
1233 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001234 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001235 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001236 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1237 transformedLight,
1238 src,
1239 dst,
1240 surfaceScale(),
1241 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001242 break;
1243 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001244
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001245 return true;
1246}
1247
robertphillipsf3f5bad2014-12-19 13:49:15 -08001248#ifndef SK_IGNORE_TO_STRING
1249void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1250 str->appendf("SkDiffuseLightingImageFilter: (");
1251 str->appendf("kD: %f\n", fKD);
1252 str->append(")");
1253}
1254#endif
1255
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001256#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001257GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001258 GrProcessorDataManager* procDataManager,
1259 GrTexture* texture,
1260 const SkMatrix& matrix,
1261 const SkIRect&,
1262 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001263) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001264 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1265 return GrDiffuseLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1266 this->kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001267}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001268#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001269
1270///////////////////////////////////////////////////////////////////////////////
1271
robertphillips2f0dbc72015-08-20 05:15:06 -07001272SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1273 SkScalar surfaceScale,
1274 SkScalar ks,
1275 SkScalar shininess,
1276 SkImageFilter* input,
1277 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001278 if (nullptr == light) {
1279 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001280 }
1281 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001282 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001283 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001284 // According to the spec, ks can be any non-negative number :
1285 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001286 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001287 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001288 }
halcanary385fe4d2015-08-26 13:07:48 -07001289 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001290}
1291
robertphillips2f0dbc72015-08-20 05:15:06 -07001292SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001293 SkScalar surfaceScale,
1294 SkScalar ks,
1295 SkScalar shininess,
1296 SkImageFilter* input,
1297 const CropRect* cropRect)
1298 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001299 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001300 fShininess(shininess)
1301{
1302}
1303
reed9fa60da2014-08-21 07:59:51 -07001304SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1305 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001306 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001307 SkScalar surfaceScale = buffer.readScalar();
1308 SkScalar ks = buffer.readScalar();
1309 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001310 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001311}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001312
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001313void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001314 this->INHERITED::flatten(buffer);
1315 buffer.writeScalar(fKS);
1316 buffer.writeScalar(fShininess);
1317}
1318
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001319bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1320 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001321 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001322 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001323 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001324 SkImageFilter* input = getInput(0);
1325 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001326 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001327 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001328 return false;
1329 }
1330
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001331 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001332 return false;
1333 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001334
1335 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001336 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001337 return false;
1338 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001339
1340 if (bounds.width() < 2 || bounds.height() < 2) {
1341 return false;
1342 }
1343
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001344 SkAutoLockPixels alp(src);
1345 if (!src.getPixels()) {
1346 return false;
1347 }
1348
reed84825042014-09-02 12:50:45 -07001349 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001350 return false;
1351 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001352
1353 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001354 offset->fX = bounds.left();
1355 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001356 SkMatrix matrix(ctx.ctm());
1357 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1358 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001359 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001360 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001361 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001362 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1363 transformedLight,
1364 src,
1365 dst,
1366 surfaceScale(),
1367 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001368 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001369 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001370 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1371 transformedLight,
1372 src,
1373 dst,
1374 surfaceScale(),
1375 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001376 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001377 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001378 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1379 transformedLight,
1380 src,
1381 dst,
1382 surfaceScale(),
1383 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001384 break;
1385 }
1386 return true;
1387}
1388
robertphillipsf3f5bad2014-12-19 13:49:15 -08001389#ifndef SK_IGNORE_TO_STRING
1390void SkSpecularLightingImageFilter::toString(SkString* str) const {
1391 str->appendf("SkSpecularLightingImageFilter: (");
1392 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1393 str->append(")");
1394}
1395#endif
1396
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001397#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001398GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001399 GrProcessorDataManager* procDataManager,
1400 GrTexture* texture,
1401 const SkMatrix& matrix,
1402 const SkIRect&,
1403 BoundaryMode boundaryMode) const {
1404 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1405 return GrSpecularLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1406 this->ks(), this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001407}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001408#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001409
1410///////////////////////////////////////////////////////////////////////////////
1411
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001412#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001413
1414namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001415SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001416 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1417 SkScalarToFloat(random->nextSScalar1()),
1418 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001419}
1420
robertphillips2f0dbc72015-08-20 05:15:06 -07001421SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001422 int type = random->nextULessThan(3);
1423 switch (type) {
1424 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001425 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001426 }
1427 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001428 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001429 }
1430 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001431 return new SkSpotLight(random_point3(random), random_point3(random),
1432 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001433 }
1434 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001435 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001436 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001437 }
1438}
1439
senorblancod0d37ca2015-04-02 04:54:56 -07001440SkString emitNormalFunc(BoundaryMode mode,
1441 const char* pointToNormalName,
1442 const char* sobelFuncName) {
1443 SkString result;
1444 switch (mode) {
1445 case kTopLeft_BoundaryMode:
1446 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1447 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1448 "\t surfaceScale);\n",
1449 pointToNormalName, sobelFuncName, gTwoThirds,
1450 sobelFuncName, gTwoThirds);
1451 break;
1452 case kTop_BoundaryMode:
1453 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1454 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1455 "\t surfaceScale);\n",
1456 pointToNormalName, sobelFuncName, gOneThird,
1457 sobelFuncName, gOneHalf);
1458 break;
1459 case kTopRight_BoundaryMode:
1460 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1461 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1462 "\t surfaceScale);\n",
1463 pointToNormalName, sobelFuncName, gTwoThirds,
1464 sobelFuncName, gTwoThirds);
1465 break;
1466 case kLeft_BoundaryMode:
1467 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1468 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1469 "\t surfaceScale);\n",
1470 pointToNormalName, sobelFuncName, gOneHalf,
1471 sobelFuncName, gOneThird);
1472 break;
1473 case kInterior_BoundaryMode:
1474 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1475 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1476 "\t surfaceScale);\n",
1477 pointToNormalName, sobelFuncName, gOneQuarter,
1478 sobelFuncName, gOneQuarter);
1479 break;
1480 case kRight_BoundaryMode:
1481 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1482 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1483 "\t surfaceScale);\n",
1484 pointToNormalName, sobelFuncName, gOneHalf,
1485 sobelFuncName, gOneThird);
1486 break;
1487 case kBottomLeft_BoundaryMode:
1488 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1489 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1490 "\t surfaceScale);\n",
1491 pointToNormalName, sobelFuncName, gTwoThirds,
1492 sobelFuncName, gTwoThirds);
1493 break;
1494 case kBottom_BoundaryMode:
1495 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1496 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1497 "\t surfaceScale);\n",
1498 pointToNormalName, sobelFuncName, gOneThird,
1499 sobelFuncName, gOneHalf);
1500 break;
1501 case kBottomRight_BoundaryMode:
1502 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1503 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1504 "\t surfaceScale);\n",
1505 pointToNormalName, sobelFuncName, gTwoThirds,
1506 sobelFuncName, gTwoThirds);
1507 break;
1508 default:
1509 SkASSERT(false);
1510 break;
1511 }
1512 return result;
1513}
1514
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001515}
1516
joshualittb0a8a372014-09-23 09:50:21 -07001517class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518public:
joshualitteb2a6762014-12-04 11:35:33 -08001519 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001520 virtual ~GrGLLightingEffect();
1521
wangyix7c157a92015-07-22 15:08:53 -07001522 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001523
jvanverthcfc18862015-04-28 08:48:20 -07001524 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001526protected:
wangyixb1daa862015-08-18 11:29:31 -07001527 /**
1528 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1529 */
1530 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1531
joshualitt15988992014-10-09 15:04:05 -07001532 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001534private:
joshualittb0a8a372014-09-23 09:50:21 -07001535 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001536
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001537 UniformHandle fImageIncrementUni;
1538 UniformHandle fSurfaceScaleUni;
1539 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001540 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001541};
1542
1543///////////////////////////////////////////////////////////////////////////////
1544
1545class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1546public:
joshualitteb2a6762014-12-04 11:35:33 -08001547 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001548 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001549
1550protected:
1551 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001552
1553private:
1554 typedef GrGLLightingEffect INHERITED;
1555
bsalomon@google.com032b2212012-07-16 13:36:18 +00001556 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001557};
1558
1559///////////////////////////////////////////////////////////////////////////////
1560
1561class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1562public:
joshualitteb2a6762014-12-04 11:35:33 -08001563 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001564 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001565
1566protected:
1567 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001568
1569private:
1570 typedef GrGLLightingEffect INHERITED;
1571
bsalomon@google.com032b2212012-07-16 13:36:18 +00001572 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001573 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001574};
1575
1576///////////////////////////////////////////////////////////////////////////////
1577
joshualitt5f10b5c2015-07-09 10:24:35 -07001578GrLightingEffect::GrLightingEffect(GrProcessorDataManager* procDataManager,
1579 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001580 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001581 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001582 const SkMatrix& matrix,
1583 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001584 : INHERITED(procDataManager, texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001585 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001586 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001587 , fFilterMatrix(matrix)
1588 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001589 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001590 if (light->requiresFragmentPosition()) {
1591 this->setWillReadFragmentPosition();
1592 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001593}
1594
1595GrLightingEffect::~GrLightingEffect() {
1596 fLight->unref();
1597}
1598
bsalomon0e08fc12014-10-15 08:19:04 -07001599bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001600 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001601 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001602 fSurfaceScale == s.fSurfaceScale &&
1603 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001604}
1605
1606///////////////////////////////////////////////////////////////////////////////
1607
joshualitt5f10b5c2015-07-09 10:24:35 -07001608GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrProcessorDataManager* procDataManager,
1609 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001610 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001611 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001612 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001613 SkScalar kd,
1614 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001615 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001616 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001617}
1618
bsalomon0e08fc12014-10-15 08:19:04 -07001619bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001620 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001621 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001622 this->kd() == s.kd();
1623}
1624
wangyix4b3050b2015-08-04 07:59:37 -07001625void GrDiffuseLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001626 GrProcessorKeyBuilder* b) const {
1627 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1628}
1629
wangyixb1daa862015-08-18 11:29:31 -07001630GrGLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001631 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001632}
1633
joshualittb0a8a372014-09-23 09:50:21 -07001634GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001635
bsalomonc21b09e2015-08-28 18:46:56 -07001636const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001637 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1638 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001639 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001640 SkMatrix matrix;
1641 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001642 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001643 }
joshualitt0067ff52015-07-08 14:26:19 -07001644 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001645 return GrDiffuseLightingEffect::Create(d->fProcDataManager,
1646 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001647 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001648}
1649
1650
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001651///////////////////////////////////////////////////////////////////////////////
1652
joshualitteb2a6762014-12-04 11:35:33 -08001653GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001654 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001655 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001656 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001657}
1658
1659GrGLLightingEffect::~GrGLLightingEffect() {
1660 delete fLight;
1661}
1662
wangyix7c157a92015-07-22 15:08:53 -07001663void GrGLLightingEffect::emitCode(EmitArgs& args) {
1664 fImageIncrementUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001665 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001666 "ImageIncrement");
wangyix7c157a92015-07-22 15:08:53 -07001667 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001668 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001669 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001670 fLight->emitLightColorUniform(args.fBuilder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001671 SkString lightFunc;
wangyix7c157a92015-07-22 15:08:53 -07001672 this->emitLightFunc(args.fBuilder, &lightFunc);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001673 static const GrGLShaderVar gSobelArgs[] = {
1674 GrGLShaderVar("a", kFloat_GrSLType),
1675 GrGLShaderVar("b", kFloat_GrSLType),
1676 GrGLShaderVar("c", kFloat_GrSLType),
1677 GrGLShaderVar("d", kFloat_GrSLType),
1678 GrGLShaderVar("e", kFloat_GrSLType),
1679 GrGLShaderVar("f", kFloat_GrSLType),
1680 GrGLShaderVar("scale", kFloat_GrSLType),
1681 };
1682 SkString sobelFuncName;
wangyix7c157a92015-07-22 15:08:53 -07001683 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1684 SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001685
1686 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001687 "sobel",
1688 SK_ARRAY_COUNT(gSobelArgs),
1689 gSobelArgs,
1690 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1691 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001692 static const GrGLShaderVar gPointToNormalArgs[] = {
1693 GrGLShaderVar("x", kFloat_GrSLType),
1694 GrGLShaderVar("y", kFloat_GrSLType),
1695 GrGLShaderVar("scale", kFloat_GrSLType),
1696 };
1697 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001698 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001699 "pointToNormal",
1700 SK_ARRAY_COUNT(gPointToNormalArgs),
1701 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001702 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001703 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001704
1705 static const GrGLShaderVar gInteriorNormalArgs[] = {
1706 GrGLShaderVar("m", kFloat_GrSLType, 9),
1707 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1708 };
senorblancod0d37ca2015-04-02 04:54:56 -07001709 SkString normalBody = emitNormalFunc(fBoundaryMode,
1710 pointToNormalName.c_str(),
1711 sobelFuncName.c_str());
1712 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001713 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001714 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001715 SK_ARRAY_COUNT(gInteriorNormalArgs),
1716 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001717 normalBody.c_str(),
1718 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001719
joshualitt30ba4362014-08-21 20:18:45 -07001720 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1721 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001722
wangyix7c157a92015-07-22 15:08:53 -07001723 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1724 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001725
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001726 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001727 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001728 for (int dx = -1; dx <= 1; dx++) {
1729 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001730 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001731 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
wangyix7c157a92015-07-22 15:08:53 -07001732 fsBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001733 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001734 }
1735 }
joshualitt30ba4362014-08-21 20:18:45 -07001736 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001737 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001738 arg.appendf("%s * m[4]", surfScale);
wangyix7c157a92015-07-22 15:08:53 -07001739 fLight->emitSurfaceToLight(args.fBuilder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001740 fsBuilder->codeAppend(";\n");
1741 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
wangyix7c157a92015-07-22 15:08:53 -07001742 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1743 fLight->emitLightColor(args.fBuilder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001744 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001745 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001746 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001747 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001748}
1749
joshualittb0a8a372014-09-23 09:50:21 -07001750void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001751 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001752 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1753 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001754}
1755
wangyixb1daa862015-08-18 11:29:31 -07001756void GrGLLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001757 const GrProcessor& proc) {
1758 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001759 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001760 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001761 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1762 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001763 SkAutoTUnref<SkImageFilterLight> transformedLight(
1764 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001765 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001766}
1767
1768///////////////////////////////////////////////////////////////////////////////
1769
1770///////////////////////////////////////////////////////////////////////////////
1771
joshualitteb2a6762014-12-04 11:35:33 -08001772GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1773 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001774}
1775
joshualitt15988992014-10-09 15:04:05 -07001776void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001777 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001778 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001779 kFloat_GrSLType, kDefault_GrSLPrecision,
1780 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001781
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001782 static const GrGLShaderVar gLightArgs[] = {
1783 GrGLShaderVar("normal", kVec3f_GrSLType),
1784 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1785 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1786 };
1787 SkString lightBody;
1788 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1789 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001790 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1791 "light",
1792 SK_ARRAY_COUNT(gLightArgs),
1793 gLightArgs,
1794 lightBody.c_str(),
1795 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001796}
1797
wangyixb1daa862015-08-18 11:29:31 -07001798void GrGLDiffuseLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001799 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001800 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001801 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001802 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001803}
1804
1805///////////////////////////////////////////////////////////////////////////////
1806
joshualitt5f10b5c2015-07-09 10:24:35 -07001807GrSpecularLightingEffect::GrSpecularLightingEffect(GrProcessorDataManager* procDataManager,
1808 GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001809 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001810 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001811 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001812 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001813 SkScalar shininess,
1814 BoundaryMode boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001815 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode)
1816 , fKS(ks)
1817 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001818 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001819}
1820
bsalomon0e08fc12014-10-15 08:19:04 -07001821bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001822 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001823 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001824 this->ks() == s.ks() &&
1825 this->shininess() == s.shininess();
1826}
1827
wangyix4b3050b2015-08-04 07:59:37 -07001828void GrSpecularLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001829 GrProcessorKeyBuilder* b) const {
1830 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1831}
1832
wangyixb1daa862015-08-18 11:29:31 -07001833GrGLFragmentProcessor* GrSpecularLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001834 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001835}
1836
joshualittb0a8a372014-09-23 09:50:21 -07001837GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001838
bsalomonc21b09e2015-08-28 18:46:56 -07001839const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001840 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1841 SkScalar ks = d->fRandom->nextUScalar1();
1842 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001843 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001844 SkMatrix matrix;
1845 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001846 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001847 }
joshualitt0067ff52015-07-08 14:26:19 -07001848 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001849 return GrSpecularLightingEffect::Create(d->fProcDataManager,
1850 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001851 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001852}
1853
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001854///////////////////////////////////////////////////////////////////////////////
1855
joshualitteb2a6762014-12-04 11:35:33 -08001856GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1857 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001858}
1859
joshualitt15988992014-10-09 15:04:05 -07001860void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001861 const char* ks;
1862 const char* shininess;
1863
joshualitt30ba4362014-08-21 20:18:45 -07001864 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001865 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001866 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001867 kFloat_GrSLType,
1868 kDefault_GrSLPrecision,
1869 "Shininess",
1870 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001871
1872 static const GrGLShaderVar gLightArgs[] = {
1873 GrGLShaderVar("normal", kVec3f_GrSLType),
1874 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1875 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1876 };
1877 SkString lightBody;
1878 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1879 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001880 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1881 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001882 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1883 "light",
1884 SK_ARRAY_COUNT(gLightArgs),
1885 gLightArgs,
1886 lightBody.c_str(),
1887 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001888}
1889
wangyixb1daa862015-08-18 11:29:31 -07001890void GrGLSpecularLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001891 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001892 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001893 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001894 pdman.set1f(fKSUni, spec.ks());
1895 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001896}
1897
1898///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001899void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001900 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001901 kVec3f_GrSLType, kDefault_GrSLPrecision,
1902 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001903}
1904
robertphillips3d32d762015-07-13 13:16:44 -07001905void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001906 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001907}
1908
robertphillips2f0dbc72015-08-20 05:15:06 -07001909void GrGLLight::setData(const GrGLProgramDataManager& pdman,
1910 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001911 setUniformPoint3(pdman, fColorUni,
1912 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001913}
1914
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001915///////////////////////////////////////////////////////////////////////////////
1916
kkinnunen7510b222014-07-30 00:04:16 -07001917void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001918 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001919 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001920 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001921 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001922 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001923}
1924
joshualitt15988992014-10-09 15:04:05 -07001925void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001926 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001927 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1928 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001929 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001930 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001931}
1932
1933///////////////////////////////////////////////////////////////////////////////
1934
kkinnunen7510b222014-07-30 00:04:16 -07001935void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001936 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001937 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001938 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001939 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001940 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001941}
1942
joshualitt15988992014-10-09 15:04:05 -07001943void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001944 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001945 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1946 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001947 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001948 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001949 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1950 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001951}
1952
1953///////////////////////////////////////////////////////////////////////////////
1954
kkinnunen7510b222014-07-30 00:04:16 -07001955void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001956 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001957 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001958 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001959 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001960 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1961 pdman.set1f(fExponentUni, spotLight->specularExponent());
1962 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1963 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1964 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1965 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001966}
1967
joshualitt15988992014-10-09 15:04:05 -07001968void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001969 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001970 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001971 kVec3f_GrSLType, kDefault_GrSLPrecision,
1972 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001973
egdaniel29bee0f2015-04-29 11:54:42 -07001974 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001975 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1976 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001977}
1978
joshualitt15988992014-10-09 15:04:05 -07001979void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001980 const char *surfaceToLight) {
1981
1982 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1983
1984 const char* exponent;
1985 const char* cosInner;
1986 const char* cosOuter;
1987 const char* coneScale;
1988 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001989 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001990 kFloat_GrSLType, kDefault_GrSLPrecision,
1991 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001992 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001993 kFloat_GrSLType, kDefault_GrSLPrecision,
1994 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001995 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001996 kFloat_GrSLType, kDefault_GrSLPrecision,
1997 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001998 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001999 kFloat_GrSLType, kDefault_GrSLPrecision,
2000 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07002001 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08002002 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002003
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002004 static const GrGLShaderVar gLightColorArgs[] = {
2005 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
2006 };
2007 SkString lightColorBody;
2008 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2009 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2010 lightColorBody.appendf("\t\treturn vec3(0);\n");
2011 lightColorBody.appendf("\t}\n");
2012 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2013 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2014 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2015 color, cosOuter, coneScale);
2016 lightColorBody.appendf("\t}\n");
2017 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07002018 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002019 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002020 "lightColor",
2021 SK_ARRAY_COUNT(gLightColorArgs),
2022 gLightColorArgs,
2023 lightColorBody.c_str(),
2024 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002025
joshualitt30ba4362014-08-21 20:18:45 -07002026 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002027}
2028
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002029#endif
2030
djsollen@google.com08337772012-06-26 14:33:13 +00002031SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2032 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2033 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002034SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END