blob: 1dca0fcab4e03681e2d11008d9c83b60079bb5c8 [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"
senorblanco1d3ff432015-10-20 10:17:34 -070011#include "SkDevice.h"
robertphillips3d32d762015-07-13 13:16:44 -070012#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070015#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070018#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070019#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
21#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070022#include "GrPaint.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000023#include "effects/GrSingleTextureEffect.h"
wangyix6af0c932015-07-22 10:21:17 -070024#include "gl/GrGLFragmentProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070025#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000026
27class GrGLDiffuseLightingEffect;
28class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000029
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000030// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070031typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000032#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000033
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000034namespace {
35
reed80ea19c2015-05-12 10:37:34 -070036const SkScalar gOneThird = SkIntToScalar(1) / 3;
37const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000038const SkScalar gOneHalf = 0.5f;
39const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000040
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000041#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070042void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
43 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000044 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070045 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000046}
47
joshualittb0a8a372014-09-23 09:50:21 -070048void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
49 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070050 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000051}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000052#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000053
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000054// Shift matrix components to the left, as we advance pixels to the right.
55inline void shiftMatrixLeft(int m[9]) {
56 m[0] = m[1];
57 m[3] = m[4];
58 m[6] = m[7];
59 m[1] = m[2];
60 m[4] = m[5];
61 m[7] = m[8];
62}
63
jvanverth992c7612015-07-17 07:22:30 -070064static inline void fast_normalize(SkPoint3* vector) {
65 // add a tiny bit so we don't have to worry about divide-by-zero
66 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
67 SkScalar scale = sk_float_rsqrt(magSq);
68 vector->fX *= scale;
69 vector->fY *= scale;
70 vector->fZ *= scale;
71}
72
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000073class DiffuseLightingType {
74public:
75 DiffuseLightingType(SkScalar kd)
76 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070077 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
78 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000079 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
80 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070081 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000082 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000083 SkClampMax(SkScalarRoundToInt(color.fX), 255),
84 SkClampMax(SkScalarRoundToInt(color.fY), 255),
85 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000086 }
87private:
88 SkScalar fKD;
89};
90
robertphillips3d32d762015-07-13 13:16:44 -070091static SkScalar max_component(const SkPoint3& p) {
92 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
93}
94
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000095class SpecularLightingType {
96public:
97 SpecularLightingType(SkScalar ks, SkScalar shininess)
98 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070099 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
100 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000101 SkPoint3 halfDir(surfaceTolight);
102 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700103 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000104 SkScalar colorScale = SkScalarMul(fKS,
105 SkScalarPow(normal.dot(halfDir), fShininess));
106 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700107 SkPoint3 color = lightColor.makeScale(colorScale);
108 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000109 SkClampMax(SkScalarRoundToInt(color.fX), 255),
110 SkClampMax(SkScalarRoundToInt(color.fY), 255),
111 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000112 }
113private:
114 SkScalar fKS;
115 SkScalar fShininess;
116};
117
118inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
119 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
120}
121
122inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700123 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
124 SkScalarMul(-y, surfaceScale),
125 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700126 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000127 return vector;
128}
129
130inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
131 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
132 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
133 surfaceScale);
134}
135
136inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
137 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
138 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
139 surfaceScale);
140}
141
142inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
143 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
144 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
145 surfaceScale);
146}
147
148inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
149 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
150 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
151 surfaceScale);
152}
153
154
155inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
156 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
157 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
158 surfaceScale);
159}
160
161inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
162 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
163 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
164 surfaceScale);
165}
166
167inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
168 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
169 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
170 surfaceScale);
171}
172
173inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
174 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
175 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
176 surfaceScale);
177}
178
179inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
180 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
181 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
182 surfaceScale);
183}
184
robertphillips2f0dbc72015-08-20 05:15:06 -0700185template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType,
186 const SkImageFilterLight* light,
187 const SkBitmap& src,
188 SkBitmap* dst,
189 SkScalar surfaceScale,
190 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000191 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000192 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000193 int left = bounds.left(), right = bounds.right();
194 int bottom = bounds.bottom();
195 int y = bounds.top();
196 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000197 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000198 int x = left;
199 const SkPMColor* row1 = src.getAddr32(x, y);
200 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000201 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000202 m[4] = SkGetPackedA32(*row1++);
203 m[5] = SkGetPackedA32(*row1++);
204 m[7] = SkGetPackedA32(*row2++);
205 m[8] = SkGetPackedA32(*row2++);
206 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700207 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
208 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000209 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 {
211 shiftMatrixLeft(m);
212 m[5] = SkGetPackedA32(*row1++);
213 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000214 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700215 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
216 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000217 }
218 shiftMatrixLeft(m);
219 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700220 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
221 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000222 }
223
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000224 for (++y; y < bottom - 1; ++y) {
225 int x = left;
226 const SkPMColor* row0 = src.getAddr32(x, y - 1);
227 const SkPMColor* row1 = src.getAddr32(x, y);
228 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000229 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000230 m[1] = SkGetPackedA32(*row0++);
231 m[2] = SkGetPackedA32(*row0++);
232 m[4] = SkGetPackedA32(*row1++);
233 m[5] = SkGetPackedA32(*row1++);
234 m[7] = SkGetPackedA32(*row2++);
235 m[8] = SkGetPackedA32(*row2++);
236 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700237 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
238 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000239 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 shiftMatrixLeft(m);
241 m[2] = SkGetPackedA32(*row0++);
242 m[5] = SkGetPackedA32(*row1++);
243 m[8] = SkGetPackedA32(*row2++);
244 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700245 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
246 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000247 }
248 shiftMatrixLeft(m);
249 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700250 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
251 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000252 }
253
254 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000255 int x = left;
256 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
257 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000258 int m[9];
259 m[1] = SkGetPackedA32(*row0++);
260 m[2] = SkGetPackedA32(*row0++);
261 m[4] = SkGetPackedA32(*row1++);
262 m[5] = SkGetPackedA32(*row1++);
263 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700264 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
265 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000266 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000267 {
268 shiftMatrixLeft(m);
269 m[2] = SkGetPackedA32(*row0++);
270 m[5] = SkGetPackedA32(*row1++);
271 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700272 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
273 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000274 }
275 shiftMatrixLeft(m);
276 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700277 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
278 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000279 }
280}
281
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000282SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000283 SkPoint3 point;
284 point.fX = buffer.readScalar();
285 point.fY = buffer.readScalar();
286 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000287 buffer.validate(SkScalarIsFinite(point.fX) &&
288 SkScalarIsFinite(point.fY) &&
289 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290 return point;
291};
292
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000293void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000294 buffer.writeScalar(point.fX);
295 buffer.writeScalar(point.fY);
296 buffer.writeScalar(point.fZ);
297};
298
senorblancod0d37ca2015-04-02 04:54:56 -0700299enum BoundaryMode {
300 kTopLeft_BoundaryMode,
301 kTop_BoundaryMode,
302 kTopRight_BoundaryMode,
303 kLeft_BoundaryMode,
304 kInterior_BoundaryMode,
305 kRight_BoundaryMode,
306 kBottomLeft_BoundaryMode,
307 kBottom_BoundaryMode,
308 kBottomRight_BoundaryMode,
309
310 kBoundaryModeCount,
311};
312
313class SkLightingImageFilterInternal : public SkLightingImageFilter {
314protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700315 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700316 SkScalar surfaceScale,
317 SkImageFilter* input,
318 const CropRect* cropRect)
319 : INHERITED(light, surfaceScale, input, cropRect) {}
320
321#if SK_SUPPORT_GPU
322 bool canFilterImageGPU() const override { return true; }
323 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
324 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700325 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700326 const SkMatrix&,
327 const SkIRect& bounds,
328 BoundaryMode boundaryMode) const = 0;
329#endif
330private:
331#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700332 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700333 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700334 const SkMatrix& matrix,
335 const GrClip& clip,
336 const SkRect& dstRect,
337 BoundaryMode boundaryMode,
338 const SkIRect& bounds) const;
339#endif
340 typedef SkLightingImageFilter INHERITED;
341};
342
343#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700344void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700345 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700346 const SkMatrix& matrix,
347 const GrClip& clip,
348 const SkRect& dstRect,
349 BoundaryMode boundaryMode,
350 const SkIRect& bounds) const {
351 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700352 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700353 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700354 paint.addColorFragmentProcessor(fp)->unref();
robertphillips2e1e51f2015-10-15 08:01:48 -0700355 drawContext->drawNonAARectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700356}
357
358bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
359 const SkBitmap& src,
360 const Context& ctx,
361 SkBitmap* result,
362 SkIPoint* offset) const {
363 SkBitmap input = src;
364 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700365 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700366 return false;
367 }
368 SkIRect bounds;
369 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
370 return false;
371 }
372 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
373 SkIntToScalar(bounds.height()));
374 GrTexture* srcTexture = input.getTexture();
375 GrContext* context = srcTexture->getContext();
376
377 GrSurfaceDesc desc;
378 desc.fFlags = kRenderTarget_GrSurfaceFlag,
379 desc.fWidth = bounds.width();
380 desc.fHeight = bounds.height();
381 desc.fConfig = kRGBA_8888_GrPixelConfig;
382
bsalomoneae62002015-07-31 13:59:30 -0700383 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700384 if (!dst) {
385 return false;
386 }
387
388 // setup new clip
389 GrClip clip(dstRect);
390
391 offset->fX = bounds.left();
392 offset->fY = bounds.top();
393 SkMatrix matrix(ctx.ctm());
394 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
395 bounds.offset(-srcOffset);
396 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
397 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
398 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
399 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
400 SkRect interior = dstRect.makeInset(1, 1);
401 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
402 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
403 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
404 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700405
robertphillips2e1e51f2015-10-15 08:01:48 -0700406 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700407 if (!drawContext) {
408 return false;
409 }
410
robertphillips2e1e51f2015-10-15 08:01:48 -0700411 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
412 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
413 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700414 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700415 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
416 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700417 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700418 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
419 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700420 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700421 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
422 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700423 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700424 WrapTexture(dst, bounds.width(), bounds.height(), result);
425 return true;
426}
427#endif
428
429class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000430public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700431 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
432 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700433 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700434
robertphillipsf3f5bad2014-12-19 13:49:15 -0800435 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000436 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000437 SkScalar kd() const { return fKD; }
438
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000439protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700440 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700441 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700442 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700443 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
444 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000445#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700446 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
447 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000448#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000449
450private:
reed9fa60da2014-08-21 07:59:51 -0700451 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700452 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000453 SkScalar fKD;
454};
455
senorblancod0d37ca2015-04-02 04:54:56 -0700456class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000457public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700458 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700459 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700460
robertphillipsf3f5bad2014-12-19 13:49:15 -0800461 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000462 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
463
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000464 SkScalar ks() const { return fKS; }
465 SkScalar shininess() const { return fShininess; }
466
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000467protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700468 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700469 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700470 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700471 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
472 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000473#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700474 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
475 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000476#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000477
478private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479 SkScalar fKS;
480 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700481 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700482 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483};
484
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000485#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000486
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000487class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000488public:
bsalomon4a339522015-10-06 08:40:50 -0700489 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
490 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491 virtual ~GrLightingEffect();
492
robertphillips2f0dbc72015-08-20 05:15:06 -0700493 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000495 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700496 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000497
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000498protected:
mtklein36352bf2015-03-25 18:17:31 -0700499 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000500
mtklein36352bf2015-03-25 18:17:31 -0700501 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700502 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800503 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700504 }
505
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000506private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700507 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000509 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700510 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700511
512 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000513};
514
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000515class GrDiffuseLightingEffect : public GrLightingEffect {
516public:
bsalomon4a339522015-10-06 08:40:50 -0700517 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700518 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700519 SkScalar surfaceScale,
520 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700521 SkScalar kd,
522 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700523 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000524 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000525
mtklein36352bf2015-03-25 18:17:31 -0700526 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000528 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000529
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000530private:
wangyixb1daa862015-08-18 11:29:31 -0700531 GrGLFragmentProcessor* onCreateGLInstance() const override;
532
wangyix4b3050b2015-08-04 07:59:37 -0700533 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
534
mtklein36352bf2015-03-25 18:17:31 -0700535 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000536
bsalomon4a339522015-10-06 08:40:50 -0700537 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700538 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000539 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000540 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700541 SkScalar kd,
542 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000543
joshualittb0a8a372014-09-23 09:50:21 -0700544 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000545 typedef GrLightingEffect INHERITED;
546 SkScalar fKD;
547};
548
549class GrSpecularLightingEffect : public GrLightingEffect {
550public:
bsalomon4a339522015-10-06 08:40:50 -0700551 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700552 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700553 SkScalar surfaceScale,
554 const SkMatrix& matrix,
555 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700556 SkScalar shininess,
557 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700558 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
559 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000560 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000561
mtklein36352bf2015-03-25 18:17:31 -0700562 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000563
wangyixb1daa862015-08-18 11:29:31 -0700564 GrGLFragmentProcessor* onCreateGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800565
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566 SkScalar ks() const { return fKS; }
567 SkScalar shininess() const { return fShininess; }
568
569private:
wangyix4b3050b2015-08-04 07:59:37 -0700570 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
571
mtklein36352bf2015-03-25 18:17:31 -0700572 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000573
bsalomon4a339522015-10-06 08:40:50 -0700574 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700575 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000576 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000577 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000578 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700579 SkScalar shininess,
580 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000581
joshualittb0a8a372014-09-23 09:50:21 -0700582 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000583 typedef GrLightingEffect INHERITED;
584 SkScalar fKS;
585 SkScalar fShininess;
586};
587
588///////////////////////////////////////////////////////////////////////////////
589
590class GrGLLight {
591public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000592 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000593
594 /**
595 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
596 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
597 */
joshualitt15988992014-10-09 15:04:05 -0700598 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000599
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000600 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000601 * These two functions are called from GrGLLightingEffect's emitCode() function.
602 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
603 * the light. The expression will be used in the FS. emitLightColor writes an expression into
604 * the FS that is the color of the light. Either function may add functions and/or uniforms to
605 * the FS. The default of emitLightColor appends the name of the constant light color uniform
606 * and so this function only needs to be overridden if the light color varies spatially.
607 */
joshualitt15988992014-10-09 15:04:05 -0700608 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
609 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000610
611 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
612 // INHERITED::setData().
robertphillips2f0dbc72015-08-20 05:15:06 -0700613 virtual void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000614
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000615protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000616 /**
617 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
618 * function.
619 */
620 UniformHandle lightColorUni() const { return fColorUni; }
621
622private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000623 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000624
625 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000626};
627
628///////////////////////////////////////////////////////////////////////////////
629
630class GrGLDistantLight : public GrGLLight {
631public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000632 virtual ~GrGLDistantLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700633 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700634 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000635
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000636private:
637 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000638 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000639};
640
641///////////////////////////////////////////////////////////////////////////////
642
643class GrGLPointLight : public GrGLLight {
644public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000645 virtual ~GrGLPointLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700646 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700647 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000648
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000649private:
650 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000651 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000652};
653
654///////////////////////////////////////////////////////////////////////////////
655
656class GrGLSpotLight : public GrGLLight {
657public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000658 virtual ~GrGLSpotLight() {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700659 void setData(const GrGLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700660 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
661 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000662
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000663private:
664 typedef GrGLLight INHERITED;
665
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000666 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000667 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000668 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000669 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000670 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000671 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000672 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000673};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000674#else
675
676class GrGLLight;
677
678#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000679
680};
681
682///////////////////////////////////////////////////////////////////////////////
683
robertphillips2f0dbc72015-08-20 05:15:06 -0700684class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000685public:
caryclark0bccd872015-10-20 10:04:03 -0700686
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000687
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000688 enum LightType {
689 kDistant_LightType,
690 kPoint_LightType,
691 kSpot_LightType,
692 };
693 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000694 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000695 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700696 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000697 return fColor == other.fColor;
698 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000699 // Called to know whether the generated GrGLLight will require access to the fragment position.
700 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700701 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000702
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000703 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000704 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700705 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000706
djsollen@google.com08337772012-06-26 14:33:13 +0000707protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700708 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700709 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
710 SkIntToScalar(SkColorGetG(color)),
711 SkIntToScalar(SkColorGetB(color)));
712 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700713 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000714 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700715 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000716 fColor = readPoint3(buffer);
717 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000718
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000719 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000720
djsollen@google.com08337772012-06-26 14:33:13 +0000721
722private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000723 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000724 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000725};
726
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000727///////////////////////////////////////////////////////////////////////////////
728
robertphillips2f0dbc72015-08-20 05:15:06 -0700729class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000730public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000731 SkDistantLight(const SkPoint3& direction, SkColor color)
732 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733 }
djsollen@google.com08337772012-06-26 14:33:13 +0000734
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000735 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
736 return fDirection;
737 };
robertphillips3d32d762015-07-13 13:16:44 -0700738 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700739 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000740 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700741 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000742#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700743 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000744#else
745 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700746 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000747#endif
748 }
mtklein36352bf2015-03-25 18:17:31 -0700749 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000750
robertphillips2f0dbc72015-08-20 05:15:06 -0700751 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000752 if (other.type() != kDistant_LightType) {
753 return false;
754 }
755
756 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
757 return INHERITED::isEqual(other) &&
758 fDirection == o.fDirection;
759 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000760
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000761 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000762 fDirection = readPoint3(buffer);
763 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000764
djsollen@google.com08337772012-06-26 14:33:13 +0000765protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000766 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
767 : INHERITED(color), fDirection(direction) {
768 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700769 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000770 return new SkDistantLight(direction(), color());
771 }
mtklein36352bf2015-03-25 18:17:31 -0700772 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000773 writePoint3(fDirection, buffer);
774 }
775
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000776private:
777 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700778
779 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000780};
781
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000782///////////////////////////////////////////////////////////////////////////////
783
robertphillips2f0dbc72015-08-20 05:15:06 -0700784class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000785public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000786 SkPointLight(const SkPoint3& location, SkColor color)
787 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000788
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000789 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700790 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
791 fLocation.fY - SkIntToScalar(y),
792 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
793 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700794 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000795 return direction;
796 };
robertphillips3d32d762015-07-13 13:16:44 -0700797 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700798 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000799 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700800 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000801#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700802 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000803#else
804 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700805 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000806#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000807 }
mtklein36352bf2015-03-25 18:17:31 -0700808 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700809 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000810 if (other.type() != kPoint_LightType) {
811 return false;
812 }
813 const SkPointLight& o = static_cast<const SkPointLight&>(other);
814 return INHERITED::isEqual(other) &&
815 fLocation == o.fLocation;
816 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700817 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000818 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
819 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000820 // Use X scale and Y scale on Z and average the result
821 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
822 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700823 SkPoint3 location = SkPoint3::Make(location2.fX,
824 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700825 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000826 return new SkPointLight(location, color());
827 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000828
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000829 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000830 fLocation = readPoint3(buffer);
831 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000832
833protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000834 SkPointLight(const SkPoint3& location, const SkPoint3& color)
835 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700836 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000837 writePoint3(fLocation, buffer);
838 }
839
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000840private:
841 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700842
843 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000844};
845
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000846///////////////////////////////////////////////////////////////////////////////
847
robertphillips2f0dbc72015-08-20 05:15:06 -0700848class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000849public:
senorblancod0d37ca2015-04-02 04:54:56 -0700850 SkSpotLight(const SkPoint3& location,
851 const SkPoint3& target,
852 SkScalar specularExponent,
853 SkScalar cutoffAngle,
854 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000855 : INHERITED(color),
856 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000857 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700858 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000859 {
860 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700861 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000862 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000863 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000864 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
865 fConeScale = SkScalarInvert(antiAliasThreshold);
866 }
djsollen@google.com08337772012-06-26 14:33:13 +0000867
robertphillips2f0dbc72015-08-20 05:15:06 -0700868 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000869 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
870 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000871 // Use X scale and Y scale on Z and average the result
872 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
873 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700874 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
875 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000876 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
877 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000878 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
879 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700880 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
881 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000882 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700883 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700884 return new SkSpotLight(location,
885 target,
886 fSpecularExponent,
887 fCosOuterConeAngle,
888 fCosInnerConeAngle,
889 fConeScale,
890 s,
891 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000892 }
893
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000894 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700895 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
896 fLocation.fY - SkIntToScalar(y),
897 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
898 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700899 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000900 return direction;
901 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000902 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000903 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700904 SkScalar scale = 0;
905 if (cosAngle >= fCosOuterConeAngle) {
906 scale = SkScalarPow(cosAngle, fSpecularExponent);
907 if (cosAngle < fCosInnerConeAngle) {
908 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
909 scale *= fConeScale;
910 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 }
robertphillips3d32d762015-07-13 13:16:44 -0700912 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000913 }
mtklein36352bf2015-03-25 18:17:31 -0700914 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000915#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700916 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000917#else
918 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700919 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000920#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000921 }
mtklein36352bf2015-03-25 18:17:31 -0700922 bool requiresFragmentPosition() const override { return true; }
923 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000924 const SkPoint3& location() const { return fLocation; }
925 const SkPoint3& target() const { return fTarget; }
926 SkScalar specularExponent() const { return fSpecularExponent; }
927 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
928 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
929 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000930 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000931
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000932 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000933 fLocation = readPoint3(buffer);
934 fTarget = readPoint3(buffer);
935 fSpecularExponent = buffer.readScalar();
936 fCosOuterConeAngle = buffer.readScalar();
937 fCosInnerConeAngle = buffer.readScalar();
938 fConeScale = buffer.readScalar();
939 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000940 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
941 SkScalarIsFinite(fCosOuterConeAngle) &&
942 SkScalarIsFinite(fCosInnerConeAngle) &&
943 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000944 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000945protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700946 SkSpotLight(const SkPoint3& location,
947 const SkPoint3& target,
948 SkScalar specularExponent,
949 SkScalar cosOuterConeAngle,
950 SkScalar cosInnerConeAngle,
951 SkScalar coneScale,
952 const SkPoint3& s,
953 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000954 : INHERITED(color),
955 fLocation(location),
956 fTarget(target),
957 fSpecularExponent(specularExponent),
958 fCosOuterConeAngle(cosOuterConeAngle),
959 fCosInnerConeAngle(cosInnerConeAngle),
960 fConeScale(coneScale),
961 fS(s)
962 {
963 }
mtklein36352bf2015-03-25 18:17:31 -0700964 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000965 writePoint3(fLocation, buffer);
966 writePoint3(fTarget, buffer);
967 buffer.writeScalar(fSpecularExponent);
968 buffer.writeScalar(fCosOuterConeAngle);
969 buffer.writeScalar(fCosInnerConeAngle);
970 buffer.writeScalar(fConeScale);
971 writePoint3(fS, buffer);
972 }
973
robertphillips2f0dbc72015-08-20 05:15:06 -0700974 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000975 if (other.type() != kSpot_LightType) {
976 return false;
977 }
978
979 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
980 return INHERITED::isEqual(other) &&
981 fLocation == o.fLocation &&
982 fTarget == o.fTarget &&
983 fSpecularExponent == o.fSpecularExponent &&
984 fCosOuterConeAngle == o.fCosOuterConeAngle;
985 }
986
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000987private:
caryclark0bccd872015-10-20 10:04:03 -0700988 static const SkScalar kSpecularExponentMin;
989 static const SkScalar kSpecularExponentMax;
990
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000991 SkPoint3 fLocation;
992 SkPoint3 fTarget;
993 SkScalar fSpecularExponent;
994 SkScalar fCosOuterConeAngle;
995 SkScalar fCosInnerConeAngle;
996 SkScalar fConeScale;
997 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -0700998
999 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001000};
1001
caryclark0bccd872015-10-20 10:04:03 -07001002// According to the spec, the specular term should be in the range [1, 128] :
1003// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1004const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1005const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1006
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001007///////////////////////////////////////////////////////////////////////////////
1008
robertphillips2f0dbc72015-08-20 05:15:06 -07001009void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001010 // Write type first, then baseclass, then subclass.
1011 buffer.writeInt(this->type());
1012 writePoint3(fColor, buffer);
1013 this->onFlattenLight(buffer);
1014}
1015
robertphillips2f0dbc72015-08-20 05:15:06 -07001016/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001017 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001018 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001019 switch (type) {
1020 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1021 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001022 case SkImageFilterLight::kDistant_LightType:
1023 return new SkDistantLight(buffer);
1024 case SkImageFilterLight::kPoint_LightType:
1025 return new SkPointLight(buffer);
1026 case SkImageFilterLight::kSpot_LightType:
1027 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001028 default:
1029 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001030 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001031 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001032 }
1033}
1034///////////////////////////////////////////////////////////////////////////////
1035
robertphillips2f0dbc72015-08-20 05:15:06 -07001036SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001037 SkImageFilter* input, const CropRect* cropRect)
1038 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001039 , fLight(SkRef(light))
1040 , fSurfaceScale(surfaceScale / 255)
1041{}
1042
1043SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1044 SkColor lightColor,
1045 SkScalar surfaceScale,
1046 SkScalar kd,
1047 SkImageFilter* input,
1048 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001049 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001050 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001051}
1052
reed9fa60da2014-08-21 07:59:51 -07001053SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1054 SkColor lightColor,
1055 SkScalar surfaceScale,
1056 SkScalar kd,
1057 SkImageFilter* input,
1058 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001059 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001060 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001061}
1062
reed9fa60da2014-08-21 07:59:51 -07001063SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1064 const SkPoint3& target,
1065 SkScalar specularExponent,
1066 SkScalar cutoffAngle,
1067 SkColor lightColor,
1068 SkScalar surfaceScale,
1069 SkScalar kd,
1070 SkImageFilter* input,
1071 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001072 SkAutoTUnref<SkImageFilterLight> light(
1073 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001074 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001075}
1076
reed9fa60da2014-08-21 07:59:51 -07001077SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1078 SkColor lightColor,
1079 SkScalar surfaceScale,
1080 SkScalar ks,
1081 SkScalar shine,
1082 SkImageFilter* input,
1083 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001084 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001085 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001086}
1087
reed9fa60da2014-08-21 07:59:51 -07001088SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1089 SkColor lightColor,
1090 SkScalar surfaceScale,
1091 SkScalar ks,
1092 SkScalar shine,
1093 SkImageFilter* input,
1094 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001095 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001096 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001097}
1098
reed9fa60da2014-08-21 07:59:51 -07001099SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1100 const SkPoint3& target,
1101 SkScalar specularExponent,
1102 SkScalar cutoffAngle,
1103 SkColor lightColor,
1104 SkScalar surfaceScale,
1105 SkScalar ks,
1106 SkScalar shine,
1107 SkImageFilter* input,
1108 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001109 SkAutoTUnref<SkImageFilterLight> light(
1110 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001111 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001112}
1113
reed9fa60da2014-08-21 07:59:51 -07001114SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001115
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001116void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001117 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001118 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001119 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001120}
1121
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001122///////////////////////////////////////////////////////////////////////////////
1123
robertphillips2f0dbc72015-08-20 05:15:06 -07001124SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1125 SkScalar surfaceScale,
1126 SkScalar kd,
1127 SkImageFilter* input,
1128 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001129 if (nullptr == light) {
1130 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001131 }
1132 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001133 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001134 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001135 // According to the spec, kd can be any non-negative number :
1136 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001137 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001138 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001139 }
halcanary385fe4d2015-08-26 13:07:48 -07001140 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001141}
1142
robertphillips2f0dbc72015-08-20 05:15:06 -07001143SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001144 SkScalar surfaceScale,
1145 SkScalar kd,
1146 SkImageFilter* input,
1147 const CropRect* cropRect)
1148 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001149 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001150{
1151}
1152
reed9fa60da2014-08-21 07:59:51 -07001153SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1154 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001155 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001156 SkScalar surfaceScale = buffer.readScalar();
1157 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001158 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001159}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001160
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001161void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001162 this->INHERITED::flatten(buffer);
1163 buffer.writeScalar(fKD);
1164}
1165
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001166bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1167 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001168 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001169 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001170 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001171 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001172 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001173 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001174 return false;
1175 }
1176
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001177 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001178 return false;
1179 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001180 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001181 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001182 return false;
1183 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001184
1185 if (bounds.width() < 2 || bounds.height() < 2) {
1186 return false;
1187 }
1188
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001189 SkAutoLockPixels alp(src);
1190 if (!src.getPixels()) {
1191 return false;
1192 }
1193
senorblanco1d3ff432015-10-20 10:17:34 -07001194 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1195 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001196 return false;
1197 }
senorblanco1d3ff432015-10-20 10:17:34 -07001198 *dst = device->accessBitmap(false);
1199 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001200
senorblanco7b7ecfc2015-08-26 14:26:40 -07001201 SkMatrix matrix(ctx.ctm());
1202 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1203 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001204
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001205 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001206 offset->fX = bounds.left();
1207 offset->fY = bounds.top();
1208 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001209 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001210 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001211 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1212 transformedLight,
1213 src,
1214 dst,
1215 surfaceScale(),
1216 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001217 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001218 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001219 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1220 transformedLight,
1221 src,
1222 dst,
1223 surfaceScale(),
1224 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001225 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001226 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001227 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1228 transformedLight,
1229 src,
1230 dst,
1231 surfaceScale(),
1232 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001233 break;
1234 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001235
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001236 return true;
1237}
1238
robertphillipsf3f5bad2014-12-19 13:49:15 -08001239#ifndef SK_IGNORE_TO_STRING
1240void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1241 str->appendf("SkDiffuseLightingImageFilter: (");
1242 str->appendf("kD: %f\n", fKD);
1243 str->append(")");
1244}
1245#endif
1246
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001247#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001248GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001249 GrTexture* texture,
1250 const SkMatrix& matrix,
1251 const SkIRect&,
1252 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001253) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001254 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001255 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1256 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001257}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001258#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001259
1260///////////////////////////////////////////////////////////////////////////////
1261
robertphillips2f0dbc72015-08-20 05:15:06 -07001262SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1263 SkScalar surfaceScale,
1264 SkScalar ks,
1265 SkScalar shininess,
1266 SkImageFilter* input,
1267 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001268 if (nullptr == light) {
1269 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001270 }
1271 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001272 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001273 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001274 // According to the spec, ks can be any non-negative number :
1275 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001276 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001277 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001278 }
halcanary385fe4d2015-08-26 13:07:48 -07001279 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001280}
1281
robertphillips2f0dbc72015-08-20 05:15:06 -07001282SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001283 SkScalar surfaceScale,
1284 SkScalar ks,
1285 SkScalar shininess,
1286 SkImageFilter* input,
1287 const CropRect* cropRect)
1288 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001289 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001290 fShininess(shininess)
1291{
1292}
1293
reed9fa60da2014-08-21 07:59:51 -07001294SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1295 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001296 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001297 SkScalar surfaceScale = buffer.readScalar();
1298 SkScalar ks = buffer.readScalar();
1299 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001300 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001301}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001302
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001303void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001304 this->INHERITED::flatten(buffer);
1305 buffer.writeScalar(fKS);
1306 buffer.writeScalar(fShininess);
1307}
1308
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001309bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1310 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001311 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001312 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001313 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001314 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001315 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001316 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001317 return false;
1318 }
1319
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001320 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001321 return false;
1322 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001323
1324 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001325 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001326 return false;
1327 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001328
1329 if (bounds.width() < 2 || bounds.height() < 2) {
1330 return false;
1331 }
1332
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001333 SkAutoLockPixels alp(src);
1334 if (!src.getPixels()) {
1335 return false;
1336 }
1337
senorblanco1d3ff432015-10-20 10:17:34 -07001338 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1339 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001340 return false;
1341 }
senorblanco1d3ff432015-10-20 10:17:34 -07001342 *dst = device->accessBitmap(false);
1343 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001344
1345 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001346 offset->fX = bounds.left();
1347 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001348 SkMatrix matrix(ctx.ctm());
1349 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1350 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001351 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001352 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001353 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001354 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1355 transformedLight,
1356 src,
1357 dst,
1358 surfaceScale(),
1359 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001360 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001361 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001362 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1363 transformedLight,
1364 src,
1365 dst,
1366 surfaceScale(),
1367 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001368 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001369 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001370 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1371 transformedLight,
1372 src,
1373 dst,
1374 surfaceScale(),
1375 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001376 break;
1377 }
1378 return true;
1379}
1380
robertphillipsf3f5bad2014-12-19 13:49:15 -08001381#ifndef SK_IGNORE_TO_STRING
1382void SkSpecularLightingImageFilter::toString(SkString* str) const {
1383 str->appendf("SkSpecularLightingImageFilter: (");
1384 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1385 str->append(")");
1386}
1387#endif
1388
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001389#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001390GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001391 GrTexture* texture,
1392 const SkMatrix& matrix,
1393 const SkIRect&,
1394 BoundaryMode boundaryMode) const {
1395 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001396 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1397 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001398}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001399#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001400
1401///////////////////////////////////////////////////////////////////////////////
1402
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001403#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001404
1405namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001406SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001407 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1408 SkScalarToFloat(random->nextSScalar1()),
1409 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001410}
1411
robertphillips2f0dbc72015-08-20 05:15:06 -07001412SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001413 int type = random->nextULessThan(3);
1414 switch (type) {
1415 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001416 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001417 }
1418 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001419 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001420 }
1421 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001422 return new SkSpotLight(random_point3(random), random_point3(random),
1423 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001424 }
1425 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001426 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001427 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001428 }
1429}
1430
senorblancod0d37ca2015-04-02 04:54:56 -07001431SkString emitNormalFunc(BoundaryMode mode,
1432 const char* pointToNormalName,
1433 const char* sobelFuncName) {
1434 SkString result;
1435 switch (mode) {
1436 case kTopLeft_BoundaryMode:
1437 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], 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, gTwoThirds,
1441 sobelFuncName, gTwoThirds);
1442 break;
1443 case kTop_BoundaryMode:
1444 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1445 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1446 "\t surfaceScale);\n",
1447 pointToNormalName, sobelFuncName, gOneThird,
1448 sobelFuncName, gOneHalf);
1449 break;
1450 case kTopRight_BoundaryMode:
1451 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1452 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1453 "\t surfaceScale);\n",
1454 pointToNormalName, sobelFuncName, gTwoThirds,
1455 sobelFuncName, gTwoThirds);
1456 break;
1457 case kLeft_BoundaryMode:
1458 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1459 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1460 "\t surfaceScale);\n",
1461 pointToNormalName, sobelFuncName, gOneHalf,
1462 sobelFuncName, gOneThird);
1463 break;
1464 case kInterior_BoundaryMode:
1465 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1466 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1467 "\t surfaceScale);\n",
1468 pointToNormalName, sobelFuncName, gOneQuarter,
1469 sobelFuncName, gOneQuarter);
1470 break;
1471 case kRight_BoundaryMode:
1472 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1473 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1474 "\t surfaceScale);\n",
1475 pointToNormalName, sobelFuncName, gOneHalf,
1476 sobelFuncName, gOneThird);
1477 break;
1478 case kBottomLeft_BoundaryMode:
1479 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1480 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1481 "\t surfaceScale);\n",
1482 pointToNormalName, sobelFuncName, gTwoThirds,
1483 sobelFuncName, gTwoThirds);
1484 break;
1485 case kBottom_BoundaryMode:
1486 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1487 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1488 "\t surfaceScale);\n",
1489 pointToNormalName, sobelFuncName, gOneThird,
1490 sobelFuncName, gOneHalf);
1491 break;
1492 case kBottomRight_BoundaryMode:
1493 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1494 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1495 "\t surfaceScale);\n",
1496 pointToNormalName, sobelFuncName, gTwoThirds,
1497 sobelFuncName, gTwoThirds);
1498 break;
1499 default:
1500 SkASSERT(false);
1501 break;
1502 }
1503 return result;
1504}
1505
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001506}
1507
joshualittb0a8a372014-09-23 09:50:21 -07001508class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001509public:
joshualitteb2a6762014-12-04 11:35:33 -08001510 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001511 virtual ~GrGLLightingEffect();
1512
wangyix7c157a92015-07-22 15:08:53 -07001513 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001514
jvanverthcfc18862015-04-28 08:48:20 -07001515 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001516
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001517protected:
wangyixb1daa862015-08-18 11:29:31 -07001518 /**
1519 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1520 */
1521 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1522
joshualitt15988992014-10-09 15:04:05 -07001523 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001524
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525private:
joshualittb0a8a372014-09-23 09:50:21 -07001526 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001527
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001528 UniformHandle fImageIncrementUni;
1529 UniformHandle fSurfaceScaleUni;
1530 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001531 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001532};
1533
1534///////////////////////////////////////////////////////////////////////////////
1535
1536class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1537public:
joshualitteb2a6762014-12-04 11:35:33 -08001538 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001539 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001540
1541protected:
1542 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001543
1544private:
1545 typedef GrGLLightingEffect INHERITED;
1546
bsalomon@google.com032b2212012-07-16 13:36:18 +00001547 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001548};
1549
1550///////////////////////////////////////////////////////////////////////////////
1551
1552class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1553public:
joshualitteb2a6762014-12-04 11:35:33 -08001554 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001555 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001556
1557protected:
1558 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001559
1560private:
1561 typedef GrGLLightingEffect INHERITED;
1562
bsalomon@google.com032b2212012-07-16 13:36:18 +00001563 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001564 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001565};
1566
1567///////////////////////////////////////////////////////////////////////////////
1568
bsalomon4a339522015-10-06 08:40:50 -07001569GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001570 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001571 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001572 const SkMatrix& matrix,
1573 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001574 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001575 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001576 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001577 , fFilterMatrix(matrix)
1578 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001579 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001580 if (light->requiresFragmentPosition()) {
1581 this->setWillReadFragmentPosition();
1582 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001583}
1584
1585GrLightingEffect::~GrLightingEffect() {
1586 fLight->unref();
1587}
1588
bsalomon0e08fc12014-10-15 08:19:04 -07001589bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001590 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001591 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001592 fSurfaceScale == s.fSurfaceScale &&
1593 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001594}
1595
1596///////////////////////////////////////////////////////////////////////////////
1597
bsalomon4a339522015-10-06 08:40:50 -07001598GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001599 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001600 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001601 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001602 SkScalar kd,
1603 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001604 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001605 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001606}
1607
bsalomon0e08fc12014-10-15 08:19:04 -07001608bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001609 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001610 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001611 this->kd() == s.kd();
1612}
1613
wangyix4b3050b2015-08-04 07:59:37 -07001614void GrDiffuseLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001615 GrProcessorKeyBuilder* b) const {
1616 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1617}
1618
wangyixb1daa862015-08-18 11:29:31 -07001619GrGLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001620 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001621}
1622
joshualittb0a8a372014-09-23 09:50:21 -07001623GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001624
bsalomonc21b09e2015-08-28 18:46:56 -07001625const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001626 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1627 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001628 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001629 SkMatrix matrix;
1630 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001631 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001632 }
joshualitt0067ff52015-07-08 14:26:19 -07001633 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001634 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001635 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001636}
1637
1638
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001639///////////////////////////////////////////////////////////////////////////////
1640
joshualitteb2a6762014-12-04 11:35:33 -08001641GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001642 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001643 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001644 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001645}
1646
1647GrGLLightingEffect::~GrGLLightingEffect() {
1648 delete fLight;
1649}
1650
wangyix7c157a92015-07-22 15:08:53 -07001651void GrGLLightingEffect::emitCode(EmitArgs& args) {
1652 fImageIncrementUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001653 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001654 "ImageIncrement");
wangyix7c157a92015-07-22 15:08:53 -07001655 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001656 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001657 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001658 fLight->emitLightColorUniform(args.fBuilder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001659 SkString lightFunc;
wangyix7c157a92015-07-22 15:08:53 -07001660 this->emitLightFunc(args.fBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001661 static const GrGLSLShaderVar gSobelArgs[] = {
1662 GrGLSLShaderVar("a", kFloat_GrSLType),
1663 GrGLSLShaderVar("b", kFloat_GrSLType),
1664 GrGLSLShaderVar("c", kFloat_GrSLType),
1665 GrGLSLShaderVar("d", kFloat_GrSLType),
1666 GrGLSLShaderVar("e", kFloat_GrSLType),
1667 GrGLSLShaderVar("f", kFloat_GrSLType),
1668 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001669 };
1670 SkString sobelFuncName;
wangyix7c157a92015-07-22 15:08:53 -07001671 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1672 SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001673
1674 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001675 "sobel",
1676 SK_ARRAY_COUNT(gSobelArgs),
1677 gSobelArgs,
1678 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1679 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001680 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1681 GrGLSLShaderVar("x", kFloat_GrSLType),
1682 GrGLSLShaderVar("y", kFloat_GrSLType),
1683 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001684 };
1685 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001686 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001687 "pointToNormal",
1688 SK_ARRAY_COUNT(gPointToNormalArgs),
1689 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001690 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001691 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001692
egdaniel0d3f0612015-10-21 10:45:48 -07001693 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1694 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1695 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001696 };
senorblancod0d37ca2015-04-02 04:54:56 -07001697 SkString normalBody = emitNormalFunc(fBoundaryMode,
1698 pointToNormalName.c_str(),
1699 sobelFuncName.c_str());
1700 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001701 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001702 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001703 SK_ARRAY_COUNT(gInteriorNormalArgs),
1704 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001705 normalBody.c_str(),
1706 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001707
joshualitt30ba4362014-08-21 20:18:45 -07001708 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1709 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001710
wangyix7c157a92015-07-22 15:08:53 -07001711 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1712 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001713
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001714 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001715 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001716 for (int dx = -1; dx <= 1; dx++) {
1717 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001718 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001719 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
wangyix7c157a92015-07-22 15:08:53 -07001720 fsBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001721 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001722 }
1723 }
joshualitt30ba4362014-08-21 20:18:45 -07001724 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001725 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001726 arg.appendf("%s * m[4]", surfScale);
wangyix7c157a92015-07-22 15:08:53 -07001727 fLight->emitSurfaceToLight(args.fBuilder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001728 fsBuilder->codeAppend(";\n");
1729 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
wangyix7c157a92015-07-22 15:08:53 -07001730 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1731 fLight->emitLightColor(args.fBuilder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001732 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001733 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001734 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001735 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001736}
1737
joshualittb0a8a372014-09-23 09:50:21 -07001738void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001739 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001740 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1741 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001742}
1743
wangyixb1daa862015-08-18 11:29:31 -07001744void GrGLLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001745 const GrProcessor& proc) {
1746 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001747 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001748 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001749 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1750 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001751 SkAutoTUnref<SkImageFilterLight> transformedLight(
1752 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001753 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001754}
1755
1756///////////////////////////////////////////////////////////////////////////////
1757
1758///////////////////////////////////////////////////////////////////////////////
1759
joshualitteb2a6762014-12-04 11:35:33 -08001760GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1761 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001762}
1763
joshualitt15988992014-10-09 15:04:05 -07001764void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001765 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001766 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001767 kFloat_GrSLType, kDefault_GrSLPrecision,
1768 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001769
egdaniel0d3f0612015-10-21 10:45:48 -07001770 static const GrGLSLShaderVar gLightArgs[] = {
1771 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1772 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1773 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001774 };
1775 SkString lightBody;
1776 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1777 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001778 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1779 "light",
1780 SK_ARRAY_COUNT(gLightArgs),
1781 gLightArgs,
1782 lightBody.c_str(),
1783 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001784}
1785
wangyixb1daa862015-08-18 11:29:31 -07001786void GrGLDiffuseLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001787 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001788 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001789 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001790 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001791}
1792
1793///////////////////////////////////////////////////////////////////////////////
1794
bsalomon4a339522015-10-06 08:40:50 -07001795GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001796 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001797 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001798 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001799 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001800 SkScalar shininess,
1801 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001802 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001803 , fKS(ks)
1804 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001805 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001806}
1807
bsalomon0e08fc12014-10-15 08:19:04 -07001808bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001809 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001810 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001811 this->ks() == s.ks() &&
1812 this->shininess() == s.shininess();
1813}
1814
wangyix4b3050b2015-08-04 07:59:37 -07001815void GrSpecularLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001816 GrProcessorKeyBuilder* b) const {
1817 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1818}
1819
wangyixb1daa862015-08-18 11:29:31 -07001820GrGLFragmentProcessor* GrSpecularLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001821 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001822}
1823
joshualittb0a8a372014-09-23 09:50:21 -07001824GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001825
bsalomonc21b09e2015-08-28 18:46:56 -07001826const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001827 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1828 SkScalar ks = d->fRandom->nextUScalar1();
1829 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001830 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001831 SkMatrix matrix;
1832 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001833 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001834 }
joshualitt0067ff52015-07-08 14:26:19 -07001835 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001836 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001837 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001838}
1839
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001840///////////////////////////////////////////////////////////////////////////////
1841
joshualitteb2a6762014-12-04 11:35:33 -08001842GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1843 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001844}
1845
joshualitt15988992014-10-09 15:04:05 -07001846void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001847 const char* ks;
1848 const char* shininess;
1849
joshualitt30ba4362014-08-21 20:18:45 -07001850 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001851 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001852 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001853 kFloat_GrSLType,
1854 kDefault_GrSLPrecision,
1855 "Shininess",
1856 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001857
egdaniel0d3f0612015-10-21 10:45:48 -07001858 static const GrGLSLShaderVar gLightArgs[] = {
1859 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1860 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1861 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001862 };
1863 SkString lightBody;
1864 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1865 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001866 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1867 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001868 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1869 "light",
1870 SK_ARRAY_COUNT(gLightArgs),
1871 gLightArgs,
1872 lightBody.c_str(),
1873 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001874}
1875
wangyixb1daa862015-08-18 11:29:31 -07001876void GrGLSpecularLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001877 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001878 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001879 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001880 pdman.set1f(fKSUni, spec.ks());
1881 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001882}
1883
1884///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001885void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001886 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001887 kVec3f_GrSLType, kDefault_GrSLPrecision,
1888 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001889}
1890
robertphillips3d32d762015-07-13 13:16:44 -07001891void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001892 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001893}
1894
robertphillips2f0dbc72015-08-20 05:15:06 -07001895void GrGLLight::setData(const GrGLProgramDataManager& pdman,
1896 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001897 setUniformPoint3(pdman, fColorUni,
1898 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001899}
1900
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001901///////////////////////////////////////////////////////////////////////////////
1902
kkinnunen7510b222014-07-30 00:04:16 -07001903void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001904 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001905 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001906 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001907 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001908 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001909}
1910
joshualitt15988992014-10-09 15:04:05 -07001911void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001912 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001913 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1914 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001915 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001916 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001917}
1918
1919///////////////////////////////////////////////////////////////////////////////
1920
kkinnunen7510b222014-07-30 00:04:16 -07001921void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001922 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001923 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001924 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001925 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001926 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001927}
1928
joshualitt15988992014-10-09 15:04:05 -07001929void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001930 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001931 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1932 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001933 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001934 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001935 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1936 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001937}
1938
1939///////////////////////////////////////////////////////////////////////////////
1940
kkinnunen7510b222014-07-30 00:04:16 -07001941void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001942 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001943 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001944 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001945 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001946 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1947 pdman.set1f(fExponentUni, spotLight->specularExponent());
1948 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1949 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1950 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1951 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001952}
1953
joshualitt15988992014-10-09 15:04:05 -07001954void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001955 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001956 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001957 kVec3f_GrSLType, kDefault_GrSLPrecision,
1958 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001959
egdaniel29bee0f2015-04-29 11:54:42 -07001960 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001961 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1962 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001963}
1964
joshualitt15988992014-10-09 15:04:05 -07001965void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001966 const char *surfaceToLight) {
1967
1968 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1969
1970 const char* exponent;
1971 const char* cosInner;
1972 const char* cosOuter;
1973 const char* coneScale;
1974 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001975 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001976 kFloat_GrSLType, kDefault_GrSLPrecision,
1977 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001978 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001979 kFloat_GrSLType, kDefault_GrSLPrecision,
1980 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001981 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001982 kFloat_GrSLType, kDefault_GrSLPrecision,
1983 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001984 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001985 kFloat_GrSLType, kDefault_GrSLPrecision,
1986 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001987 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001988 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001989
egdaniel0d3f0612015-10-21 10:45:48 -07001990 static const GrGLSLShaderVar gLightColorArgs[] = {
1991 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001992 };
1993 SkString lightColorBody;
1994 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1995 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1996 lightColorBody.appendf("\t\treturn vec3(0);\n");
1997 lightColorBody.appendf("\t}\n");
1998 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1999 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2000 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2001 color, cosOuter, coneScale);
2002 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002003 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07002004 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002005 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002006 "lightColor",
2007 SK_ARRAY_COUNT(gLightColorArgs),
2008 gLightColorArgs,
2009 lightColorBody.c_str(),
2010 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002011
joshualitt30ba4362014-08-21 20:18:45 -07002012 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002013}
2014
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002015#endif
2016
djsollen@google.com08337772012-06-26 14:33:13 +00002017SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2018 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2019 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002020SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END