blob: 199bb4d684f8e3ab842f1f44d22126e8b3f75197 [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;
bsalomon4a339522015-10-06 08:40:50 -0700324 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700325 const SkMatrix&,
326 const SkIRect& bounds,
327 BoundaryMode boundaryMode) const = 0;
328#endif
329private:
330#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700331 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700332 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700333 const SkMatrix& matrix,
334 const GrClip& clip,
335 const SkRect& dstRect,
336 BoundaryMode boundaryMode,
337 const SkIRect& bounds) const;
338#endif
339 typedef SkLightingImageFilter INHERITED;
340};
341
342#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700343void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700344 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700345 const SkMatrix& matrix,
346 const GrClip& clip,
347 const SkRect& dstRect,
348 BoundaryMode boundaryMode,
349 const SkIRect& bounds) const {
350 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700351 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700352 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700353 paint.addColorFragmentProcessor(fp)->unref();
robertphillips2e1e51f2015-10-15 08:01:48 -0700354 drawContext->drawNonAARectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700355}
356
357bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
358 const SkBitmap& src,
359 const Context& ctx,
360 SkBitmap* result,
361 SkIPoint* offset) const {
362 SkBitmap input = src;
363 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700364 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700365 return false;
366 }
367 SkIRect bounds;
368 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
369 return false;
370 }
371 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
372 SkIntToScalar(bounds.height()));
373 GrTexture* srcTexture = input.getTexture();
374 GrContext* context = srcTexture->getContext();
375
376 GrSurfaceDesc desc;
377 desc.fFlags = kRenderTarget_GrSurfaceFlag,
378 desc.fWidth = bounds.width();
379 desc.fHeight = bounds.height();
380 desc.fConfig = kRGBA_8888_GrPixelConfig;
381
bsalomoneae62002015-07-31 13:59:30 -0700382 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700383 if (!dst) {
384 return false;
385 }
386
387 // setup new clip
388 GrClip clip(dstRect);
389
390 offset->fX = bounds.left();
391 offset->fY = bounds.top();
392 SkMatrix matrix(ctx.ctm());
393 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
394 bounds.offset(-srcOffset);
395 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
396 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
397 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
398 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
399 SkRect interior = dstRect.makeInset(1, 1);
400 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
401 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
402 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
403 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700404
robertphillips2e1e51f2015-10-15 08:01:48 -0700405 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700406 if (!drawContext) {
407 return false;
408 }
409
robertphillips2e1e51f2015-10-15 08:01:48 -0700410 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
411 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
412 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700413 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700414 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
415 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700416 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700417 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
418 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700419 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700420 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
421 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700422 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700423 WrapTexture(dst, bounds.width(), bounds.height(), result);
424 return true;
425}
426#endif
427
428class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000429public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700430 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
431 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700432 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700433
robertphillipsf3f5bad2014-12-19 13:49:15 -0800434 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000435 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000436 SkScalar kd() const { return fKD; }
437
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000438protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700439 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700440 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700441 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700442 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
443 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000444#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700445 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
446 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000447#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000448
449private:
reed9fa60da2014-08-21 07:59:51 -0700450 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700451 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000452 SkScalar fKD;
453};
454
senorblancod0d37ca2015-04-02 04:54:56 -0700455class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700457 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700458 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700459
robertphillipsf3f5bad2014-12-19 13:49:15 -0800460 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
462
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000463 SkScalar ks() const { return fKS; }
464 SkScalar shininess() const { return fShininess; }
465
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000466protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700467 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700468 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700469 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700470 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
471 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000472#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700473 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
474 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000475#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000476
477private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000478 SkScalar fKS;
479 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700480 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700481 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000482};
483
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000484#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000485
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000486class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000487public:
bsalomon4a339522015-10-06 08:40:50 -0700488 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
489 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490 virtual ~GrLightingEffect();
491
robertphillips2f0dbc72015-08-20 05:15:06 -0700492 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000494 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700495 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000496
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000497protected:
mtklein36352bf2015-03-25 18:17:31 -0700498 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000499
mtklein36352bf2015-03-25 18:17:31 -0700500 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700501 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800502 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700503 }
504
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000505private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700506 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000507 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000508 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700509 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700510
511 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512};
513
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000514class GrDiffuseLightingEffect : public GrLightingEffect {
515public:
bsalomon4a339522015-10-06 08:40:50 -0700516 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700517 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700518 SkScalar surfaceScale,
519 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700520 SkScalar kd,
521 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700522 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000523 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000524
mtklein36352bf2015-03-25 18:17:31 -0700525 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000526
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000528
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529private:
wangyixb1daa862015-08-18 11:29:31 -0700530 GrGLFragmentProcessor* onCreateGLInstance() const override;
531
wangyix4b3050b2015-08-04 07:59:37 -0700532 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
533
mtklein36352bf2015-03-25 18:17:31 -0700534 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000535
bsalomon4a339522015-10-06 08:40:50 -0700536 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700537 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000538 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000539 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700540 SkScalar kd,
541 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000542
joshualittb0a8a372014-09-23 09:50:21 -0700543 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000544 typedef GrLightingEffect INHERITED;
545 SkScalar fKD;
546};
547
548class GrSpecularLightingEffect : public GrLightingEffect {
549public:
bsalomon4a339522015-10-06 08:40:50 -0700550 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700551 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700552 SkScalar surfaceScale,
553 const SkMatrix& matrix,
554 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700555 SkScalar shininess,
556 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700557 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
558 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000559 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000560
mtklein36352bf2015-03-25 18:17:31 -0700561 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000562
wangyixb1daa862015-08-18 11:29:31 -0700563 GrGLFragmentProcessor* onCreateGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800564
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565 SkScalar ks() const { return fKS; }
566 SkScalar shininess() const { return fShininess; }
567
568private:
wangyix4b3050b2015-08-04 07:59:37 -0700569 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
570
mtklein36352bf2015-03-25 18:17:31 -0700571 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000572
bsalomon4a339522015-10-06 08:40:50 -0700573 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700574 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000575 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000576 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000577 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700578 SkScalar shininess,
579 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000580
joshualittb0a8a372014-09-23 09:50:21 -0700581 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000582 typedef GrLightingEffect INHERITED;
583 SkScalar fKS;
584 SkScalar fShininess;
585};
586
587///////////////////////////////////////////////////////////////////////////////
588
589class GrGLLight {
590public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000591 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000592
593 /**
594 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
595 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
596 */
joshualitt15988992014-10-09 15:04:05 -0700597 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000598
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000599 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000600 * These two functions are called from GrGLLightingEffect's emitCode() function.
601 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
602 * the light. The expression will be used in the FS. emitLightColor writes an expression into
603 * the FS that is the color of the light. Either function may add functions and/or uniforms to
604 * the FS. The default of emitLightColor appends the name of the constant light color uniform
605 * and so this function only needs to be overridden if the light color varies spatially.
606 */
joshualitt15988992014-10-09 15:04:05 -0700607 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
608 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000609
610 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
611 // INHERITED::setData().
robertphillips2f0dbc72015-08-20 05:15:06 -0700612 virtual void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000613
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000614protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000615 /**
616 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
617 * function.
618 */
619 UniformHandle lightColorUni() const { return fColorUni; }
620
621private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000622 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000623
624 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625};
626
627///////////////////////////////////////////////////////////////////////////////
628
629class GrGLDistantLight : public GrGLLight {
630public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000631 virtual ~GrGLDistantLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700632 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700633 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000634
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000635private:
636 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000637 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638};
639
640///////////////////////////////////////////////////////////////////////////////
641
642class GrGLPointLight : public GrGLLight {
643public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000644 virtual ~GrGLPointLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700645 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700646 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000647
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000648private:
649 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000650 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000651};
652
653///////////////////////////////////////////////////////////////////////////////
654
655class GrGLSpotLight : public GrGLLight {
656public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000657 virtual ~GrGLSpotLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700658 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700659 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
660 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000661
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662private:
663 typedef GrGLLight INHERITED;
664
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000665 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000666 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000667 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000668 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000669 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000670 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000671 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000672};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000673#else
674
675class GrGLLight;
676
677#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000678
679};
680
681///////////////////////////////////////////////////////////////////////////////
682
robertphillips2f0dbc72015-08-20 05:15:06 -0700683class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000684public:
caryclark0bccd872015-10-20 10:04:03 -0700685
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000686
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000687 enum LightType {
688 kDistant_LightType,
689 kPoint_LightType,
690 kSpot_LightType,
691 };
692 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000693 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000694 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700695 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000696 return fColor == other.fColor;
697 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000698 // Called to know whether the generated GrGLLight will require access to the fragment position.
699 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700700 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000702 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000703 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700704 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000705
djsollen@google.com08337772012-06-26 14:33:13 +0000706protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700707 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700708 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
709 SkIntToScalar(SkColorGetG(color)),
710 SkIntToScalar(SkColorGetB(color)));
711 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700712 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000713 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700714 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000715 fColor = readPoint3(buffer);
716 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000717
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000718 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000719
djsollen@google.com08337772012-06-26 14:33:13 +0000720
721private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000722 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000723 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000724};
725
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000726///////////////////////////////////////////////////////////////////////////////
727
robertphillips2f0dbc72015-08-20 05:15:06 -0700728class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000729public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000730 SkDistantLight(const SkPoint3& direction, SkColor color)
731 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000732 }
djsollen@google.com08337772012-06-26 14:33:13 +0000733
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000734 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
735 return fDirection;
736 };
robertphillips3d32d762015-07-13 13:16:44 -0700737 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700738 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000739 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700740 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000741#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700742 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000743#else
744 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700745 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000746#endif
747 }
mtklein36352bf2015-03-25 18:17:31 -0700748 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000749
robertphillips2f0dbc72015-08-20 05:15:06 -0700750 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000751 if (other.type() != kDistant_LightType) {
752 return false;
753 }
754
755 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
756 return INHERITED::isEqual(other) &&
757 fDirection == o.fDirection;
758 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000759
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000760 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000761 fDirection = readPoint3(buffer);
762 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000763
djsollen@google.com08337772012-06-26 14:33:13 +0000764protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000765 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
766 : INHERITED(color), fDirection(direction) {
767 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700768 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000769 return new SkDistantLight(direction(), color());
770 }
mtklein36352bf2015-03-25 18:17:31 -0700771 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000772 writePoint3(fDirection, buffer);
773 }
774
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000775private:
776 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700777
778 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779};
780
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000781///////////////////////////////////////////////////////////////////////////////
782
robertphillips2f0dbc72015-08-20 05:15:06 -0700783class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000785 SkPointLight(const SkPoint3& location, SkColor color)
786 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000787
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000788 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700789 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
790 fLocation.fY - SkIntToScalar(y),
791 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
792 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700793 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000794 return direction;
795 };
robertphillips3d32d762015-07-13 13:16:44 -0700796 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700797 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000798 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700799 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000800#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700801 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000802#else
803 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700804 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000805#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000806 }
mtklein36352bf2015-03-25 18:17:31 -0700807 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700808 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000809 if (other.type() != kPoint_LightType) {
810 return false;
811 }
812 const SkPointLight& o = static_cast<const SkPointLight&>(other);
813 return INHERITED::isEqual(other) &&
814 fLocation == o.fLocation;
815 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700816 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000817 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
818 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000819 // Use X scale and Y scale on Z and average the result
820 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
821 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700822 SkPoint3 location = SkPoint3::Make(location2.fX,
823 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700824 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000825 return new SkPointLight(location, color());
826 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000827
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000828 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000829 fLocation = readPoint3(buffer);
830 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000831
832protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000833 SkPointLight(const SkPoint3& location, const SkPoint3& color)
834 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700835 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000836 writePoint3(fLocation, buffer);
837 }
838
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000839private:
840 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700841
842 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000843};
844
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000845///////////////////////////////////////////////////////////////////////////////
846
robertphillips2f0dbc72015-08-20 05:15:06 -0700847class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848public:
senorblancod0d37ca2015-04-02 04:54:56 -0700849 SkSpotLight(const SkPoint3& location,
850 const SkPoint3& target,
851 SkScalar specularExponent,
852 SkScalar cutoffAngle,
853 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000854 : INHERITED(color),
855 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000856 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700857 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000858 {
859 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700860 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000861 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000862 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000863 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
864 fConeScale = SkScalarInvert(antiAliasThreshold);
865 }
djsollen@google.com08337772012-06-26 14:33:13 +0000866
robertphillips2f0dbc72015-08-20 05:15:06 -0700867 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000868 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
869 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000870 // Use X scale and Y scale on Z and average the result
871 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
872 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700873 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
874 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000875 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
876 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000877 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
878 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700879 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
880 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000881 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700882 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700883 return new SkSpotLight(location,
884 target,
885 fSpecularExponent,
886 fCosOuterConeAngle,
887 fCosInnerConeAngle,
888 fConeScale,
889 s,
890 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000891 }
892
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000893 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700894 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
895 fLocation.fY - SkIntToScalar(y),
896 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
897 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700898 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000899 return direction;
900 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000901 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700903 SkScalar scale = 0;
904 if (cosAngle >= fCosOuterConeAngle) {
905 scale = SkScalarPow(cosAngle, fSpecularExponent);
906 if (cosAngle < fCosInnerConeAngle) {
907 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
908 scale *= fConeScale;
909 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910 }
robertphillips3d32d762015-07-13 13:16:44 -0700911 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000912 }
mtklein36352bf2015-03-25 18:17:31 -0700913 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000914#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700915 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000916#else
917 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700918 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000919#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000920 }
mtklein36352bf2015-03-25 18:17:31 -0700921 bool requiresFragmentPosition() const override { return true; }
922 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000923 const SkPoint3& location() const { return fLocation; }
924 const SkPoint3& target() const { return fTarget; }
925 SkScalar specularExponent() const { return fSpecularExponent; }
926 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
927 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
928 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000929 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000930
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000931 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000932 fLocation = readPoint3(buffer);
933 fTarget = readPoint3(buffer);
934 fSpecularExponent = buffer.readScalar();
935 fCosOuterConeAngle = buffer.readScalar();
936 fCosInnerConeAngle = buffer.readScalar();
937 fConeScale = buffer.readScalar();
938 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000939 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
940 SkScalarIsFinite(fCosOuterConeAngle) &&
941 SkScalarIsFinite(fCosInnerConeAngle) &&
942 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000943 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000944protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700945 SkSpotLight(const SkPoint3& location,
946 const SkPoint3& target,
947 SkScalar specularExponent,
948 SkScalar cosOuterConeAngle,
949 SkScalar cosInnerConeAngle,
950 SkScalar coneScale,
951 const SkPoint3& s,
952 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000953 : INHERITED(color),
954 fLocation(location),
955 fTarget(target),
956 fSpecularExponent(specularExponent),
957 fCosOuterConeAngle(cosOuterConeAngle),
958 fCosInnerConeAngle(cosInnerConeAngle),
959 fConeScale(coneScale),
960 fS(s)
961 {
962 }
mtklein36352bf2015-03-25 18:17:31 -0700963 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000964 writePoint3(fLocation, buffer);
965 writePoint3(fTarget, buffer);
966 buffer.writeScalar(fSpecularExponent);
967 buffer.writeScalar(fCosOuterConeAngle);
968 buffer.writeScalar(fCosInnerConeAngle);
969 buffer.writeScalar(fConeScale);
970 writePoint3(fS, buffer);
971 }
972
robertphillips2f0dbc72015-08-20 05:15:06 -0700973 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000974 if (other.type() != kSpot_LightType) {
975 return false;
976 }
977
978 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
979 return INHERITED::isEqual(other) &&
980 fLocation == o.fLocation &&
981 fTarget == o.fTarget &&
982 fSpecularExponent == o.fSpecularExponent &&
983 fCosOuterConeAngle == o.fCosOuterConeAngle;
984 }
985
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000986private:
caryclark0bccd872015-10-20 10:04:03 -0700987 static const SkScalar kSpecularExponentMin;
988 static const SkScalar kSpecularExponentMax;
989
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000990 SkPoint3 fLocation;
991 SkPoint3 fTarget;
992 SkScalar fSpecularExponent;
993 SkScalar fCosOuterConeAngle;
994 SkScalar fCosInnerConeAngle;
995 SkScalar fConeScale;
996 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -0700997
998 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000999};
1000
caryclark0bccd872015-10-20 10:04:03 -07001001// According to the spec, the specular term should be in the range [1, 128] :
1002// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1003const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1004const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1005
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001006///////////////////////////////////////////////////////////////////////////////
1007
robertphillips2f0dbc72015-08-20 05:15:06 -07001008void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001009 // Write type first, then baseclass, then subclass.
1010 buffer.writeInt(this->type());
1011 writePoint3(fColor, buffer);
1012 this->onFlattenLight(buffer);
1013}
1014
robertphillips2f0dbc72015-08-20 05:15:06 -07001015/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001016 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001017 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001018 switch (type) {
1019 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1020 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001021 case SkImageFilterLight::kDistant_LightType:
1022 return new SkDistantLight(buffer);
1023 case SkImageFilterLight::kPoint_LightType:
1024 return new SkPointLight(buffer);
1025 case SkImageFilterLight::kSpot_LightType:
1026 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001027 default:
1028 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001029 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001030 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001031 }
1032}
1033///////////////////////////////////////////////////////////////////////////////
1034
robertphillips2f0dbc72015-08-20 05:15:06 -07001035SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001036 SkImageFilter* input, const CropRect* cropRect)
1037 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001038 , fLight(SkRef(light))
1039 , fSurfaceScale(surfaceScale / 255)
1040{}
1041
1042SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1043 SkColor lightColor,
1044 SkScalar surfaceScale,
1045 SkScalar kd,
1046 SkImageFilter* input,
1047 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001048 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001049 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001050}
1051
reed9fa60da2014-08-21 07:59:51 -07001052SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1053 SkColor lightColor,
1054 SkScalar surfaceScale,
1055 SkScalar kd,
1056 SkImageFilter* input,
1057 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001058 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001059 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001060}
1061
reed9fa60da2014-08-21 07:59:51 -07001062SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1063 const SkPoint3& target,
1064 SkScalar specularExponent,
1065 SkScalar cutoffAngle,
1066 SkColor lightColor,
1067 SkScalar surfaceScale,
1068 SkScalar kd,
1069 SkImageFilter* input,
1070 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001071 SkAutoTUnref<SkImageFilterLight> light(
1072 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001073 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001074}
1075
reed9fa60da2014-08-21 07:59:51 -07001076SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1077 SkColor lightColor,
1078 SkScalar surfaceScale,
1079 SkScalar ks,
1080 SkScalar shine,
1081 SkImageFilter* input,
1082 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001083 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001084 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001085}
1086
reed9fa60da2014-08-21 07:59:51 -07001087SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1088 SkColor lightColor,
1089 SkScalar surfaceScale,
1090 SkScalar ks,
1091 SkScalar shine,
1092 SkImageFilter* input,
1093 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001094 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001095 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001096}
1097
reed9fa60da2014-08-21 07:59:51 -07001098SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1099 const SkPoint3& target,
1100 SkScalar specularExponent,
1101 SkScalar cutoffAngle,
1102 SkColor lightColor,
1103 SkScalar surfaceScale,
1104 SkScalar ks,
1105 SkScalar shine,
1106 SkImageFilter* input,
1107 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001108 SkAutoTUnref<SkImageFilterLight> light(
1109 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001110 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001111}
1112
reed9fa60da2014-08-21 07:59:51 -07001113SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001114
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001115void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001116 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001117 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001118 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001119}
1120
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001121///////////////////////////////////////////////////////////////////////////////
1122
robertphillips2f0dbc72015-08-20 05:15:06 -07001123SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1124 SkScalar surfaceScale,
1125 SkScalar kd,
1126 SkImageFilter* input,
1127 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001128 if (nullptr == light) {
1129 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001130 }
1131 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001132 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001133 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001134 // According to the spec, kd can be any non-negative number :
1135 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001136 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001137 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001138 }
halcanary385fe4d2015-08-26 13:07:48 -07001139 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001140}
1141
robertphillips2f0dbc72015-08-20 05:15:06 -07001142SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001143 SkScalar surfaceScale,
1144 SkScalar kd,
1145 SkImageFilter* input,
1146 const CropRect* cropRect)
1147 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001148 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001149{
1150}
1151
reed9fa60da2014-08-21 07:59:51 -07001152SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1153 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001154 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001155 SkScalar surfaceScale = buffer.readScalar();
1156 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001157 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001158}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001159
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001160void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001161 this->INHERITED::flatten(buffer);
1162 buffer.writeScalar(fKD);
1163}
1164
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001165bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1166 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001167 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001168 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001169 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001170 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001171 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001172 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001173 return false;
1174 }
1175
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001176 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001177 return false;
1178 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001179 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001180 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001181 return false;
1182 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001183
1184 if (bounds.width() < 2 || bounds.height() < 2) {
1185 return false;
1186 }
1187
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001188 SkAutoLockPixels alp(src);
1189 if (!src.getPixels()) {
1190 return false;
1191 }
1192
reed84825042014-09-02 12:50:45 -07001193 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001194 return false;
1195 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001196
senorblanco7b7ecfc2015-08-26 14:26:40 -07001197 SkMatrix matrix(ctx.ctm());
1198 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1199 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001200
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001201 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001202 offset->fX = bounds.left();
1203 offset->fY = bounds.top();
1204 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001205 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001206 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001207 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1208 transformedLight,
1209 src,
1210 dst,
1211 surfaceScale(),
1212 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001213 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001214 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001215 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1216 transformedLight,
1217 src,
1218 dst,
1219 surfaceScale(),
1220 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001221 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001222 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001223 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1224 transformedLight,
1225 src,
1226 dst,
1227 surfaceScale(),
1228 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001229 break;
1230 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001231
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001232 return true;
1233}
1234
robertphillipsf3f5bad2014-12-19 13:49:15 -08001235#ifndef SK_IGNORE_TO_STRING
1236void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1237 str->appendf("SkDiffuseLightingImageFilter: (");
1238 str->appendf("kD: %f\n", fKD);
1239 str->append(")");
1240}
1241#endif
1242
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001243#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001244GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001245 GrTexture* texture,
1246 const SkMatrix& matrix,
1247 const SkIRect&,
1248 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001249) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001250 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001251 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1252 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001253}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001254#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001255
1256///////////////////////////////////////////////////////////////////////////////
1257
robertphillips2f0dbc72015-08-20 05:15:06 -07001258SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1259 SkScalar surfaceScale,
1260 SkScalar ks,
1261 SkScalar shininess,
1262 SkImageFilter* input,
1263 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001264 if (nullptr == light) {
1265 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001266 }
1267 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001268 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001269 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001270 // According to the spec, ks can be any non-negative number :
1271 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001272 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001273 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001274 }
halcanary385fe4d2015-08-26 13:07:48 -07001275 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001276}
1277
robertphillips2f0dbc72015-08-20 05:15:06 -07001278SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001279 SkScalar surfaceScale,
1280 SkScalar ks,
1281 SkScalar shininess,
1282 SkImageFilter* input,
1283 const CropRect* cropRect)
1284 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001285 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001286 fShininess(shininess)
1287{
1288}
1289
reed9fa60da2014-08-21 07:59:51 -07001290SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1291 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001292 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001293 SkScalar surfaceScale = buffer.readScalar();
1294 SkScalar ks = buffer.readScalar();
1295 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001296 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001297}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001298
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001299void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001300 this->INHERITED::flatten(buffer);
1301 buffer.writeScalar(fKS);
1302 buffer.writeScalar(fShininess);
1303}
1304
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001305bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1306 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001307 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001308 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001309 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001310 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001311 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001312 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001313 return false;
1314 }
1315
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001316 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001317 return false;
1318 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001319
1320 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001321 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001322 return false;
1323 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001324
1325 if (bounds.width() < 2 || bounds.height() < 2) {
1326 return false;
1327 }
1328
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001329 SkAutoLockPixels alp(src);
1330 if (!src.getPixels()) {
1331 return false;
1332 }
1333
reed84825042014-09-02 12:50:45 -07001334 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001335 return false;
1336 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001337
1338 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001339 offset->fX = bounds.left();
1340 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001341 SkMatrix matrix(ctx.ctm());
1342 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1343 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001344 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001345 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001346 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001347 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1348 transformedLight,
1349 src,
1350 dst,
1351 surfaceScale(),
1352 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001353 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001354 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001355 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1356 transformedLight,
1357 src,
1358 dst,
1359 surfaceScale(),
1360 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001361 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001362 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001363 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1364 transformedLight,
1365 src,
1366 dst,
1367 surfaceScale(),
1368 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001369 break;
1370 }
1371 return true;
1372}
1373
robertphillipsf3f5bad2014-12-19 13:49:15 -08001374#ifndef SK_IGNORE_TO_STRING
1375void SkSpecularLightingImageFilter::toString(SkString* str) const {
1376 str->appendf("SkSpecularLightingImageFilter: (");
1377 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1378 str->append(")");
1379}
1380#endif
1381
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001382#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001383GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001384 GrTexture* texture,
1385 const SkMatrix& matrix,
1386 const SkIRect&,
1387 BoundaryMode boundaryMode) const {
1388 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001389 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1390 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001391}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001392#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001393
1394///////////////////////////////////////////////////////////////////////////////
1395
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001396#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001397
1398namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001399SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001400 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1401 SkScalarToFloat(random->nextSScalar1()),
1402 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001403}
1404
robertphillips2f0dbc72015-08-20 05:15:06 -07001405SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001406 int type = random->nextULessThan(3);
1407 switch (type) {
1408 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001409 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001410 }
1411 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001412 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001413 }
1414 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001415 return new SkSpotLight(random_point3(random), random_point3(random),
1416 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001417 }
1418 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001419 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001420 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001421 }
1422}
1423
senorblancod0d37ca2015-04-02 04:54:56 -07001424SkString emitNormalFunc(BoundaryMode mode,
1425 const char* pointToNormalName,
1426 const char* sobelFuncName) {
1427 SkString result;
1428 switch (mode) {
1429 case kTopLeft_BoundaryMode:
1430 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1431 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1432 "\t surfaceScale);\n",
1433 pointToNormalName, sobelFuncName, gTwoThirds,
1434 sobelFuncName, gTwoThirds);
1435 break;
1436 case kTop_BoundaryMode:
1437 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1438 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1439 "\t surfaceScale);\n",
1440 pointToNormalName, sobelFuncName, gOneThird,
1441 sobelFuncName, gOneHalf);
1442 break;
1443 case kTopRight_BoundaryMode:
1444 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1445 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1446 "\t surfaceScale);\n",
1447 pointToNormalName, sobelFuncName, gTwoThirds,
1448 sobelFuncName, gTwoThirds);
1449 break;
1450 case kLeft_BoundaryMode:
1451 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1452 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1453 "\t surfaceScale);\n",
1454 pointToNormalName, sobelFuncName, gOneHalf,
1455 sobelFuncName, gOneThird);
1456 break;
1457 case kInterior_BoundaryMode:
1458 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1459 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1460 "\t surfaceScale);\n",
1461 pointToNormalName, sobelFuncName, gOneQuarter,
1462 sobelFuncName, gOneQuarter);
1463 break;
1464 case kRight_BoundaryMode:
1465 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1466 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1467 "\t surfaceScale);\n",
1468 pointToNormalName, sobelFuncName, gOneHalf,
1469 sobelFuncName, gOneThird);
1470 break;
1471 case kBottomLeft_BoundaryMode:
1472 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1473 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1474 "\t surfaceScale);\n",
1475 pointToNormalName, sobelFuncName, gTwoThirds,
1476 sobelFuncName, gTwoThirds);
1477 break;
1478 case kBottom_BoundaryMode:
1479 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1480 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1481 "\t surfaceScale);\n",
1482 pointToNormalName, sobelFuncName, gOneThird,
1483 sobelFuncName, gOneHalf);
1484 break;
1485 case kBottomRight_BoundaryMode:
1486 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1487 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1488 "\t surfaceScale);\n",
1489 pointToNormalName, sobelFuncName, gTwoThirds,
1490 sobelFuncName, gTwoThirds);
1491 break;
1492 default:
1493 SkASSERT(false);
1494 break;
1495 }
1496 return result;
1497}
1498
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001499}
1500
joshualittb0a8a372014-09-23 09:50:21 -07001501class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001502public:
joshualitteb2a6762014-12-04 11:35:33 -08001503 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001504 virtual ~GrGLLightingEffect();
1505
wangyix7c157a92015-07-22 15:08:53 -07001506 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001507
jvanverthcfc18862015-04-28 08:48:20 -07001508 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001509
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001510protected:
wangyixb1daa862015-08-18 11:29:31 -07001511 /**
1512 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1513 */
1514 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1515
joshualitt15988992014-10-09 15:04:05 -07001516 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001517
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518private:
joshualittb0a8a372014-09-23 09:50:21 -07001519 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001520
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001521 UniformHandle fImageIncrementUni;
1522 UniformHandle fSurfaceScaleUni;
1523 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001524 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525};
1526
1527///////////////////////////////////////////////////////////////////////////////
1528
1529class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1530public:
joshualitteb2a6762014-12-04 11:35:33 -08001531 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001532 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001533
1534protected:
1535 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001536
1537private:
1538 typedef GrGLLightingEffect INHERITED;
1539
bsalomon@google.com032b2212012-07-16 13:36:18 +00001540 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001541};
1542
1543///////////////////////////////////////////////////////////////////////////////
1544
1545class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1546public:
joshualitteb2a6762014-12-04 11:35:33 -08001547 GrGLSpecularLightingEffect(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 fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001557 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001558};
1559
1560///////////////////////////////////////////////////////////////////////////////
1561
bsalomon4a339522015-10-06 08:40:50 -07001562GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001563 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001564 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001565 const SkMatrix& matrix,
1566 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001567 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001568 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001569 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001570 , fFilterMatrix(matrix)
1571 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001572 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001573 if (light->requiresFragmentPosition()) {
1574 this->setWillReadFragmentPosition();
1575 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001576}
1577
1578GrLightingEffect::~GrLightingEffect() {
1579 fLight->unref();
1580}
1581
bsalomon0e08fc12014-10-15 08:19:04 -07001582bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001583 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001584 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001585 fSurfaceScale == s.fSurfaceScale &&
1586 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001587}
1588
1589///////////////////////////////////////////////////////////////////////////////
1590
bsalomon4a339522015-10-06 08:40:50 -07001591GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001592 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001593 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001594 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001595 SkScalar kd,
1596 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001597 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001598 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001599}
1600
bsalomon0e08fc12014-10-15 08:19:04 -07001601bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001602 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001603 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001604 this->kd() == s.kd();
1605}
1606
wangyix4b3050b2015-08-04 07:59:37 -07001607void GrDiffuseLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001608 GrProcessorKeyBuilder* b) const {
1609 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1610}
1611
wangyixb1daa862015-08-18 11:29:31 -07001612GrGLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001613 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001614}
1615
joshualittb0a8a372014-09-23 09:50:21 -07001616GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001617
bsalomonc21b09e2015-08-28 18:46:56 -07001618const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001619 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1620 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001621 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001622 SkMatrix matrix;
1623 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001624 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001625 }
joshualitt0067ff52015-07-08 14:26:19 -07001626 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001627 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001628 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001629}
1630
1631
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001632///////////////////////////////////////////////////////////////////////////////
1633
joshualitteb2a6762014-12-04 11:35:33 -08001634GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001635 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001636 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001637 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638}
1639
1640GrGLLightingEffect::~GrGLLightingEffect() {
1641 delete fLight;
1642}
1643
wangyix7c157a92015-07-22 15:08:53 -07001644void GrGLLightingEffect::emitCode(EmitArgs& args) {
1645 fImageIncrementUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001646 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001647 "ImageIncrement");
wangyix7c157a92015-07-22 15:08:53 -07001648 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001649 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001650 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001651 fLight->emitLightColorUniform(args.fBuilder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001652 SkString lightFunc;
wangyix7c157a92015-07-22 15:08:53 -07001653 this->emitLightFunc(args.fBuilder, &lightFunc);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001654 static const GrGLShaderVar gSobelArgs[] = {
1655 GrGLShaderVar("a", kFloat_GrSLType),
1656 GrGLShaderVar("b", kFloat_GrSLType),
1657 GrGLShaderVar("c", kFloat_GrSLType),
1658 GrGLShaderVar("d", kFloat_GrSLType),
1659 GrGLShaderVar("e", kFloat_GrSLType),
1660 GrGLShaderVar("f", kFloat_GrSLType),
1661 GrGLShaderVar("scale", kFloat_GrSLType),
1662 };
1663 SkString sobelFuncName;
wangyix7c157a92015-07-22 15:08:53 -07001664 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1665 SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001666
1667 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001668 "sobel",
1669 SK_ARRAY_COUNT(gSobelArgs),
1670 gSobelArgs,
1671 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1672 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001673 static const GrGLShaderVar gPointToNormalArgs[] = {
1674 GrGLShaderVar("x", kFloat_GrSLType),
1675 GrGLShaderVar("y", kFloat_GrSLType),
1676 GrGLShaderVar("scale", kFloat_GrSLType),
1677 };
1678 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001679 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001680 "pointToNormal",
1681 SK_ARRAY_COUNT(gPointToNormalArgs),
1682 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001683 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001684 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001685
1686 static const GrGLShaderVar gInteriorNormalArgs[] = {
1687 GrGLShaderVar("m", kFloat_GrSLType, 9),
1688 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1689 };
senorblancod0d37ca2015-04-02 04:54:56 -07001690 SkString normalBody = emitNormalFunc(fBoundaryMode,
1691 pointToNormalName.c_str(),
1692 sobelFuncName.c_str());
1693 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001694 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001695 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001696 SK_ARRAY_COUNT(gInteriorNormalArgs),
1697 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001698 normalBody.c_str(),
1699 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001700
joshualitt30ba4362014-08-21 20:18:45 -07001701 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1702 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001703
wangyix7c157a92015-07-22 15:08:53 -07001704 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1705 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001706
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001707 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001708 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001709 for (int dx = -1; dx <= 1; dx++) {
1710 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001711 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001712 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
wangyix7c157a92015-07-22 15:08:53 -07001713 fsBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001714 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001715 }
1716 }
joshualitt30ba4362014-08-21 20:18:45 -07001717 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001718 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001719 arg.appendf("%s * m[4]", surfScale);
wangyix7c157a92015-07-22 15:08:53 -07001720 fLight->emitSurfaceToLight(args.fBuilder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001721 fsBuilder->codeAppend(";\n");
1722 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
wangyix7c157a92015-07-22 15:08:53 -07001723 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1724 fLight->emitLightColor(args.fBuilder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001725 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001726 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001727 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001728 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001729}
1730
joshualittb0a8a372014-09-23 09:50:21 -07001731void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001732 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001733 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1734 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001735}
1736
wangyixb1daa862015-08-18 11:29:31 -07001737void GrGLLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001738 const GrProcessor& proc) {
1739 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001740 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001741 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001742 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1743 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001744 SkAutoTUnref<SkImageFilterLight> transformedLight(
1745 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001746 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001747}
1748
1749///////////////////////////////////////////////////////////////////////////////
1750
1751///////////////////////////////////////////////////////////////////////////////
1752
joshualitteb2a6762014-12-04 11:35:33 -08001753GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1754 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001755}
1756
joshualitt15988992014-10-09 15:04:05 -07001757void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001758 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001759 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001760 kFloat_GrSLType, kDefault_GrSLPrecision,
1761 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001762
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001763 static const GrGLShaderVar gLightArgs[] = {
1764 GrGLShaderVar("normal", kVec3f_GrSLType),
1765 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1766 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1767 };
1768 SkString lightBody;
1769 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1770 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001771 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1772 "light",
1773 SK_ARRAY_COUNT(gLightArgs),
1774 gLightArgs,
1775 lightBody.c_str(),
1776 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001777}
1778
wangyixb1daa862015-08-18 11:29:31 -07001779void GrGLDiffuseLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001780 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001781 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001782 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001783 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001784}
1785
1786///////////////////////////////////////////////////////////////////////////////
1787
bsalomon4a339522015-10-06 08:40:50 -07001788GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001789 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001790 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001791 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001792 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001793 SkScalar shininess,
1794 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001795 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001796 , fKS(ks)
1797 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001798 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001799}
1800
bsalomon0e08fc12014-10-15 08:19:04 -07001801bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001802 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001803 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001804 this->ks() == s.ks() &&
1805 this->shininess() == s.shininess();
1806}
1807
wangyix4b3050b2015-08-04 07:59:37 -07001808void GrSpecularLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001809 GrProcessorKeyBuilder* b) const {
1810 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1811}
1812
wangyixb1daa862015-08-18 11:29:31 -07001813GrGLFragmentProcessor* GrSpecularLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001814 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001815}
1816
joshualittb0a8a372014-09-23 09:50:21 -07001817GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001818
bsalomonc21b09e2015-08-28 18:46:56 -07001819const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001820 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1821 SkScalar ks = d->fRandom->nextUScalar1();
1822 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001823 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001824 SkMatrix matrix;
1825 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001826 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001827 }
joshualitt0067ff52015-07-08 14:26:19 -07001828 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001829 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001830 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001831}
1832
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001833///////////////////////////////////////////////////////////////////////////////
1834
joshualitteb2a6762014-12-04 11:35:33 -08001835GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1836 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001837}
1838
joshualitt15988992014-10-09 15:04:05 -07001839void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001840 const char* ks;
1841 const char* shininess;
1842
joshualitt30ba4362014-08-21 20:18:45 -07001843 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001844 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001845 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001846 kFloat_GrSLType,
1847 kDefault_GrSLPrecision,
1848 "Shininess",
1849 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001850
1851 static const GrGLShaderVar gLightArgs[] = {
1852 GrGLShaderVar("normal", kVec3f_GrSLType),
1853 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1854 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1855 };
1856 SkString lightBody;
1857 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1858 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001859 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1860 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001861 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1862 "light",
1863 SK_ARRAY_COUNT(gLightArgs),
1864 gLightArgs,
1865 lightBody.c_str(),
1866 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001867}
1868
wangyixb1daa862015-08-18 11:29:31 -07001869void GrGLSpecularLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001870 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001871 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001872 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001873 pdman.set1f(fKSUni, spec.ks());
1874 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001875}
1876
1877///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001878void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001879 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001880 kVec3f_GrSLType, kDefault_GrSLPrecision,
1881 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001882}
1883
robertphillips3d32d762015-07-13 13:16:44 -07001884void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001885 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001886}
1887
robertphillips2f0dbc72015-08-20 05:15:06 -07001888void GrGLLight::setData(const GrGLProgramDataManager& pdman,
1889 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001890 setUniformPoint3(pdman, fColorUni,
1891 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001892}
1893
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001894///////////////////////////////////////////////////////////////////////////////
1895
kkinnunen7510b222014-07-30 00:04:16 -07001896void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001897 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001898 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001899 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001900 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001901 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001902}
1903
joshualitt15988992014-10-09 15:04:05 -07001904void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001905 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001906 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1907 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001908 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001909 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001910}
1911
1912///////////////////////////////////////////////////////////////////////////////
1913
kkinnunen7510b222014-07-30 00:04:16 -07001914void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001915 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001916 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001917 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001918 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001919 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001920}
1921
joshualitt15988992014-10-09 15:04:05 -07001922void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001923 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001924 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1925 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001926 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001927 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001928 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1929 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001930}
1931
1932///////////////////////////////////////////////////////////////////////////////
1933
kkinnunen7510b222014-07-30 00:04:16 -07001934void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001935 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001936 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001937 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001938 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001939 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1940 pdman.set1f(fExponentUni, spotLight->specularExponent());
1941 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1942 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1943 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1944 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001945}
1946
joshualitt15988992014-10-09 15:04:05 -07001947void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001948 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001949 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001950 kVec3f_GrSLType, kDefault_GrSLPrecision,
1951 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001952
egdaniel29bee0f2015-04-29 11:54:42 -07001953 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001954 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1955 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001956}
1957
joshualitt15988992014-10-09 15:04:05 -07001958void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001959 const char *surfaceToLight) {
1960
1961 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1962
1963 const char* exponent;
1964 const char* cosInner;
1965 const char* cosOuter;
1966 const char* coneScale;
1967 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001968 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001969 kFloat_GrSLType, kDefault_GrSLPrecision,
1970 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001971 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001972 kFloat_GrSLType, kDefault_GrSLPrecision,
1973 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001974 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001975 kFloat_GrSLType, kDefault_GrSLPrecision,
1976 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001977 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001978 kFloat_GrSLType, kDefault_GrSLPrecision,
1979 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001980 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001981 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001982
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001983 static const GrGLShaderVar gLightColorArgs[] = {
1984 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1985 };
1986 SkString lightColorBody;
1987 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1988 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1989 lightColorBody.appendf("\t\treturn vec3(0);\n");
1990 lightColorBody.appendf("\t}\n");
1991 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1992 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1993 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1994 color, cosOuter, coneScale);
1995 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07001996 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07001997 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001998 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001999 "lightColor",
2000 SK_ARRAY_COUNT(gLightColorArgs),
2001 gLightColorArgs,
2002 lightColorBody.c_str(),
2003 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002004
joshualitt30ba4362014-08-21 20:18:45 -07002005 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002006}
2007
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002008#endif
2009
djsollen@google.com08337772012-06-26 14:33:13 +00002010SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2011 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2012 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002013SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END