blob: 34e70346027d63fa2df0c518508aaaed419165eb [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
robertphillips3d32d762015-07-13 13:16:44 -070011#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
robertphillipsad3dc0d2016-04-15 05:06:11 -070013#include "SkSpecialImage.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"
csmartdalton02fa32c2016-08-19 13:29:27 -070019#include "GrFixedClip.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
kkinnunencabe20c2015-06-01 01:37:26 -070021#include "GrPaint.h"
Robert Phillips7f6cd902016-11-10 17:03:43 -050022#include "GrRenderTargetContext.h"
23#include "GrTextureProxy.h"
24
robertphillips1de87df2016-01-14 06:03:29 -080025#include "SkGr.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000026#include "effects/GrSingleTextureEffect.h"
senorblanco9bd5f742016-02-17 10:59:47 -080027#include "effects/GrTextureDomain.h"
egdaniel64c47282015-11-13 06:54:19 -080028#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080029#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070030#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080031#include "glsl/GrGLSLUniformHandler.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050032#include "../private/GrGLSL.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000033
34class GrGLDiffuseLightingEffect;
35class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000036
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000037// For brevity
egdaniel018fb622015-10-28 07:26:40 -070038typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000039#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000040
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000041namespace {
42
reed80ea19c2015-05-12 10:37:34 -070043const SkScalar gOneThird = SkIntToScalar(1) / 3;
44const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000045const SkScalar gOneHalf = 0.5f;
46const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000047
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000048#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070049void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070050 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070051 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070052 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000053}
54
egdaniel018fb622015-10-28 07:26:40 -070055void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070056 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070057 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000058}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000059#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000060
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000061// Shift matrix components to the left, as we advance pixels to the right.
62inline void shiftMatrixLeft(int m[9]) {
63 m[0] = m[1];
64 m[3] = m[4];
65 m[6] = m[7];
66 m[1] = m[2];
67 m[4] = m[5];
68 m[7] = m[8];
69}
70
jvanverth992c7612015-07-17 07:22:30 -070071static inline void fast_normalize(SkPoint3* vector) {
72 // add a tiny bit so we don't have to worry about divide-by-zero
73 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
74 SkScalar scale = sk_float_rsqrt(magSq);
75 vector->fX *= scale;
76 vector->fY *= scale;
77 vector->fZ *= scale;
78}
79
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000080class DiffuseLightingType {
81public:
82 DiffuseLightingType(SkScalar kd)
83 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070084 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
85 const SkPoint3& lightColor) const {
Mike Reed8be952a2017-02-13 20:44:33 -050086 SkScalar colorScale = fKD * normal.dot(surfaceTolight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000087 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070088 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000089 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000090 SkClampMax(SkScalarRoundToInt(color.fX), 255),
91 SkClampMax(SkScalarRoundToInt(color.fY), 255),
92 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000093 }
94private:
95 SkScalar fKD;
96};
97
robertphillips3d32d762015-07-13 13:16:44 -070098static SkScalar max_component(const SkPoint3& p) {
99 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
100}
101
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000102class SpecularLightingType {
103public:
104 SpecularLightingType(SkScalar ks, SkScalar shininess)
105 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700106 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
107 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000108 SkPoint3 halfDir(surfaceTolight);
109 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700110 fast_normalize(&halfDir);
Mike Reed8be952a2017-02-13 20:44:33 -0500111 SkScalar colorScale = fKS * SkScalarPow(normal.dot(halfDir), fShininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000112 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700113 SkPoint3 color = lightColor.makeScale(colorScale);
114 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000115 SkClampMax(SkScalarRoundToInt(color.fX), 255),
116 SkClampMax(SkScalarRoundToInt(color.fY), 255),
117 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000118 }
119private:
120 SkScalar fKS;
121 SkScalar fShininess;
122};
123
124inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
Mike Reed8be952a2017-02-13 20:44:33 -0500125 return (-a + b - 2 * c + 2 * d -e + f) * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000126}
127
128inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
Mike Reed8be952a2017-02-13 20:44:33 -0500129 SkPoint3 vector = SkPoint3::Make(-x * surfaceScale, -y * surfaceScale, 1);
jvanverth992c7612015-07-17 07:22:30 -0700130 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000131 return vector;
132}
133
134inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
135 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
136 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
137 surfaceScale);
138}
139
140inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
141 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
142 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
143 surfaceScale);
144}
145
146inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
147 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
148 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
149 surfaceScale);
150}
151
152inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
153 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
154 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
155 surfaceScale);
156}
157
158
159inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
160 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
161 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
162 surfaceScale);
163}
164
165inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
166 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
167 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
168 surfaceScale);
169}
170
171inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
172 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
173 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
174 surfaceScale);
175}
176
177inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
178 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
179 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
180 surfaceScale);
181}
182
183inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
184 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
185 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
186 surfaceScale);
187}
188
senorblanco84f0e742016-02-16 13:26:56 -0800189
190class UncheckedPixelFetcher {
191public:
192 static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
193 return SkGetPackedA32(*src.getAddr32(x, y));
194 }
195};
196
197// The DecalPixelFetcher is used when the destination crop rect exceeds the input bitmap bounds.
198class DecalPixelFetcher {
199public:
200 static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
201 if (x < bounds.fLeft || x >= bounds.fRight || y < bounds.fTop || y >= bounds.fBottom) {
202 return 0;
203 } else {
204 return SkGetPackedA32(*src.getAddr32(x, y));
205 }
206 }
207};
208
209template <class LightingType, class LightType, class PixelFetcher>
210void lightBitmap(const LightingType& lightingType,
211 const SkImageFilterLight* light,
212 const SkBitmap& src,
213 SkBitmap* dst,
214 SkScalar surfaceScale,
215 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000216 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000217 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000218 int left = bounds.left(), right = bounds.right();
219 int bottom = bounds.bottom();
220 int y = bounds.top();
senorblanco84f0e742016-02-16 13:26:56 -0800221 SkIRect srcBounds = src.bounds();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000222 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000223 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000224 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000225 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800226 m[4] = PixelFetcher::Fetch(src, x, y, srcBounds);
227 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
228 m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds);
229 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000230 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700231 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
232 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000233 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000234 {
235 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800236 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
237 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000238 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700239 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
240 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000241 }
242 shiftMatrixLeft(m);
243 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700244 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
245 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000246 }
247
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000248 for (++y; y < bottom - 1; ++y) {
249 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000250 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800251 m[1] = PixelFetcher::Fetch(src, x, y - 1, srcBounds);
252 m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
253 m[4] = PixelFetcher::Fetch(src, x, y, srcBounds);
254 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
255 m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds);
256 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000257 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700258 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
259 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000260 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000261 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800262 m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
263 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
264 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000265 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700266 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
267 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000268 }
269 shiftMatrixLeft(m);
270 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700271 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
272 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000273 }
274
275 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000276 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000277 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800278 m[1] = PixelFetcher::Fetch(src, x, bottom - 2, srcBounds);
279 m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
280 m[4] = PixelFetcher::Fetch(src, x, bottom - 1, srcBounds);
281 m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000282 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700283 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
284 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000285 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 {
287 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800288 m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
289 m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700291 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
292 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000293 }
294 shiftMatrixLeft(m);
295 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700296 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
297 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000298 }
299}
300
senorblanco84f0e742016-02-16 13:26:56 -0800301template <class LightingType, class LightType>
302void lightBitmap(const LightingType& lightingType,
303 const SkImageFilterLight* light,
304 const SkBitmap& src,
305 SkBitmap* dst,
306 SkScalar surfaceScale,
307 const SkIRect& bounds) {
308 if (src.bounds().contains(bounds)) {
309 lightBitmap<LightingType, LightType, UncheckedPixelFetcher>(
310 lightingType, light, src, dst, surfaceScale, bounds);
311 } else {
312 lightBitmap<LightingType, LightType, DecalPixelFetcher>(
313 lightingType, light, src, dst, surfaceScale, bounds);
314 }
315}
316
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000317SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000318 SkPoint3 point;
319 point.fX = buffer.readScalar();
320 point.fY = buffer.readScalar();
321 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000322 buffer.validate(SkScalarIsFinite(point.fX) &&
323 SkScalarIsFinite(point.fY) &&
324 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000325 return point;
326};
327
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000328void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000329 buffer.writeScalar(point.fX);
330 buffer.writeScalar(point.fY);
331 buffer.writeScalar(point.fZ);
332};
333
senorblancod0d37ca2015-04-02 04:54:56 -0700334enum BoundaryMode {
335 kTopLeft_BoundaryMode,
336 kTop_BoundaryMode,
337 kTopRight_BoundaryMode,
338 kLeft_BoundaryMode,
339 kInterior_BoundaryMode,
340 kRight_BoundaryMode,
341 kBottomLeft_BoundaryMode,
342 kBottom_BoundaryMode,
343 kBottomRight_BoundaryMode,
344
345 kBoundaryModeCount,
346};
347
348class SkLightingImageFilterInternal : public SkLightingImageFilter {
349protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700350 SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -0700351 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -0700352 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -0700353 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -0700354 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect) {
355 }
senorblancod0d37ca2015-04-02 04:54:56 -0700356
357#if SK_SUPPORT_GPU
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400358 sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700359 SkSpecialImage* input,
360 const SkIRect& bounds,
brianosman2a75e5d2016-09-22 07:15:37 -0700361 const SkMatrix& matrix,
362 const OutputProperties& outputProperties) const;
Robert Phillips296b1cc2017-03-15 10:42:12 -0400363 virtual sk_sp<GrFragmentProcessor> makeFragmentProcessor(GrResourceProvider*,
364 sk_sp<GrTextureProxy>,
bungeman06ca8ec2016-06-09 08:01:03 -0700365 const SkMatrix&,
366 const SkIRect* srcBounds,
367 BoundaryMode boundaryMode) const = 0;
senorblancod0d37ca2015-04-02 04:54:56 -0700368#endif
369private:
370#if SK_SUPPORT_GPU
Robert Phillips296b1cc2017-03-15 10:42:12 -0400371 void drawRect(GrRenderTargetContext*,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500372 sk_sp<GrTextureProxy> srcProxy,
senorblancod0d37ca2015-04-02 04:54:56 -0700373 const SkMatrix& matrix,
374 const GrClip& clip,
375 const SkRect& dstRect,
376 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800377 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700378 const SkIRect& bounds) const;
379#endif
380 typedef SkLightingImageFilter INHERITED;
381};
382
383#if SK_SUPPORT_GPU
Robert Phillips296b1cc2017-03-15 10:42:12 -0400384void SkLightingImageFilterInternal::drawRect(GrRenderTargetContext* renderTargetContext,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500385 sk_sp<GrTextureProxy> srcProxy,
senorblancod0d37ca2015-04-02 04:54:56 -0700386 const SkMatrix& matrix,
387 const GrClip& clip,
388 const SkRect& dstRect,
389 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800390 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700391 const SkIRect& bounds) const {
Robert Phillips296b1cc2017-03-15 10:42:12 -0400392 GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider();
393
senorblancod0d37ca2015-04-02 04:54:56 -0700394 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700395 GrPaint paint;
Brian Osman11052242016-10-27 14:47:55 -0400396 paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
Robert Phillips296b1cc2017-03-15 10:42:12 -0400397 sk_sp<GrFragmentProcessor> fp(this->makeFragmentProcessor(resourceProvider, std::move(srcProxy),
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500398 matrix, srcBounds,
bungeman06ca8ec2016-06-09 08:01:03 -0700399 boundaryMode));
400 paint.addColorFragmentProcessor(std::move(fp));
reed374772b2016-10-05 17:33:02 -0700401 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon82f44312017-01-11 13:42:54 -0500402 renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect,
403 srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700404}
405
brianosman2a75e5d2016-09-22 07:15:37 -0700406sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(
407 SkSpecialImage* source,
408 SkSpecialImage* input,
409 const SkIRect& offsetBounds,
410 const SkMatrix& matrix,
411 const OutputProperties& outputProperties) const {
robertphillipsad3dc0d2016-04-15 05:06:11 -0700412 SkASSERT(source->isTextureBacked());
413
414 GrContext* context = source->getContext();
415
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500416 sk_sp<GrTextureProxy> inputProxy(input->asTextureProxyRef(context));
417 SkASSERT(inputProxy);
senorblancod0d37ca2015-04-02 04:54:56 -0700418
Robert Phillips7f6cd902016-11-10 17:03:43 -0500419 sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
420 SkBackingFit::kApprox, offsetBounds.width(), offsetBounds.height(),
421 GrRenderableConfigForColorSpace(outputProperties.colorSpace()),
422 sk_ref_sp(outputProperties.colorSpace())));
Brian Osman11052242016-10-27 14:47:55 -0400423 if (!renderTargetContext) {
robertphillipsad3dc0d2016-04-15 05:06:11 -0700424 return nullptr;
425 }
426
cdalton846c0512016-05-13 10:25:00 -0700427 SkIRect dstIRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height());
428 SkRect dstRect = SkRect::Make(dstIRect);
robertphillipsad3dc0d2016-04-15 05:06:11 -0700429
senorblancod0d37ca2015-04-02 04:54:56 -0700430 // setup new clip
cdalton846c0512016-05-13 10:25:00 -0700431 GrFixedClip clip(dstIRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700432
robertphillipsad3dc0d2016-04-15 05:06:11 -0700433 const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
senorblancod0d37ca2015-04-02 04:54:56 -0700434 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
435 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
436 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
437 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
438 SkRect interior = dstRect.makeInset(1, 1);
439 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
440 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
441 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
442 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700443
robertphillipsad3dc0d2016-04-15 05:06:11 -0700444 const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds;
Robert Phillips296b1cc2017-03-15 10:42:12 -0400445 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, topLeft,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700446 kTopLeft_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400447 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, top,
Brian Osman11052242016-10-27 14:47:55 -0400448 kTop_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400449 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, topRight,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700450 kTopRight_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400451 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, left,
Brian Osman11052242016-10-27 14:47:55 -0400452 kLeft_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400453 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, interior,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700454 kInterior_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400455 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, right,
Brian Osman11052242016-10-27 14:47:55 -0400456 kRight_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400457 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottomLeft,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700458 kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400459 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottom,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700460 kBottom_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400461 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottomRight,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700462 kBottomRight_BoundaryMode, pSrcBounds, offsetBounds);
robertphillipsea461502015-05-26 11:38:03 -0700463
Robert Phillips7f6cd902016-11-10 17:03:43 -0500464 return SkSpecialImage::MakeDeferredFromGpu(
465 context,
466 SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()),
robertphillipsad3dc0d2016-04-15 05:06:11 -0700467 kNeedNewImageUniqueID_SpecialImage,
Robert Phillipsf200a902017-01-30 13:27:37 -0500468 renderTargetContext->asTextureProxyRef(),
Robert Phillips75a475c2017-01-13 09:18:59 -0500469 renderTargetContext->refColorSpace());
senorblancod0d37ca2015-04-02 04:54:56 -0700470}
471#endif
472
473class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474public:
robertphillips12fa47d2016-04-08 16:28:09 -0700475 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
476 SkScalar surfaceScale,
477 SkScalar kd,
478 sk_sp<SkImageFilter>,
479 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700480
robertphillipsf3f5bad2014-12-19 13:49:15 -0800481 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000482 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000483 SkScalar kd() const { return fKD; }
484
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700486 SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, SkScalar surfaceScale,
487 SkScalar kd,
488 sk_sp<SkImageFilter> input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700489 void flatten(SkWriteBuffer& buffer) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700490
491 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
492 SkIPoint* offset) const override;
493
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000494#if SK_SUPPORT_GPU
Robert Phillips296b1cc2017-03-15 10:42:12 -0400495 sk_sp<GrFragmentProcessor> makeFragmentProcessor(GrResourceProvider*, sk_sp<GrTextureProxy>,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500496 const SkMatrix&, const SkIRect* bounds,
bungeman06ca8ec2016-06-09 08:01:03 -0700497 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000498#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000499
500private:
reed9fa60da2014-08-21 07:59:51 -0700501 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000502 SkScalar fKD;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700503
504 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000505};
506
senorblancod0d37ca2015-04-02 04:54:56 -0700507class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000508public:
robertphillips12fa47d2016-04-08 16:28:09 -0700509 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
510 SkScalar surfaceScale,
511 SkScalar ks, SkScalar shininess,
512 sk_sp<SkImageFilter>, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700513
robertphillipsf3f5bad2014-12-19 13:49:15 -0800514 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
516
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000517 SkScalar ks() const { return fKS; }
518 SkScalar shininess() const { return fShininess; }
519
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000520protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700521 SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
522 SkScalar surfaceScale, SkScalar ks,
523 SkScalar shininess,
524 sk_sp<SkImageFilter> input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700525 void flatten(SkWriteBuffer& buffer) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700526
527 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
528 SkIPoint* offset) const override;
529
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000530#if SK_SUPPORT_GPU
Robert Phillips296b1cc2017-03-15 10:42:12 -0400531 sk_sp<GrFragmentProcessor> makeFragmentProcessor(GrResourceProvider*, sk_sp<GrTextureProxy>,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500532 const SkMatrix&, const SkIRect* bounds,
bungeman06ca8ec2016-06-09 08:01:03 -0700533 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000534#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000535
536private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000537 SkScalar fKS;
538 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700539 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700540 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000541};
542
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000543#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000544
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000545class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000546public:
Robert Phillips296b1cc2017-03-15 10:42:12 -0400547 GrLightingEffect(GrResourceProvider*, sk_sp<GrTextureProxy>,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500548 const SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco9bd5f742016-02-17 10:59:47 -0800549 const SkMatrix& matrix, BoundaryMode boundaryMode, const SkIRect* srcBounds);
robertphillipse004bfc2015-11-16 09:06:59 -0800550 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000551
robertphillips2f0dbc72015-08-20 05:15:06 -0700552 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000553 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000554 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700555 BoundaryMode boundaryMode() const { return fBoundaryMode; }
senorblanco9bd5f742016-02-17 10:59:47 -0800556 const GrTextureDomain& domain() const { return fDomain; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000557
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000558protected:
mtklein36352bf2015-03-25 18:17:31 -0700559 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000560
egdaniel1a8ecdf2014-10-03 06:24:12 -0700561
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000562private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700563 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000564 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000565 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700566 BoundaryMode fBoundaryMode;
senorblanco9bd5f742016-02-17 10:59:47 -0800567 GrTextureDomain fDomain;
robertphillips2f0dbc72015-08-20 05:15:06 -0700568
569 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000570};
571
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000572class GrDiffuseLightingEffect : public GrLightingEffect {
573public:
Robert Phillips296b1cc2017-03-15 10:42:12 -0400574 static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500575 sk_sp<GrTextureProxy> proxy,
bungeman06ca8ec2016-06-09 08:01:03 -0700576 const SkImageFilterLight* light,
577 SkScalar surfaceScale,
578 const SkMatrix& matrix,
579 SkScalar kd,
580 BoundaryMode boundaryMode,
581 const SkIRect* srcBounds) {
582 return sk_sp<GrFragmentProcessor>(
Robert Phillips296b1cc2017-03-15 10:42:12 -0400583 new GrDiffuseLightingEffect(resourceProvider, std::move(proxy), light,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500584 surfaceScale, matrix, kd, boundaryMode, srcBounds));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000585 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000586
mtklein36352bf2015-03-25 18:17:31 -0700587 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000588
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000589 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000590
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000591private:
egdaniel57d3b032015-11-13 11:57:27 -0800592 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700593
Brian Salomon94efbf52016-11-29 13:43:05 -0500594 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700595
mtklein36352bf2015-03-25 18:17:31 -0700596 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000597
Robert Phillips296b1cc2017-03-15 10:42:12 -0400598 GrDiffuseLightingEffect(GrResourceProvider*, sk_sp<GrTextureProxy>,
robertphillips2f0dbc72015-08-20 05:15:06 -0700599 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000600 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000601 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700602 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800603 BoundaryMode boundaryMode,
604 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000605
joshualittb0a8a372014-09-23 09:50:21 -0700606 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
Robert Phillips696b2932017-02-08 12:49:00 +0000607 SkScalar fKD;
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500608
609 typedef GrLightingEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000610};
611
612class GrSpecularLightingEffect : public GrLightingEffect {
613public:
Robert Phillips296b1cc2017-03-15 10:42:12 -0400614 static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500615 sk_sp<GrTextureProxy> proxy,
bungeman06ca8ec2016-06-09 08:01:03 -0700616 const SkImageFilterLight* light,
617 SkScalar surfaceScale,
618 const SkMatrix& matrix,
619 SkScalar ks,
620 SkScalar shininess,
621 BoundaryMode boundaryMode,
622 const SkIRect* srcBounds) {
623 return sk_sp<GrFragmentProcessor>(
Robert Phillips296b1cc2017-03-15 10:42:12 -0400624 new GrSpecularLightingEffect(resourceProvider, std::move(proxy),
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500625 light, surfaceScale, matrix, ks, shininess,
bungeman06ca8ec2016-06-09 08:01:03 -0700626 boundaryMode, srcBounds));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000627 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628
mtklein36352bf2015-03-25 18:17:31 -0700629 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000630
egdaniel57d3b032015-11-13 11:57:27 -0800631 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800632
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633 SkScalar ks() const { return fKS; }
634 SkScalar shininess() const { return fShininess; }
635
636private:
Brian Salomon94efbf52016-11-29 13:43:05 -0500637 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700638
mtklein36352bf2015-03-25 18:17:31 -0700639 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000640
Robert Phillips296b1cc2017-03-15 10:42:12 -0400641 GrSpecularLightingEffect(GrResourceProvider*, sk_sp<GrTextureProxy>,
robertphillips2f0dbc72015-08-20 05:15:06 -0700642 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000643 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000644 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000645 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700646 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800647 BoundaryMode boundaryMode,
648 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000649
joshualittb0a8a372014-09-23 09:50:21 -0700650 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000651 SkScalar fKS;
652 SkScalar fShininess;
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500653
654 typedef GrLightingEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000655};
656
657///////////////////////////////////////////////////////////////////////////////
658
659class GrGLLight {
660public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000661 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000662
663 /**
664 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
665 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
666 */
egdaniel7ea439b2015-12-03 09:20:44 -0800667 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000668
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000669 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000670 * These two functions are called from GrGLLightingEffect's emitCode() function.
671 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
672 * the light. The expression will be used in the FS. emitLightColor writes an expression into
673 * the FS that is the color of the light. Either function may add functions and/or uniforms to
674 * the FS. The default of emitLightColor appends the name of the constant light color uniform
675 * and so this function only needs to be overridden if the light color varies spatially.
676 */
egdaniel7ea439b2015-12-03 09:20:44 -0800677 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800678 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -0800679 const char* z) = 0;
680 virtual void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800681 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800682 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000683
684 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
685 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700686 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000687
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000688protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000689 /**
690 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
691 * function.
692 */
693 UniformHandle lightColorUni() const { return fColorUni; }
694
695private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000696 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000697
698 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000699};
700
701///////////////////////////////////////////////////////////////////////////////
702
703class GrGLDistantLight : public GrGLLight {
704public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000705 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700706 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800707 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000708
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000709private:
710 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000711 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000712};
713
714///////////////////////////////////////////////////////////////////////////////
715
716class GrGLPointLight : public GrGLLight {
717public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000718 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700719 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800720 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000721
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000722private:
723 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000724 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000725};
726
727///////////////////////////////////////////////////////////////////////////////
728
729class GrGLSpotLight : public GrGLLight {
730public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000731 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700732 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800733 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
egdaniel7ea439b2015-12-03 09:20:44 -0800734 void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800735 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800736 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000737
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000738private:
739 typedef GrGLLight INHERITED;
740
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000741 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000742 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000743 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000744 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000745 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000746 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000747 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000748};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000749#else
750
751class GrGLLight;
752
753#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000754
755};
756
757///////////////////////////////////////////////////////////////////////////////
758
robertphillips2f0dbc72015-08-20 05:15:06 -0700759class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000760public:
halcanary9d524f22016-03-29 09:03:52 -0700761
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000762
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000763 enum LightType {
764 kDistant_LightType,
765 kPoint_LightType,
766 kSpot_LightType,
767 };
768 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000769 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000770 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700771 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000772 return fColor == other.fColor;
773 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700774 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000775
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000776 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000777 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700778 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000779
djsollen@google.com08337772012-06-26 14:33:13 +0000780protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700781 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700782 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
783 SkIntToScalar(SkColorGetG(color)),
784 SkIntToScalar(SkColorGetB(color)));
785 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700786 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000787 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700788 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000789 fColor = readPoint3(buffer);
790 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000791
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000792 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000793
djsollen@google.com08337772012-06-26 14:33:13 +0000794
795private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000796 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000797 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000798};
799
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000800///////////////////////////////////////////////////////////////////////////////
801
robertphillips2f0dbc72015-08-20 05:15:06 -0700802class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000803public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000804 SkDistantLight(const SkPoint3& direction, SkColor color)
805 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000806 }
djsollen@google.com08337772012-06-26 14:33:13 +0000807
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000808 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
809 return fDirection;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400810 }
robertphillips3d32d762015-07-13 13:16:44 -0700811 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700812 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000813 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700814 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000815#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700816 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000817#else
818 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700819 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000820#endif
821 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000822
robertphillips2f0dbc72015-08-20 05:15:06 -0700823 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000824 if (other.type() != kDistant_LightType) {
825 return false;
826 }
827
828 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
829 return INHERITED::isEqual(other) &&
830 fDirection == o.fDirection;
831 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000832
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000833 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000834 fDirection = readPoint3(buffer);
835 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000836
djsollen@google.com08337772012-06-26 14:33:13 +0000837protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000838 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
839 : INHERITED(color), fDirection(direction) {
840 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700841 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000842 return new SkDistantLight(direction(), color());
843 }
mtklein36352bf2015-03-25 18:17:31 -0700844 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000845 writePoint3(fDirection, buffer);
846 }
847
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848private:
849 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700850
851 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000852};
853
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000854///////////////////////////////////////////////////////////////////////////////
855
robertphillips2f0dbc72015-08-20 05:15:06 -0700856class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000857public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000858 SkPointLight(const SkPoint3& location, SkColor color)
859 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000860
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000861 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700862 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
863 fLocation.fY - SkIntToScalar(y),
Mike Reed8be952a2017-02-13 20:44:33 -0500864 fLocation.fZ - SkIntToScalar(z) * surfaceScale);
jvanverth992c7612015-07-17 07:22:30 -0700865 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000866 return direction;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400867 }
robertphillips3d32d762015-07-13 13:16:44 -0700868 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700869 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000870 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700871 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000872#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700873 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000874#else
875 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700876 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000877#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000878 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700879 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000880 if (other.type() != kPoint_LightType) {
881 return false;
882 }
883 const SkPointLight& o = static_cast<const SkPointLight&>(other);
884 return INHERITED::isEqual(other) &&
885 fLocation == o.fLocation;
886 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700887 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000888 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
889 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000890 // Use X scale and Y scale on Z and average the result
891 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
892 matrix.mapVectors(&locationZ, 1);
halcanary9d524f22016-03-29 09:03:52 -0700893 SkPoint3 location = SkPoint3::Make(location2.fX,
894 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700895 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000896 return new SkPointLight(location, color());
897 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000898
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000899 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000900 fLocation = readPoint3(buffer);
901 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000902
903protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000904 SkPointLight(const SkPoint3& location, const SkPoint3& color)
905 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700906 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000907 writePoint3(fLocation, buffer);
908 }
909
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910private:
911 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700912
913 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000914};
915
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000916///////////////////////////////////////////////////////////////////////////////
917
robertphillips2f0dbc72015-08-20 05:15:06 -0700918class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000919public:
senorblancod0d37ca2015-04-02 04:54:56 -0700920 SkSpotLight(const SkPoint3& location,
921 const SkPoint3& target,
922 SkScalar specularExponent,
923 SkScalar cutoffAngle,
924 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000925 : INHERITED(color),
926 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000927 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700928 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000929 {
930 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700931 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000932 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000933 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000934 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
935 fConeScale = SkScalarInvert(antiAliasThreshold);
936 }
djsollen@google.com08337772012-06-26 14:33:13 +0000937
robertphillips2f0dbc72015-08-20 05:15:06 -0700938 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000939 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
940 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000941 // Use X scale and Y scale on Z and average the result
942 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
943 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700944 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
945 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000946 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
947 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000948 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
949 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700950 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
951 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000952 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700953 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700954 return new SkSpotLight(location,
955 target,
956 fSpecularExponent,
957 fCosOuterConeAngle,
958 fCosInnerConeAngle,
959 fConeScale,
960 s,
961 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000962 }
963
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000964 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700965 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
966 fLocation.fY - SkIntToScalar(y),
Mike Reed8be952a2017-02-13 20:44:33 -0500967 fLocation.fZ - SkIntToScalar(z) * surfaceScale);
jvanverth992c7612015-07-17 07:22:30 -0700968 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000969 return direction;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400970 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000971 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000972 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700973 SkScalar scale = 0;
974 if (cosAngle >= fCosOuterConeAngle) {
975 scale = SkScalarPow(cosAngle, fSpecularExponent);
976 if (cosAngle < fCosInnerConeAngle) {
Mike Reed8be952a2017-02-13 20:44:33 -0500977 scale *= (cosAngle - fCosOuterConeAngle) * fConeScale;
robertphillips3d32d762015-07-13 13:16:44 -0700978 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000979 }
robertphillips3d32d762015-07-13 13:16:44 -0700980 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000981 }
mtklein36352bf2015-03-25 18:17:31 -0700982 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000983#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700984 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000985#else
986 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700987 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000988#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000989 }
mtklein36352bf2015-03-25 18:17:31 -0700990 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000991 const SkPoint3& location() const { return fLocation; }
992 const SkPoint3& target() const { return fTarget; }
993 SkScalar specularExponent() const { return fSpecularExponent; }
994 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
995 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
996 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000997 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000998
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000999 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +00001000 fLocation = readPoint3(buffer);
1001 fTarget = readPoint3(buffer);
1002 fSpecularExponent = buffer.readScalar();
1003 fCosOuterConeAngle = buffer.readScalar();
1004 fCosInnerConeAngle = buffer.readScalar();
1005 fConeScale = buffer.readScalar();
1006 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001007 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
1008 SkScalarIsFinite(fCosOuterConeAngle) &&
1009 SkScalarIsFinite(fCosInnerConeAngle) &&
1010 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +00001011 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001012protected:
senorblancod0d37ca2015-04-02 04:54:56 -07001013 SkSpotLight(const SkPoint3& location,
1014 const SkPoint3& target,
1015 SkScalar specularExponent,
1016 SkScalar cosOuterConeAngle,
1017 SkScalar cosInnerConeAngle,
1018 SkScalar coneScale,
1019 const SkPoint3& s,
1020 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001021 : INHERITED(color),
1022 fLocation(location),
1023 fTarget(target),
1024 fSpecularExponent(specularExponent),
1025 fCosOuterConeAngle(cosOuterConeAngle),
1026 fCosInnerConeAngle(cosInnerConeAngle),
1027 fConeScale(coneScale),
1028 fS(s)
1029 {
1030 }
mtklein36352bf2015-03-25 18:17:31 -07001031 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +00001032 writePoint3(fLocation, buffer);
1033 writePoint3(fTarget, buffer);
1034 buffer.writeScalar(fSpecularExponent);
1035 buffer.writeScalar(fCosOuterConeAngle);
1036 buffer.writeScalar(fCosInnerConeAngle);
1037 buffer.writeScalar(fConeScale);
1038 writePoint3(fS, buffer);
1039 }
1040
robertphillips2f0dbc72015-08-20 05:15:06 -07001041 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001042 if (other.type() != kSpot_LightType) {
1043 return false;
1044 }
1045
1046 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1047 return INHERITED::isEqual(other) &&
1048 fLocation == o.fLocation &&
1049 fTarget == o.fTarget &&
1050 fSpecularExponent == o.fSpecularExponent &&
1051 fCosOuterConeAngle == o.fCosOuterConeAngle;
1052 }
1053
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001054private:
caryclark0bccd872015-10-20 10:04:03 -07001055 static const SkScalar kSpecularExponentMin;
1056 static const SkScalar kSpecularExponentMax;
1057
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001058 SkPoint3 fLocation;
1059 SkPoint3 fTarget;
1060 SkScalar fSpecularExponent;
1061 SkScalar fCosOuterConeAngle;
1062 SkScalar fCosInnerConeAngle;
1063 SkScalar fConeScale;
1064 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001065
1066 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001067};
1068
caryclark0bccd872015-10-20 10:04:03 -07001069// According to the spec, the specular term should be in the range [1, 128] :
1070// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1071const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1072const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1073
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001074///////////////////////////////////////////////////////////////////////////////
1075
robertphillips2f0dbc72015-08-20 05:15:06 -07001076void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001077 // Write type first, then baseclass, then subclass.
1078 buffer.writeInt(this->type());
1079 writePoint3(fColor, buffer);
1080 this->onFlattenLight(buffer);
1081}
1082
robertphillips2f0dbc72015-08-20 05:15:06 -07001083/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001084 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001085 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001086 switch (type) {
1087 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1088 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001089 case SkImageFilterLight::kDistant_LightType:
1090 return new SkDistantLight(buffer);
1091 case SkImageFilterLight::kPoint_LightType:
1092 return new SkPointLight(buffer);
1093 case SkImageFilterLight::kSpot_LightType:
1094 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001095 default:
1096 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001097 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001098 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001099 }
1100}
1101///////////////////////////////////////////////////////////////////////////////
1102
robertphillips12fa47d2016-04-08 16:28:09 -07001103SkLightingImageFilter::SkLightingImageFilter(sk_sp<SkImageFilterLight> light,
1104 SkScalar surfaceScale,
1105 sk_sp<SkImageFilter> input, const CropRect* cropRect)
1106 : INHERITED(&input, 1, cropRect)
1107 , fLight(std::move(light))
1108 , fSurfaceScale(surfaceScale / 255) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001109}
1110
robertphillips82b043e2016-04-10 14:04:19 -07001111SkLightingImageFilter::~SkLightingImageFilter() {}
1112
robertphillips12fa47d2016-04-08 16:28:09 -07001113sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitDiffuse(const SkPoint3& direction,
1114 SkColor lightColor,
1115 SkScalar surfaceScale,
1116 SkScalar kd,
1117 sk_sp<SkImageFilter> input,
1118 const CropRect* cropRect) {
1119 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
Mike Kleinfc6c37b2016-09-27 09:34:10 -04001120 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
robertphillips12fa47d2016-04-08 16:28:09 -07001121 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001122}
1123
robertphillips12fa47d2016-04-08 16:28:09 -07001124sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitDiffuse(const SkPoint3& location,
1125 SkColor lightColor,
1126 SkScalar surfaceScale,
1127 SkScalar kd,
1128 sk_sp<SkImageFilter> input,
1129 const CropRect* cropRect) {
1130 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1131 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1132 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001133}
1134
robertphillips12fa47d2016-04-08 16:28:09 -07001135sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitDiffuse(const SkPoint3& location,
1136 const SkPoint3& target,
1137 SkScalar specularExponent,
1138 SkScalar cutoffAngle,
reed9fa60da2014-08-21 07:59:51 -07001139 SkColor lightColor,
1140 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -07001141 SkScalar kd,
1142 sk_sp<SkImageFilter> input,
reed9fa60da2014-08-21 07:59:51 -07001143 const CropRect* cropRect) {
robertphillips12fa47d2016-04-08 16:28:09 -07001144 sk_sp<SkImageFilterLight> light(
halcanary385fe4d2015-08-26 13:07:48 -07001145 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
robertphillips12fa47d2016-04-08 16:28:09 -07001146 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1147 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001148}
1149
robertphillips12fa47d2016-04-08 16:28:09 -07001150sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitSpecular(const SkPoint3& direction,
1151 SkColor lightColor,
1152 SkScalar surfaceScale,
1153 SkScalar ks,
1154 SkScalar shine,
1155 sk_sp<SkImageFilter> input,
1156 const CropRect* cropRect) {
1157 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1158 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1159 std::move(input), cropRect);
1160}
1161
1162sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitSpecular(const SkPoint3& location,
1163 SkColor lightColor,
1164 SkScalar surfaceScale,
1165 SkScalar ks,
1166 SkScalar shine,
1167 sk_sp<SkImageFilter> input,
1168 const CropRect* cropRect) {
1169 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1170 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1171 std::move(input), cropRect);
1172}
1173
1174sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitSpecular(const SkPoint3& location,
1175 const SkPoint3& target,
1176 SkScalar specularExponent,
1177 SkScalar cutoffAngle,
1178 SkColor lightColor,
1179 SkScalar surfaceScale,
1180 SkScalar ks,
1181 SkScalar shine,
1182 sk_sp<SkImageFilter> input,
1183 const CropRect* cropRect) {
1184 sk_sp<SkImageFilterLight> light(
1185 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
1186 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1187 std::move(input), cropRect);
1188}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001189
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001190void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001191 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001192 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001193 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001194}
1195
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001196///////////////////////////////////////////////////////////////////////////////
1197
robertphillips12fa47d2016-04-08 16:28:09 -07001198sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1199 SkScalar surfaceScale,
1200 SkScalar kd,
1201 sk_sp<SkImageFilter> input,
1202 const CropRect* cropRect) {
1203 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001204 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001205 }
1206 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001207 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001208 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001209 // According to the spec, kd can be any non-negative number :
1210 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001211 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001212 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001213 }
Mike Kleinfc6c37b2016-09-27 09:34:10 -04001214 return sk_sp<SkImageFilter>(new SkDiffuseLightingImageFilter(std::move(light), surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -07001215 kd, std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001216}
1217
robertphillips12fa47d2016-04-08 16:28:09 -07001218SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001219 SkScalar surfaceScale,
1220 SkScalar kd,
robertphillips12fa47d2016-04-08 16:28:09 -07001221 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001222 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001223 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1224 , fKD(kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001225}
1226
reed60c9b582016-04-03 09:11:13 -07001227sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001228 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001229 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001230 SkScalar surfaceScale = buffer.readScalar();
1231 SkScalar kd = buffer.readScalar();
robertphillips12fa47d2016-04-08 16:28:09 -07001232 return Make(std::move(light), surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001233}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001234
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001235void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001236 this->INHERITED::flatten(buffer);
1237 buffer.writeScalar(fKD);
1238}
1239
robertphillipsad3dc0d2016-04-15 05:06:11 -07001240sk_sp<SkSpecialImage> SkDiffuseLightingImageFilter::onFilterImage(SkSpecialImage* source,
1241 const Context& ctx,
1242 SkIPoint* offset) const {
1243 SkIPoint inputOffset = SkIPoint::Make(0, 0);
1244 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
1245 if (!input) {
1246 return nullptr;
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001247 }
1248
robertphillipsad3dc0d2016-04-15 05:06:11 -07001249 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1250 input->width(), input->height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001251 SkIRect bounds;
robertphillipsad3dc0d2016-04-15 05:06:11 -07001252 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1253 return nullptr;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001254 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001255
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001256 offset->fX = bounds.left();
1257 offset->fY = bounds.top();
robertphillipsad3dc0d2016-04-15 05:06:11 -07001258 bounds.offset(-inputOffset);
1259
1260#if SK_SUPPORT_GPU
1261 if (source->isTextureBacked()) {
1262 SkMatrix matrix(ctx.ctm());
1263 matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1264
brianosman2a75e5d2016-09-22 07:15:37 -07001265 return this->filterImageGPU(source, input.get(), bounds, matrix, ctx.outputProperties());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001266 }
1267#endif
1268
1269 if (bounds.width() < 2 || bounds.height() < 2) {
1270 return nullptr;
1271 }
1272
1273 SkBitmap inputBM;
1274
1275 if (!input->getROPixels(&inputBM)) {
1276 return nullptr;
1277 }
1278
1279 if (inputBM.colorType() != kN32_SkColorType) {
1280 return nullptr;
1281 }
1282
1283 SkAutoLockPixels alp(inputBM);
1284 if (!inputBM.getPixels()) {
1285 return nullptr;
1286 }
1287
1288 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1289
1290 SkBitmap dst;
1291 if (!dst.tryAllocPixels(info)) {
1292 return nullptr;
1293 }
1294
1295 SkAutoLockPixels dstLock(dst);
1296
1297 SkMatrix matrix(ctx.ctm());
1298 matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1299
1300 sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1301
1302 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001303 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001304 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001305 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001306 transformedLight.get(),
1307 inputBM,
1308 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001309 surfaceScale(),
1310 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001311 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001312 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001313 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001314 transformedLight.get(),
1315 inputBM,
1316 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001317 surfaceScale(),
1318 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001319 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001320 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001321 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001322 transformedLight.get(),
1323 inputBM,
1324 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001325 surfaceScale(),
1326 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001327 break;
1328 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001329
robertphillips3e302272016-04-20 11:48:36 -07001330 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
robertphillipsad3dc0d2016-04-15 05:06:11 -07001331 dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001332}
1333
robertphillipsf3f5bad2014-12-19 13:49:15 -08001334#ifndef SK_IGNORE_TO_STRING
1335void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1336 str->appendf("SkDiffuseLightingImageFilter: (");
1337 str->appendf("kD: %f\n", fKD);
1338 str->append(")");
1339}
1340#endif
1341
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001342#if SK_SUPPORT_GPU
bungeman06ca8ec2016-06-09 08:01:03 -07001343sk_sp<GrFragmentProcessor> SkDiffuseLightingImageFilter::makeFragmentProcessor(
Robert Phillips296b1cc2017-03-15 10:42:12 -04001344 GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001345 sk_sp<GrTextureProxy> proxy,
joshualitt5f10b5c2015-07-09 10:24:35 -07001346 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001347 const SkIRect* srcBounds,
1348 BoundaryMode boundaryMode) const {
Mike Reed8be952a2017-02-13 20:44:33 -05001349 SkScalar scale = this->surfaceScale() * 255;
Robert Phillips296b1cc2017-03-15 10:42:12 -04001350 return GrDiffuseLightingEffect::Make(resourceProvider, std::move(proxy),
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001351 this->light(), scale, matrix, this->kd(),
bungeman06ca8ec2016-06-09 08:01:03 -07001352 boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001353}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001354#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001355
1356///////////////////////////////////////////////////////////////////////////////
1357
robertphillips12fa47d2016-04-08 16:28:09 -07001358sk_sp<SkImageFilter> SkSpecularLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1359 SkScalar surfaceScale,
1360 SkScalar ks,
1361 SkScalar shininess,
1362 sk_sp<SkImageFilter> input,
1363 const CropRect* cropRect) {
1364 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001365 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001366 }
1367 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001368 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001369 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001370 // According to the spec, ks can be any non-negative number :
1371 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001372 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001373 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001374 }
robertphillips12fa47d2016-04-08 16:28:09 -07001375 return sk_sp<SkImageFilter>(new SkSpecularLightingImageFilter(std::move(light), surfaceScale,
1376 ks, shininess,
1377 std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001378}
1379
robertphillips12fa47d2016-04-08 16:28:09 -07001380SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001381 SkScalar surfaceScale,
1382 SkScalar ks,
1383 SkScalar shininess,
robertphillips12fa47d2016-04-08 16:28:09 -07001384 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001385 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001386 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1387 , fKS(ks)
1388 , fShininess(shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001389}
1390
reed60c9b582016-04-03 09:11:13 -07001391sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001392 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001393 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001394 SkScalar surfaceScale = buffer.readScalar();
1395 SkScalar ks = buffer.readScalar();
1396 SkScalar shine = buffer.readScalar();
robertphillips12fa47d2016-04-08 16:28:09 -07001397 return Make(std::move(light), surfaceScale, ks, shine, common.getInput(0),
1398 &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001399}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001400
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001401void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001402 this->INHERITED::flatten(buffer);
1403 buffer.writeScalar(fKS);
1404 buffer.writeScalar(fShininess);
1405}
1406
robertphillipsad3dc0d2016-04-15 05:06:11 -07001407sk_sp<SkSpecialImage> SkSpecularLightingImageFilter::onFilterImage(SkSpecialImage* source,
1408 const Context& ctx,
1409 SkIPoint* offset) const {
1410 SkIPoint inputOffset = SkIPoint::Make(0, 0);
1411 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
1412 if (!input) {
1413 return nullptr;
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001414 }
1415
robertphillipsad3dc0d2016-04-15 05:06:11 -07001416 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1417 input->width(), input->height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001418 SkIRect bounds;
robertphillipsad3dc0d2016-04-15 05:06:11 -07001419 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1420 return nullptr;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001421 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001422
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001423 offset->fX = bounds.left();
1424 offset->fY = bounds.top();
robertphillipsad3dc0d2016-04-15 05:06:11 -07001425 bounds.offset(-inputOffset);
1426
1427#if SK_SUPPORT_GPU
1428 if (source->isTextureBacked()) {
1429 SkMatrix matrix(ctx.ctm());
1430 matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1431
brianosman2a75e5d2016-09-22 07:15:37 -07001432 return this->filterImageGPU(source, input.get(), bounds, matrix, ctx.outputProperties());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001433 }
1434#endif
1435
1436 if (bounds.width() < 2 || bounds.height() < 2) {
1437 return nullptr;
1438 }
1439
1440 SkBitmap inputBM;
1441
1442 if (!input->getROPixels(&inputBM)) {
1443 return nullptr;
1444 }
1445
1446 if (inputBM.colorType() != kN32_SkColorType) {
1447 return nullptr;
1448 }
1449
1450 SkAutoLockPixels alp(inputBM);
1451 if (!inputBM.getPixels()) {
1452 return nullptr;
1453 }
1454
1455 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1456
1457 SkBitmap dst;
1458 if (!dst.tryAllocPixels(info)) {
1459 return nullptr;
1460 }
1461
1462 SkAutoLockPixels dstLock(dst);
1463
1464 SpecularLightingType lightingType(fKS, fShininess);
1465
senorblanco7b7ecfc2015-08-26 14:26:40 -07001466 SkMatrix matrix(ctx.ctm());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001467 matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1468
1469 sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1470
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001471 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001472 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001473 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001474 transformedLight.get(),
1475 inputBM,
1476 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001477 surfaceScale(),
1478 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001479 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001480 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001481 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001482 transformedLight.get(),
1483 inputBM,
1484 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001485 surfaceScale(),
1486 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001487 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001488 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001489 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001490 transformedLight.get(),
1491 inputBM,
1492 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001493 surfaceScale(),
1494 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001495 break;
1496 }
robertphillipsad3dc0d2016-04-15 05:06:11 -07001497
robertphillips3e302272016-04-20 11:48:36 -07001498 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001499}
1500
robertphillipsf3f5bad2014-12-19 13:49:15 -08001501#ifndef SK_IGNORE_TO_STRING
1502void SkSpecularLightingImageFilter::toString(SkString* str) const {
1503 str->appendf("SkSpecularLightingImageFilter: (");
1504 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1505 str->append(")");
1506}
1507#endif
1508
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001509#if SK_SUPPORT_GPU
bungeman06ca8ec2016-06-09 08:01:03 -07001510sk_sp<GrFragmentProcessor> SkSpecularLightingImageFilter::makeFragmentProcessor(
Robert Phillips296b1cc2017-03-15 10:42:12 -04001511 GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001512 sk_sp<GrTextureProxy> proxy,
joshualitt5f10b5c2015-07-09 10:24:35 -07001513 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001514 const SkIRect* srcBounds,
joshualitt5f10b5c2015-07-09 10:24:35 -07001515 BoundaryMode boundaryMode) const {
Mike Reed8be952a2017-02-13 20:44:33 -05001516 SkScalar scale = this->surfaceScale() * 255;
Robert Phillips296b1cc2017-03-15 10:42:12 -04001517 return GrSpecularLightingEffect::Make(resourceProvider, std::move(proxy), this->light(),
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001518 scale, matrix, this->ks(),
bungeman06ca8ec2016-06-09 08:01:03 -07001519 this->shininess(), boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001520}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001521#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001522
1523///////////////////////////////////////////////////////////////////////////////
1524
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001525#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001526
1527namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001528SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001529 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1530 SkScalarToFloat(random->nextSScalar1()),
1531 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001532}
1533
robertphillips2f0dbc72015-08-20 05:15:06 -07001534SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001535 int type = random->nextULessThan(3);
1536 switch (type) {
1537 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001538 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001539 }
1540 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001541 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001542 }
1543 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001544 return new SkSpotLight(random_point3(random), random_point3(random),
1545 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001546 }
1547 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001548 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001549 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001550 }
1551}
1552
senorblancod0d37ca2015-04-02 04:54:56 -07001553SkString emitNormalFunc(BoundaryMode mode,
1554 const char* pointToNormalName,
1555 const char* sobelFuncName) {
1556 SkString result;
1557 switch (mode) {
1558 case kTopLeft_BoundaryMode:
1559 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1560 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1561 "\t surfaceScale);\n",
1562 pointToNormalName, sobelFuncName, gTwoThirds,
1563 sobelFuncName, gTwoThirds);
1564 break;
1565 case kTop_BoundaryMode:
1566 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1567 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1568 "\t surfaceScale);\n",
1569 pointToNormalName, sobelFuncName, gOneThird,
1570 sobelFuncName, gOneHalf);
1571 break;
1572 case kTopRight_BoundaryMode:
1573 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1574 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1575 "\t surfaceScale);\n",
1576 pointToNormalName, sobelFuncName, gTwoThirds,
1577 sobelFuncName, gTwoThirds);
1578 break;
1579 case kLeft_BoundaryMode:
1580 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1581 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1582 "\t surfaceScale);\n",
1583 pointToNormalName, sobelFuncName, gOneHalf,
1584 sobelFuncName, gOneThird);
1585 break;
1586 case kInterior_BoundaryMode:
1587 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1588 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1589 "\t surfaceScale);\n",
1590 pointToNormalName, sobelFuncName, gOneQuarter,
1591 sobelFuncName, gOneQuarter);
1592 break;
1593 case kRight_BoundaryMode:
1594 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1595 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1596 "\t surfaceScale);\n",
1597 pointToNormalName, sobelFuncName, gOneHalf,
1598 sobelFuncName, gOneThird);
1599 break;
1600 case kBottomLeft_BoundaryMode:
1601 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1602 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1603 "\t surfaceScale);\n",
1604 pointToNormalName, sobelFuncName, gTwoThirds,
1605 sobelFuncName, gTwoThirds);
1606 break;
1607 case kBottom_BoundaryMode:
1608 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1609 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1610 "\t surfaceScale);\n",
1611 pointToNormalName, sobelFuncName, gOneThird,
1612 sobelFuncName, gOneHalf);
1613 break;
1614 case kBottomRight_BoundaryMode:
1615 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1616 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1617 "\t surfaceScale);\n",
1618 pointToNormalName, sobelFuncName, gTwoThirds,
1619 sobelFuncName, gTwoThirds);
1620 break;
1621 default:
1622 SkASSERT(false);
1623 break;
1624 }
1625 return result;
1626}
1627
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001628}
1629
Brian Salomon587e08f2017-01-27 10:59:27 -05001630class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001631public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001632 GrGLLightingEffect() : fLight(nullptr) { }
1633 virtual ~GrGLLightingEffect() { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001634
wangyix7c157a92015-07-22 15:08:53 -07001635 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001636
Brian Salomon94efbf52016-11-29 13:43:05 -05001637 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001639protected:
wangyixb1daa862015-08-18 11:29:31 -07001640 /**
1641 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1642 */
egdaniel018fb622015-10-28 07:26:40 -07001643 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001644
egdaniel7ea439b2015-12-03 09:20:44 -08001645 virtual void emitLightFunc(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -08001646 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -08001647 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001648
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001649private:
egdaniel64c47282015-11-13 06:54:19 -08001650 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001651
senorblanco9bd5f742016-02-17 10:59:47 -08001652 UniformHandle fImageIncrementUni;
1653 UniformHandle fSurfaceScaleUni;
1654 GrTextureDomain::GLDomain fDomain;
1655 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001656};
1657
1658///////////////////////////////////////////////////////////////////////////////
1659
1660class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1661public:
cdalton85285412016-02-18 12:37:07 -08001662 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001663
1664protected:
egdaniel018fb622015-10-28 07:26:40 -07001665 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001666
1667private:
1668 typedef GrGLLightingEffect INHERITED;
1669
bsalomon@google.com032b2212012-07-16 13:36:18 +00001670 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001671};
1672
1673///////////////////////////////////////////////////////////////////////////////
1674
1675class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1676public:
cdalton85285412016-02-18 12:37:07 -08001677 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001678
1679protected:
egdaniel018fb622015-10-28 07:26:40 -07001680 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001681
1682private:
1683 typedef GrGLLightingEffect INHERITED;
1684
bsalomon@google.com032b2212012-07-16 13:36:18 +00001685 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001686 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001687};
1688
1689///////////////////////////////////////////////////////////////////////////////
1690
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001691static GrTextureDomain create_domain(GrTextureProxy* proxy, const SkIRect* srcBounds,
Robert Phillipse98234f2017-01-09 14:23:59 -05001692 GrTextureDomain::Mode mode) {
senorblanco9bd5f742016-02-17 10:59:47 -08001693 if (srcBounds) {
Robert Phillipse98234f2017-01-09 14:23:59 -05001694 SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(*srcBounds, mode);
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001695 return GrTextureDomain(proxy, texelDomain, mode);
senorblanco9bd5f742016-02-17 10:59:47 -08001696 } else {
Robert Phillipse98234f2017-01-09 14:23:59 -05001697 return GrTextureDomain::IgnoredDomain();
senorblanco9bd5f742016-02-17 10:59:47 -08001698 }
1699}
1700
Robert Phillips296b1cc2017-03-15 10:42:12 -04001701GrLightingEffect::GrLightingEffect(GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001702 sk_sp<GrTextureProxy> proxy,
robertphillips2f0dbc72015-08-20 05:15:06 -07001703 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001704 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001705 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001706 BoundaryMode boundaryMode,
1707 const SkIRect* srcBounds)
Brian Salomonf3b995b2017-02-15 10:22:23 -05001708 // Perhaps this could advertise the opaque or coverage-as-alpha optimizations?
Robert Phillips296b1cc2017-03-15 10:42:12 -04001709 : INHERITED(resourceProvider, kNone_OptimizationFlags, proxy, nullptr, SkMatrix::I())
Brian Salomon587e08f2017-01-27 10:59:27 -05001710 , fLight(light)
1711 , fSurfaceScale(surfaceScale)
1712 , fFilterMatrix(matrix)
1713 , fBoundaryMode(boundaryMode)
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001714 , fDomain(create_domain(proxy.get(), srcBounds, GrTextureDomain::kDecal_Mode)) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001715 fLight->ref();
1716}
1717
1718GrLightingEffect::~GrLightingEffect() {
1719 fLight->unref();
1720}
1721
bsalomon0e08fc12014-10-15 08:19:04 -07001722bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001723 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001724 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001725 fSurfaceScale == s.fSurfaceScale &&
1726 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001727}
1728
1729///////////////////////////////////////////////////////////////////////////////
1730
Robert Phillips296b1cc2017-03-15 10:42:12 -04001731GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001732 sk_sp<GrTextureProxy> proxy,
robertphillips2f0dbc72015-08-20 05:15:06 -07001733 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001734 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001735 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001736 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -08001737 BoundaryMode boundaryMode,
1738 const SkIRect* srcBounds)
Robert Phillips296b1cc2017-03-15 10:42:12 -04001739 : INHERITED(resourceProvider, std::move(proxy), light, surfaceScale, matrix,
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001740 boundaryMode, srcBounds), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001741 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001742}
1743
bsalomon0e08fc12014-10-15 08:19:04 -07001744bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001745 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001746 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001747}
1748
Brian Salomon94efbf52016-11-29 13:43:05 -05001749void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001750 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001751 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1752}
1753
egdaniel57d3b032015-11-13 11:57:27 -08001754GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001755 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001756}
1757
joshualittb0a8a372014-09-23 09:50:21 -07001758GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001759
Hal Canary6f6961e2017-01-31 13:50:44 -05001760#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -07001761sk_sp<GrFragmentProcessor> GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001762 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
1763 : GrProcessorUnitTest::kAlphaTextureIdx;
1764 sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
joshualitt0067ff52015-07-08 14:26:19 -07001765 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1766 SkScalar kd = d->fRandom->nextUScalar1();
Hal Canary67b39de2016-11-07 11:47:44 -05001767 sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001768 SkMatrix matrix;
1769 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001770 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001771 }
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001772 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()),
1773 d->fRandom->nextRangeU(0, proxy->height()),
1774 d->fRandom->nextRangeU(0, proxy->width()),
1775 d->fRandom->nextRangeU(0, proxy->height()));
joshualitt0067ff52015-07-08 14:26:19 -07001776 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
Robert Phillips296b1cc2017-03-15 10:42:12 -04001777 return GrDiffuseLightingEffect::Make(d->resourceProvider(),
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001778 std::move(proxy), light.get(), surfaceScale,
1779 matrix, kd, mode, &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001780}
Hal Canary6f6961e2017-01-31 13:50:44 -05001781#endif
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001782
1783
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001784///////////////////////////////////////////////////////////////////////////////
1785
wangyix7c157a92015-07-22 15:08:53 -07001786void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001787 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1788 if (!fLight) {
1789 fLight = le.light()->createGLLight();
1790 }
1791
egdaniel7ea439b2015-12-03 09:20:44 -08001792 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
cdalton5e58cee2016-02-11 12:49:47 -08001793 fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001794 kVec2f_GrSLType, kDefault_GrSLPrecision,
1795 "ImageIncrement");
cdalton5e58cee2016-02-11 12:49:47 -08001796 fSurfaceScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001797 kFloat_GrSLType, kDefault_GrSLPrecision,
1798 "SurfaceScale");
1799 fLight->emitLightColorUniform(uniformHandler);
cdalton85285412016-02-18 12:37:07 -08001800 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001801 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001802 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
Brian Salomon99938a82016-11-21 13:41:08 -05001803 static const GrShaderVar gSobelArgs[] = {
1804 GrShaderVar("a", kFloat_GrSLType),
1805 GrShaderVar("b", kFloat_GrSLType),
1806 GrShaderVar("c", kFloat_GrSLType),
1807 GrShaderVar("d", kFloat_GrSLType),
1808 GrShaderVar("e", kFloat_GrSLType),
1809 GrShaderVar("f", kFloat_GrSLType),
1810 GrShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001811 };
1812 SkString sobelFuncName;
bsalomon1a1aa932016-09-12 09:30:36 -07001813 SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
joshualitt30ba4362014-08-21 20:18:45 -07001814
egdaniel4ca2e602015-11-18 08:01:26 -08001815 fragBuilder->emitFunction(kFloat_GrSLType,
1816 "sobel",
1817 SK_ARRAY_COUNT(gSobelArgs),
1818 gSobelArgs,
1819 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1820 &sobelFuncName);
Brian Salomon99938a82016-11-21 13:41:08 -05001821 static const GrShaderVar gPointToNormalArgs[] = {
1822 GrShaderVar("x", kFloat_GrSLType),
1823 GrShaderVar("y", kFloat_GrSLType),
1824 GrShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001825 };
1826 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001827 fragBuilder->emitFunction(kVec3f_GrSLType,
1828 "pointToNormal",
1829 SK_ARRAY_COUNT(gPointToNormalArgs),
1830 gPointToNormalArgs,
1831 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1832 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001833
Brian Salomon99938a82016-11-21 13:41:08 -05001834 static const GrShaderVar gInteriorNormalArgs[] = {
1835 GrShaderVar("m", kFloat_GrSLType, 9),
1836 GrShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001837 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001838 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001839 pointToNormalName.c_str(),
1840 sobelFuncName.c_str());
1841 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001842 fragBuilder->emitFunction(kVec3f_GrSLType,
1843 "normal",
1844 SK_ARRAY_COUNT(gInteriorNormalArgs),
1845 gInteriorNormalArgs,
1846 normalBody.c_str(),
1847 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001848
egdaniel4ca2e602015-11-18 08:01:26 -08001849 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1850 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001851
egdaniel7ea439b2015-12-03 09:20:44 -08001852 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1853 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001854
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001855 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001856 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001857 for (int dx = -1; dx <= 1; dx++) {
1858 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001859 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco9bd5f742016-02-17 10:59:47 -08001860 SkString temp;
1861 temp.appendf("temp%d", index);
1862 fragBuilder->codeAppendf("vec4 %s;", temp.c_str());
1863 fDomain.sampleTexture(fragBuilder,
1864 args.fUniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -05001865 args.fShaderCaps,
senorblanco9bd5f742016-02-17 10:59:47 -08001866 le.domain(),
1867 temp.c_str(),
1868 texCoords,
cdalton3f6f76f2016-04-11 12:18:09 -07001869 args.fTexSamplers[0]);
senorblanco9bd5f742016-02-17 10:59:47 -08001870 fragBuilder->codeAppendf("m[%d] = %s.a;", index, temp.c_str());
1871 index++;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001872 }
1873 }
egdaniel4ca2e602015-11-18 08:01:26 -08001874 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001875 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001876 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001877 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001878 fragBuilder->codeAppend(";\n");
1879 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1880 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001881 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001882 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001883 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001884 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001885 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001886}
1887
joshualittb0a8a372014-09-23 09:50:21 -07001888void GrGLLightingEffect::GenKey(const GrProcessor& proc,
Brian Salomon94efbf52016-11-29 13:43:05 -05001889 const GrShaderCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001890 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1891 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco9bd5f742016-02-17 10:59:47 -08001892 b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001893}
1894
egdaniel018fb622015-10-28 07:26:40 -07001895void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1896 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001897 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001898 if (!fLight) {
1899 fLight = lighting.light()->createGLLight();
1900 }
1901
Brian Salomondb4183d2016-11-17 12:48:40 -05001902 GrTexture* texture = lighting.textureSampler(0).texture();
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001903 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001904 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1905 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
Hal Canary67b39de2016-11-07 11:47:44 -05001906 sk_sp<SkImageFilterLight> transformedLight(
1907 lighting.light()->transform(lighting.filterMatrix()));
Robert Phillipse98234f2017-01-09 14:23:59 -05001908 fDomain.setData(pdman, lighting.domain(), texture);
Hal Canary67b39de2016-11-07 11:47:44 -05001909 fLight->setData(pdman, transformedLight.get());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001910}
1911
1912///////////////////////////////////////////////////////////////////////////////
1913
1914///////////////////////////////////////////////////////////////////////////////
1915
egdaniel7ea439b2015-12-03 09:20:44 -08001916void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001917 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001918 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001919 const char* kd;
cdalton5e58cee2016-02-11 12:49:47 -08001920 fKDUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
bsalomon422f56f2014-12-09 10:18:12 -08001921 kFloat_GrSLType, kDefault_GrSLPrecision,
1922 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001923
Brian Salomon99938a82016-11-21 13:41:08 -05001924 static const GrShaderVar gLightArgs[] = {
1925 GrShaderVar("normal", kVec3f_GrSLType),
1926 GrShaderVar("surfaceToLight", kVec3f_GrSLType),
1927 GrShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001928 };
1929 SkString lightBody;
1930 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1931 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001932 fragBuilder->emitFunction(kVec4f_GrSLType,
1933 "light",
1934 SK_ARRAY_COUNT(gLightArgs),
1935 gLightArgs,
1936 lightBody.c_str(),
1937 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001938}
1939
egdaniel018fb622015-10-28 07:26:40 -07001940void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1941 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001942 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001943 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001944 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001945}
1946
1947///////////////////////////////////////////////////////////////////////////////
1948
Robert Phillips296b1cc2017-03-15 10:42:12 -04001949GrSpecularLightingEffect::GrSpecularLightingEffect(GrResourceProvider* resourceProvider,
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001950 sk_sp<GrTextureProxy> proxy,
robertphillips2f0dbc72015-08-20 05:15:06 -07001951 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001952 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001953 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001954 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001955 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -08001956 BoundaryMode boundaryMode,
1957 const SkIRect* srcBounds)
Robert Phillips296b1cc2017-03-15 10:42:12 -04001958 : INHERITED(resourceProvider, std::move(proxy), light, surfaceScale,
1959 matrix, boundaryMode, srcBounds)
robertphillips2f0dbc72015-08-20 05:15:06 -07001960 , fKS(ks)
1961 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001962 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001963}
1964
bsalomon0e08fc12014-10-15 08:19:04 -07001965bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001966 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001967 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001968 this->ks() == s.ks() &&
1969 this->shininess() == s.shininess();
1970}
1971
Brian Salomon94efbf52016-11-29 13:43:05 -05001972void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001973 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001974 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1975}
1976
egdaniel57d3b032015-11-13 11:57:27 -08001977GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001978 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001979}
1980
joshualittb0a8a372014-09-23 09:50:21 -07001981GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001982
Hal Canary6f6961e2017-01-31 13:50:44 -05001983#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -07001984sk_sp<GrFragmentProcessor> GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001985 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
1986 : GrProcessorUnitTest::kAlphaTextureIdx;
1987 sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
joshualitt0067ff52015-07-08 14:26:19 -07001988 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1989 SkScalar ks = d->fRandom->nextUScalar1();
1990 SkScalar shininess = d->fRandom->nextUScalar1();
Hal Canary67b39de2016-11-07 11:47:44 -05001991 sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001992 SkMatrix matrix;
1993 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001994 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001995 }
joshualitt0067ff52015-07-08 14:26:19 -07001996 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001997 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()),
1998 d->fRandom->nextRangeU(0, proxy->height()),
1999 d->fRandom->nextRangeU(0, proxy->width()),
2000 d->fRandom->nextRangeU(0, proxy->height()));
Robert Phillips296b1cc2017-03-15 10:42:12 -04002001 return GrSpecularLightingEffect::Make(d->resourceProvider(), std::move(proxy),
Hal Canary67b39de2016-11-07 11:47:44 -05002002 light.get(), surfaceScale, matrix, ks, shininess, mode,
bungeman06ca8ec2016-06-09 08:01:03 -07002003 &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002004}
Hal Canary6f6961e2017-01-31 13:50:44 -05002005#endif
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002006
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002007///////////////////////////////////////////////////////////////////////////////
2008
egdaniel7ea439b2015-12-03 09:20:44 -08002009void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002010 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002011 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002012 const char* ks;
2013 const char* shininess;
2014
cdalton5e58cee2016-02-11 12:49:47 -08002015 fKSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002016 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
cdalton5e58cee2016-02-11 12:49:47 -08002017 fShininessUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002018 kFloat_GrSLType,
2019 kDefault_GrSLPrecision,
2020 "Shininess",
2021 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002022
Brian Salomon99938a82016-11-21 13:41:08 -05002023 static const GrShaderVar gLightArgs[] = {
2024 GrShaderVar("normal", kVec3f_GrSLType),
2025 GrShaderVar("surfaceToLight", kVec3f_GrSLType),
2026 GrShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002027 };
2028 SkString lightBody;
2029 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
Brian Osman9bc39bb2017-03-17 09:36:31 -04002030 lightBody.appendf("\thighp float colorScale = %s * pow(dot(normal, halfDir), %s);\n",
2031 ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00002032 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
2033 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08002034 fragBuilder->emitFunction(kVec4f_GrSLType,
2035 "light",
2036 SK_ARRAY_COUNT(gLightArgs),
2037 gLightArgs,
2038 lightBody.c_str(),
2039 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002040}
2041
egdaniel018fb622015-10-28 07:26:40 -07002042void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
2043 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07002044 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07002045 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07002046 pdman.set1f(fKSUni, spec.ks());
2047 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002048}
2049
2050///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08002051void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
cdalton5e58cee2016-02-11 12:49:47 -08002052 fColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002053 kVec3f_GrSLType, kDefault_GrSLPrecision,
2054 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002055}
2056
egdaniel7ea439b2015-12-03 09:20:44 -08002057void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002058 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002059 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08002060 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002061}
2062
egdaniel018fb622015-10-28 07:26:40 -07002063void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002064 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07002065 setUniformPoint3(pdman, fColorUni,
2066 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002067}
2068
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002069///////////////////////////////////////////////////////////////////////////////
2070
egdaniel018fb622015-10-28 07:26:40 -07002071void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002072 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002073 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002074 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002075 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002076 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002077}
2078
egdaniel7ea439b2015-12-03 09:20:44 -08002079void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002080 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002081 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002082 const char* dir;
cdalton5e58cee2016-02-11 12:49:47 -08002083 fDirectionUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002084 kVec3f_GrSLType, kDefault_GrSLPrecision,
2085 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08002086 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002087}
2088
2089///////////////////////////////////////////////////////////////////////////////
2090
egdaniel018fb622015-10-28 07:26:40 -07002091void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002092 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002093 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002094 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002095 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002096 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002097}
2098
egdaniel7ea439b2015-12-03 09:20:44 -08002099void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002100 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002101 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002102 const char* loc;
cdalton5e58cee2016-02-11 12:49:47 -08002103 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002104 kVec3f_GrSLType, kDefault_GrSLPrecision,
2105 "LightLocation", &loc);
Ethan Nicholas38657112017-02-09 17:01:22 -05002106 fragBuilder->codeAppendf("normalize(%s - vec3(sk_FragCoord.xy, %s))",
2107 loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002108}
2109
2110///////////////////////////////////////////////////////////////////////////////
2111
egdaniel018fb622015-10-28 07:26:40 -07002112void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002113 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002114 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002115 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002116 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002117 setUniformPoint3(pdman, fLocationUni, spotLight->location());
2118 pdman.set1f(fExponentUni, spotLight->specularExponent());
2119 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
2120 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
2121 pdman.set1f(fConeScaleUni, spotLight->coneScale());
2122 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002123}
2124
egdaniel7ea439b2015-12-03 09:20:44 -08002125void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002126 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002127 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002128 const char* location;
cdalton5e58cee2016-02-11 12:49:47 -08002129 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002130 kVec3f_GrSLType, kDefault_GrSLPrecision,
2131 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07002132
Ethan Nicholas38657112017-02-09 17:01:22 -05002133 fragBuilder->codeAppendf("normalize(%s - vec3(sk_FragCoord.xy, %s))",
2134 location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002135}
2136
egdaniel7ea439b2015-12-03 09:20:44 -08002137void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002138 GrGLSLFPFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002139 const char *surfaceToLight) {
2140
egdaniel7ea439b2015-12-03 09:20:44 -08002141 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002142
2143 const char* exponent;
2144 const char* cosInner;
2145 const char* cosOuter;
2146 const char* coneScale;
2147 const char* s;
cdalton5e58cee2016-02-11 12:49:47 -08002148 fExponentUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002149 kFloat_GrSLType, kDefault_GrSLPrecision,
2150 "Exponent", &exponent);
cdalton5e58cee2016-02-11 12:49:47 -08002151 fCosInnerConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002152 kFloat_GrSLType, kDefault_GrSLPrecision,
2153 "CosInnerConeAngle", &cosInner);
cdalton5e58cee2016-02-11 12:49:47 -08002154 fCosOuterConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002155 kFloat_GrSLType, kDefault_GrSLPrecision,
2156 "CosOuterConeAngle", &cosOuter);
cdalton5e58cee2016-02-11 12:49:47 -08002157 fConeScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002158 kFloat_GrSLType, kDefault_GrSLPrecision,
2159 "ConeScale", &coneScale);
cdalton5e58cee2016-02-11 12:49:47 -08002160 fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002161 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002162
Brian Salomon99938a82016-11-21 13:41:08 -05002163 static const GrShaderVar gLightColorArgs[] = {
2164 GrShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002165 };
2166 SkString lightColorBody;
2167 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2168 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2169 lightColorBody.appendf("\t\treturn vec3(0);\n");
2170 lightColorBody.appendf("\t}\n");
2171 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2172 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2173 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2174 color, cosOuter, coneScale);
2175 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002176 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002177 fragBuilder->emitFunction(kVec3f_GrSLType,
2178 "lightColor",
2179 SK_ARRAY_COUNT(gLightColorArgs),
2180 gLightColorArgs,
2181 lightColorBody.c_str(),
2182 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002183
egdaniel4ca2e602015-11-18 08:01:26 -08002184 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002185}
2186
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002187#endif
2188
djsollen@google.com08337772012-06-26 14:33:13 +00002189SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2190 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2191 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002192SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END