blob: b37fc28b2a6961554e7054a385ee002901c5ac33 [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"
robertphillipsea461502015-05-26 11:38:03 -070019#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
21#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070022#include "GrPaint.h"
robertphillips1de87df2016-01-14 06:03:29 -080023#include "SkGr.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000024#include "effects/GrSingleTextureEffect.h"
senorblanco9bd5f742016-02-17 10:59:47 -080025#include "effects/GrTextureDomain.h"
egdaniel64c47282015-11-13 06:54:19 -080026#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080027#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070028#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080029#include "glsl/GrGLSLUniformHandler.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000030
31class GrGLDiffuseLightingEffect;
32class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000033
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000034// For brevity
egdaniel018fb622015-10-28 07:26:40 -070035typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000036#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000037
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000038namespace {
39
reed80ea19c2015-05-12 10:37:34 -070040const SkScalar gOneThird = SkIntToScalar(1) / 3;
41const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000042const SkScalar gOneHalf = 0.5f;
43const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000044
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000045#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070046void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070047 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070048 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070049 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000050}
51
egdaniel018fb622015-10-28 07:26:40 -070052void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070053 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070054 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000055}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000056#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000057
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000058// Shift matrix components to the left, as we advance pixels to the right.
59inline void shiftMatrixLeft(int m[9]) {
60 m[0] = m[1];
61 m[3] = m[4];
62 m[6] = m[7];
63 m[1] = m[2];
64 m[4] = m[5];
65 m[7] = m[8];
66}
67
jvanverth992c7612015-07-17 07:22:30 -070068static inline void fast_normalize(SkPoint3* vector) {
69 // add a tiny bit so we don't have to worry about divide-by-zero
70 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
71 SkScalar scale = sk_float_rsqrt(magSq);
72 vector->fX *= scale;
73 vector->fY *= scale;
74 vector->fZ *= scale;
75}
76
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000077class DiffuseLightingType {
78public:
79 DiffuseLightingType(SkScalar kd)
80 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070081 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
82 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000083 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
84 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070085 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000086 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000087 SkClampMax(SkScalarRoundToInt(color.fX), 255),
88 SkClampMax(SkScalarRoundToInt(color.fY), 255),
89 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000090 }
91private:
92 SkScalar fKD;
93};
94
robertphillips3d32d762015-07-13 13:16:44 -070095static SkScalar max_component(const SkPoint3& p) {
96 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
97}
98
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000099class SpecularLightingType {
100public:
101 SpecularLightingType(SkScalar ks, SkScalar shininess)
102 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700103 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
104 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000105 SkPoint3 halfDir(surfaceTolight);
106 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700107 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000108 SkScalar colorScale = SkScalarMul(fKS,
109 SkScalarPow(normal.dot(halfDir), fShininess));
110 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700111 SkPoint3 color = lightColor.makeScale(colorScale);
112 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000113 SkClampMax(SkScalarRoundToInt(color.fX), 255),
114 SkClampMax(SkScalarRoundToInt(color.fY), 255),
115 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000116 }
117private:
118 SkScalar fKS;
119 SkScalar fShininess;
120};
121
122inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
123 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
124}
125
126inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700127 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
128 SkScalarMul(-y, surfaceScale),
129 SK_Scalar1);
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
robertphillipsad3dc0d2016-04-15 05:06:11 -0700358 sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source,
359 SkSpecialImage* input,
360 const SkIRect& bounds,
361 const SkMatrix& matrix) const;
bsalomon4a339522015-10-06 08:40:50 -0700362 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700363 const SkMatrix&,
senorblanco9bd5f742016-02-17 10:59:47 -0800364 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700365 BoundaryMode boundaryMode) const = 0;
366#endif
367private:
368#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700369 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700370 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700371 const SkMatrix& matrix,
372 const GrClip& clip,
373 const SkRect& dstRect,
374 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800375 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700376 const SkIRect& bounds) const;
377#endif
378 typedef SkLightingImageFilter INHERITED;
379};
380
381#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700382void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700383 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700384 const SkMatrix& matrix,
385 const GrClip& clip,
386 const SkRect& dstRect,
387 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800388 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700389 const SkIRect& bounds) const {
390 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700391 GrPaint paint;
brianosman898235c2016-04-06 07:38:23 -0700392 // SRGBTODO: AllowSRGBInputs?
senorblanco9bd5f742016-02-17 10:59:47 -0800393 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, srcBounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700394 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800395 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800396 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700397}
398
robertphillipsad3dc0d2016-04-15 05:06:11 -0700399sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(SkSpecialImage* source,
400 SkSpecialImage* input,
401 const SkIRect& offsetBounds,
402 const SkMatrix& matrix) const {
403 SkASSERT(source->isTextureBacked());
404
405 GrContext* context = source->getContext();
406
407 sk_sp<GrTexture> inputTexture(input->asTextureRef(context));
408 SkASSERT(inputTexture);
senorblancod0d37ca2015-04-02 04:54:56 -0700409
410 GrSurfaceDesc desc;
411 desc.fFlags = kRenderTarget_GrSurfaceFlag,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700412 desc.fWidth = offsetBounds.width();
413 desc.fHeight = offsetBounds.height();
senorblancod0d37ca2015-04-02 04:54:56 -0700414 desc.fConfig = kRGBA_8888_GrPixelConfig;
415
robertphillipsad3dc0d2016-04-15 05:06:11 -0700416 sk_sp<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700417 if (!dst) {
robertphillipsad3dc0d2016-04-15 05:06:11 -0700418 return nullptr;
senorblancod0d37ca2015-04-02 04:54:56 -0700419 }
420
robertphillipsad3dc0d2016-04-15 05:06:11 -0700421 sk_sp<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
422 if (!drawContext) {
423 return nullptr;
424 }
425
426 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(offsetBounds.width()),
427 SkIntToScalar(offsetBounds.height()));
428
senorblancod0d37ca2015-04-02 04:54:56 -0700429 // setup new clip
430 GrClip clip(dstRect);
431
robertphillipsad3dc0d2016-04-15 05:06:11 -0700432 const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
senorblancod0d37ca2015-04-02 04:54:56 -0700433 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
434 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
435 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
436 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
437 SkRect interior = dstRect.makeInset(1, 1);
438 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
439 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
440 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
441 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700442
robertphillipsad3dc0d2016-04-15 05:06:11 -0700443 const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds;
444 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, topLeft,
445 kTopLeft_BoundaryMode, pSrcBounds, offsetBounds);
446 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, top, kTop_BoundaryMode,
447 pSrcBounds, offsetBounds);
448 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, topRight,
449 kTopRight_BoundaryMode, pSrcBounds, offsetBounds);
450 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, left, kLeft_BoundaryMode,
451 pSrcBounds, offsetBounds);
452 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, interior,
453 kInterior_BoundaryMode, pSrcBounds, offsetBounds);
454 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, right, kRight_BoundaryMode,
455 pSrcBounds, offsetBounds);
456 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, bottomLeft,
457 kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds);
458 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, bottom,
459 kBottom_BoundaryMode, pSrcBounds, offsetBounds);
460 this->drawRect(drawContext.get(), inputTexture.get(), matrix, clip, bottomRight,
461 kBottomRight_BoundaryMode, pSrcBounds, offsetBounds);
robertphillipsea461502015-05-26 11:38:03 -0700462
robertphillipsad3dc0d2016-04-15 05:06:11 -0700463 return SkSpecialImage::MakeFromGpu(source->internal_getProxy(),
464 SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()),
465 kNeedNewImageUniqueID_SpecialImage,
466 dst.get());
senorblancod0d37ca2015-04-02 04:54:56 -0700467}
468#endif
469
470class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471public:
robertphillips12fa47d2016-04-08 16:28:09 -0700472 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
473 SkScalar surfaceScale,
474 SkScalar kd,
475 sk_sp<SkImageFilter>,
476 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700477
robertphillipsf3f5bad2014-12-19 13:49:15 -0800478 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000480 SkScalar kd() const { return fKD; }
481
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000482protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700483 SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, SkScalar surfaceScale,
484 SkScalar kd,
485 sk_sp<SkImageFilter> input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700486 void flatten(SkWriteBuffer& buffer) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700487
488 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
489 SkIPoint* offset) const override;
490
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000491#if SK_SUPPORT_GPU
senorblanco9bd5f742016-02-17 10:59:47 -0800492 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect* bounds,
bsalomon4a339522015-10-06 08:40:50 -0700493 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000494#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000495
496private:
reed9fa60da2014-08-21 07:59:51 -0700497 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000498 SkScalar fKD;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700499
500 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501};
502
senorblancod0d37ca2015-04-02 04:54:56 -0700503class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000504public:
robertphillips12fa47d2016-04-08 16:28:09 -0700505 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
506 SkScalar surfaceScale,
507 SkScalar ks, SkScalar shininess,
508 sk_sp<SkImageFilter>, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700509
robertphillipsf3f5bad2014-12-19 13:49:15 -0800510 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000511 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
512
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000513 SkScalar ks() const { return fKS; }
514 SkScalar shininess() const { return fShininess; }
515
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000516protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700517 SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
518 SkScalar surfaceScale, SkScalar ks,
519 SkScalar shininess,
520 sk_sp<SkImageFilter> input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700521 void flatten(SkWriteBuffer& buffer) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700522
523 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
524 SkIPoint* offset) const override;
525
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000526#if SK_SUPPORT_GPU
senorblanco9bd5f742016-02-17 10:59:47 -0800527 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect* bounds,
bsalomon4a339522015-10-06 08:40:50 -0700528 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000529#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000530
531private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000532 SkScalar fKS;
533 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700534 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700535 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000536};
537
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000538#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000539
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000540class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000541public:
bsalomon4a339522015-10-06 08:40:50 -0700542 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco9bd5f742016-02-17 10:59:47 -0800543 const SkMatrix& matrix, BoundaryMode boundaryMode, const SkIRect* srcBounds);
robertphillipse004bfc2015-11-16 09:06:59 -0800544 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000545
robertphillips2f0dbc72015-08-20 05:15:06 -0700546 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000547 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000548 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700549 BoundaryMode boundaryMode() const { return fBoundaryMode; }
senorblanco9bd5f742016-02-17 10:59:47 -0800550 const GrTextureDomain& domain() const { return fDomain; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000551
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000552protected:
mtklein36352bf2015-03-25 18:17:31 -0700553 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000554
mtklein36352bf2015-03-25 18:17:31 -0700555 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700556 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800557 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700558 }
559
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000560private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700561 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000562 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000563 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700564 BoundaryMode fBoundaryMode;
senorblanco9bd5f742016-02-17 10:59:47 -0800565 GrTextureDomain fDomain;
robertphillips2f0dbc72015-08-20 05:15:06 -0700566
567 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000568};
569
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000570class GrDiffuseLightingEffect : public GrLightingEffect {
571public:
bsalomon4a339522015-10-06 08:40:50 -0700572 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700573 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700574 SkScalar surfaceScale,
575 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700576 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800577 BoundaryMode boundaryMode,
578 const SkIRect* srcBounds) {
579 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode,
580 srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000581 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000582
mtklein36352bf2015-03-25 18:17:31 -0700583 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000584
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000585 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000586
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000587private:
egdaniel57d3b032015-11-13 11:57:27 -0800588 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700589
egdaniel57d3b032015-11-13 11:57:27 -0800590 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700591
mtklein36352bf2015-03-25 18:17:31 -0700592 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000593
bsalomon4a339522015-10-06 08:40:50 -0700594 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700595 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000596 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000597 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700598 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800599 BoundaryMode boundaryMode,
600 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000601
joshualittb0a8a372014-09-23 09:50:21 -0700602 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000603 typedef GrLightingEffect INHERITED;
604 SkScalar fKD;
605};
606
607class GrSpecularLightingEffect : public GrLightingEffect {
608public:
bsalomon4a339522015-10-06 08:40:50 -0700609 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700610 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700611 SkScalar surfaceScale,
612 const SkMatrix& matrix,
613 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700614 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800615 BoundaryMode boundaryMode,
616 const SkIRect* srcBounds) {
bsalomon4a339522015-10-06 08:40:50 -0700617 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800618 boundaryMode, srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000619 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000620
mtklein36352bf2015-03-25 18:17:31 -0700621 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000622
egdaniel57d3b032015-11-13 11:57:27 -0800623 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800624
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625 SkScalar ks() const { return fKS; }
626 SkScalar shininess() const { return fShininess; }
627
628private:
egdaniel57d3b032015-11-13 11:57:27 -0800629 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700630
mtklein36352bf2015-03-25 18:17:31 -0700631 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000632
bsalomon4a339522015-10-06 08:40:50 -0700633 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700634 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000635 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000636 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000637 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700638 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800639 BoundaryMode boundaryMode,
640 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000641
joshualittb0a8a372014-09-23 09:50:21 -0700642 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000643 typedef GrLightingEffect INHERITED;
644 SkScalar fKS;
645 SkScalar fShininess;
646};
647
648///////////////////////////////////////////////////////////////////////////////
649
650class GrGLLight {
651public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000652 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000653
654 /**
655 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
656 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
657 */
egdaniel7ea439b2015-12-03 09:20:44 -0800658 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000659
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000660 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000661 * These two functions are called from GrGLLightingEffect's emitCode() function.
662 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
663 * the light. The expression will be used in the FS. emitLightColor writes an expression into
664 * the FS that is the color of the light. Either function may add functions and/or uniforms to
665 * the FS. The default of emitLightColor appends the name of the constant light color uniform
666 * and so this function only needs to be overridden if the light color varies spatially.
667 */
egdaniel7ea439b2015-12-03 09:20:44 -0800668 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800669 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -0800670 const char* z) = 0;
671 virtual void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800672 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800673 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000674
675 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
676 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700677 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000678
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000679protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000680 /**
681 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
682 * function.
683 */
684 UniformHandle lightColorUni() const { return fColorUni; }
685
686private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000687 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000688
689 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000690};
691
692///////////////////////////////////////////////////////////////////////////////
693
694class GrGLDistantLight : public GrGLLight {
695public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000696 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700697 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800698 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000699
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000700private:
701 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000702 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000703};
704
705///////////////////////////////////////////////////////////////////////////////
706
707class GrGLPointLight : public GrGLLight {
708public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000709 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700710 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800711 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000712
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000713private:
714 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000715 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000716};
717
718///////////////////////////////////////////////////////////////////////////////
719
720class GrGLSpotLight : public GrGLLight {
721public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000722 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700723 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800724 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
egdaniel7ea439b2015-12-03 09:20:44 -0800725 void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800726 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800727 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000728
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000729private:
730 typedef GrGLLight INHERITED;
731
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000732 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000733 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000734 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000735 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000736 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000737 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000738 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000739};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000740#else
741
742class GrGLLight;
743
744#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000745
746};
747
748///////////////////////////////////////////////////////////////////////////////
749
robertphillips2f0dbc72015-08-20 05:15:06 -0700750class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000751public:
halcanary9d524f22016-03-29 09:03:52 -0700752
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000753
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000754 enum LightType {
755 kDistant_LightType,
756 kPoint_LightType,
757 kSpot_LightType,
758 };
759 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000760 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000761 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700762 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000763 return fColor == other.fColor;
764 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000765 // Called to know whether the generated GrGLLight will require access to the fragment position.
766 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700767 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000768
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000769 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000770 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700771 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000772
djsollen@google.com08337772012-06-26 14:33:13 +0000773protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700774 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700775 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
776 SkIntToScalar(SkColorGetG(color)),
777 SkIntToScalar(SkColorGetB(color)));
778 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700779 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000780 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700781 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000782 fColor = readPoint3(buffer);
783 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000784
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000785 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000786
djsollen@google.com08337772012-06-26 14:33:13 +0000787
788private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000789 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000790 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000791};
792
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000793///////////////////////////////////////////////////////////////////////////////
794
robertphillips2f0dbc72015-08-20 05:15:06 -0700795class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000796public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000797 SkDistantLight(const SkPoint3& direction, SkColor color)
798 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000799 }
djsollen@google.com08337772012-06-26 14:33:13 +0000800
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000801 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
802 return fDirection;
803 };
robertphillips3d32d762015-07-13 13:16:44 -0700804 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700805 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000806 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700807 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000808#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700809 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000810#else
811 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700812 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000813#endif
814 }
mtklein36352bf2015-03-25 18:17:31 -0700815 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000816
robertphillips2f0dbc72015-08-20 05:15:06 -0700817 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000818 if (other.type() != kDistant_LightType) {
819 return false;
820 }
821
822 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
823 return INHERITED::isEqual(other) &&
824 fDirection == o.fDirection;
825 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000826
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000827 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000828 fDirection = readPoint3(buffer);
829 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000830
djsollen@google.com08337772012-06-26 14:33:13 +0000831protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000832 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
833 : INHERITED(color), fDirection(direction) {
834 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700835 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000836 return new SkDistantLight(direction(), color());
837 }
mtklein36352bf2015-03-25 18:17:31 -0700838 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000839 writePoint3(fDirection, buffer);
840 }
841
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000842private:
843 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700844
845 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000846};
847
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000848///////////////////////////////////////////////////////////////////////////////
849
robertphillips2f0dbc72015-08-20 05:15:06 -0700850class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000852 SkPointLight(const SkPoint3& location, SkColor color)
853 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000854
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000855 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700856 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
857 fLocation.fY - SkIntToScalar(y),
858 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
859 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700860 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000861 return direction;
862 };
robertphillips3d32d762015-07-13 13:16:44 -0700863 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700864 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000865 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700866 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000867#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700868 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000869#else
870 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700871 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000872#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000873 }
mtklein36352bf2015-03-25 18:17:31 -0700874 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700875 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000876 if (other.type() != kPoint_LightType) {
877 return false;
878 }
879 const SkPointLight& o = static_cast<const SkPointLight&>(other);
880 return INHERITED::isEqual(other) &&
881 fLocation == o.fLocation;
882 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700883 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000884 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
885 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000886 // Use X scale and Y scale on Z and average the result
887 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
888 matrix.mapVectors(&locationZ, 1);
halcanary9d524f22016-03-29 09:03:52 -0700889 SkPoint3 location = SkPoint3::Make(location2.fX,
890 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700891 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000892 return new SkPointLight(location, color());
893 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000894
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000895 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000896 fLocation = readPoint3(buffer);
897 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000898
899protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000900 SkPointLight(const SkPoint3& location, const SkPoint3& color)
901 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700902 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000903 writePoint3(fLocation, buffer);
904 }
905
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000906private:
907 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700908
909 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910};
911
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000912///////////////////////////////////////////////////////////////////////////////
913
robertphillips2f0dbc72015-08-20 05:15:06 -0700914class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000915public:
senorblancod0d37ca2015-04-02 04:54:56 -0700916 SkSpotLight(const SkPoint3& location,
917 const SkPoint3& target,
918 SkScalar specularExponent,
919 SkScalar cutoffAngle,
920 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000921 : INHERITED(color),
922 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700924 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000925 {
926 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700927 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000928 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000929 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000930 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
931 fConeScale = SkScalarInvert(antiAliasThreshold);
932 }
djsollen@google.com08337772012-06-26 14:33:13 +0000933
robertphillips2f0dbc72015-08-20 05:15:06 -0700934 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000935 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
936 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000937 // Use X scale and Y scale on Z and average the result
938 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
939 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700940 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
941 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000942 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
943 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000944 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
945 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700946 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
947 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000948 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700949 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700950 return new SkSpotLight(location,
951 target,
952 fSpecularExponent,
953 fCosOuterConeAngle,
954 fCosInnerConeAngle,
955 fConeScale,
956 s,
957 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000958 }
959
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000960 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700961 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
962 fLocation.fY - SkIntToScalar(y),
963 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
964 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700965 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000966 return direction;
967 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000968 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000969 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700970 SkScalar scale = 0;
971 if (cosAngle >= fCosOuterConeAngle) {
972 scale = SkScalarPow(cosAngle, fSpecularExponent);
973 if (cosAngle < fCosInnerConeAngle) {
974 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
975 scale *= fConeScale;
976 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000977 }
robertphillips3d32d762015-07-13 13:16:44 -0700978 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000979 }
mtklein36352bf2015-03-25 18:17:31 -0700980 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000981#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700982 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000983#else
984 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700985 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000986#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000987 }
mtklein36352bf2015-03-25 18:17:31 -0700988 bool requiresFragmentPosition() const override { return true; }
989 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000990 const SkPoint3& location() const { return fLocation; }
991 const SkPoint3& target() const { return fTarget; }
992 SkScalar specularExponent() const { return fSpecularExponent; }
993 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
994 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
995 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000996 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000997
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000998 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000999 fLocation = readPoint3(buffer);
1000 fTarget = readPoint3(buffer);
1001 fSpecularExponent = buffer.readScalar();
1002 fCosOuterConeAngle = buffer.readScalar();
1003 fCosInnerConeAngle = buffer.readScalar();
1004 fConeScale = buffer.readScalar();
1005 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001006 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
1007 SkScalarIsFinite(fCosOuterConeAngle) &&
1008 SkScalarIsFinite(fCosInnerConeAngle) &&
1009 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +00001010 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001011protected:
senorblancod0d37ca2015-04-02 04:54:56 -07001012 SkSpotLight(const SkPoint3& location,
1013 const SkPoint3& target,
1014 SkScalar specularExponent,
1015 SkScalar cosOuterConeAngle,
1016 SkScalar cosInnerConeAngle,
1017 SkScalar coneScale,
1018 const SkPoint3& s,
1019 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001020 : INHERITED(color),
1021 fLocation(location),
1022 fTarget(target),
1023 fSpecularExponent(specularExponent),
1024 fCosOuterConeAngle(cosOuterConeAngle),
1025 fCosInnerConeAngle(cosInnerConeAngle),
1026 fConeScale(coneScale),
1027 fS(s)
1028 {
1029 }
mtklein36352bf2015-03-25 18:17:31 -07001030 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +00001031 writePoint3(fLocation, buffer);
1032 writePoint3(fTarget, buffer);
1033 buffer.writeScalar(fSpecularExponent);
1034 buffer.writeScalar(fCosOuterConeAngle);
1035 buffer.writeScalar(fCosInnerConeAngle);
1036 buffer.writeScalar(fConeScale);
1037 writePoint3(fS, buffer);
1038 }
1039
robertphillips2f0dbc72015-08-20 05:15:06 -07001040 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001041 if (other.type() != kSpot_LightType) {
1042 return false;
1043 }
1044
1045 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1046 return INHERITED::isEqual(other) &&
1047 fLocation == o.fLocation &&
1048 fTarget == o.fTarget &&
1049 fSpecularExponent == o.fSpecularExponent &&
1050 fCosOuterConeAngle == o.fCosOuterConeAngle;
1051 }
1052
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001053private:
caryclark0bccd872015-10-20 10:04:03 -07001054 static const SkScalar kSpecularExponentMin;
1055 static const SkScalar kSpecularExponentMax;
1056
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001057 SkPoint3 fLocation;
1058 SkPoint3 fTarget;
1059 SkScalar fSpecularExponent;
1060 SkScalar fCosOuterConeAngle;
1061 SkScalar fCosInnerConeAngle;
1062 SkScalar fConeScale;
1063 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001064
1065 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001066};
1067
caryclark0bccd872015-10-20 10:04:03 -07001068// According to the spec, the specular term should be in the range [1, 128] :
1069// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1070const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1071const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1072
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001073///////////////////////////////////////////////////////////////////////////////
1074
robertphillips2f0dbc72015-08-20 05:15:06 -07001075void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001076 // Write type first, then baseclass, then subclass.
1077 buffer.writeInt(this->type());
1078 writePoint3(fColor, buffer);
1079 this->onFlattenLight(buffer);
1080}
1081
robertphillips2f0dbc72015-08-20 05:15:06 -07001082/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001083 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001084 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001085 switch (type) {
1086 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1087 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001088 case SkImageFilterLight::kDistant_LightType:
1089 return new SkDistantLight(buffer);
1090 case SkImageFilterLight::kPoint_LightType:
1091 return new SkPointLight(buffer);
1092 case SkImageFilterLight::kSpot_LightType:
1093 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001094 default:
1095 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001096 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001097 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001098 }
1099}
1100///////////////////////////////////////////////////////////////////////////////
1101
robertphillips12fa47d2016-04-08 16:28:09 -07001102SkLightingImageFilter::SkLightingImageFilter(sk_sp<SkImageFilterLight> light,
1103 SkScalar surfaceScale,
1104 sk_sp<SkImageFilter> input, const CropRect* cropRect)
1105 : INHERITED(&input, 1, cropRect)
1106 , fLight(std::move(light))
1107 , fSurfaceScale(surfaceScale / 255) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001108}
1109
robertphillips82b043e2016-04-10 14:04:19 -07001110SkLightingImageFilter::~SkLightingImageFilter() {}
1111
robertphillips12fa47d2016-04-08 16:28:09 -07001112sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitDiffuse(const SkPoint3& direction,
1113 SkColor lightColor,
1114 SkScalar surfaceScale,
1115 SkScalar kd,
1116 sk_sp<SkImageFilter> input,
1117 const CropRect* cropRect) {
1118 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1119 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1120 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001121}
1122
robertphillips12fa47d2016-04-08 16:28:09 -07001123sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitDiffuse(const SkPoint3& location,
1124 SkColor lightColor,
1125 SkScalar surfaceScale,
1126 SkScalar kd,
1127 sk_sp<SkImageFilter> input,
1128 const CropRect* cropRect) {
1129 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1130 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1131 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001132}
1133
robertphillips12fa47d2016-04-08 16:28:09 -07001134sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitDiffuse(const SkPoint3& location,
1135 const SkPoint3& target,
1136 SkScalar specularExponent,
1137 SkScalar cutoffAngle,
reed9fa60da2014-08-21 07:59:51 -07001138 SkColor lightColor,
1139 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -07001140 SkScalar kd,
1141 sk_sp<SkImageFilter> input,
reed9fa60da2014-08-21 07:59:51 -07001142 const CropRect* cropRect) {
robertphillips12fa47d2016-04-08 16:28:09 -07001143 sk_sp<SkImageFilterLight> light(
halcanary385fe4d2015-08-26 13:07:48 -07001144 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
robertphillips12fa47d2016-04-08 16:28:09 -07001145 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1146 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001147}
1148
robertphillips12fa47d2016-04-08 16:28:09 -07001149sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitSpecular(const SkPoint3& direction,
1150 SkColor lightColor,
1151 SkScalar surfaceScale,
1152 SkScalar ks,
1153 SkScalar shine,
1154 sk_sp<SkImageFilter> input,
1155 const CropRect* cropRect) {
1156 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1157 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1158 std::move(input), cropRect);
1159}
1160
1161sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitSpecular(const SkPoint3& location,
1162 SkColor lightColor,
1163 SkScalar surfaceScale,
1164 SkScalar ks,
1165 SkScalar shine,
1166 sk_sp<SkImageFilter> input,
1167 const CropRect* cropRect) {
1168 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1169 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1170 std::move(input), cropRect);
1171}
1172
1173sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitSpecular(const SkPoint3& location,
1174 const SkPoint3& target,
1175 SkScalar specularExponent,
1176 SkScalar cutoffAngle,
1177 SkColor lightColor,
1178 SkScalar surfaceScale,
1179 SkScalar ks,
1180 SkScalar shine,
1181 sk_sp<SkImageFilter> input,
1182 const CropRect* cropRect) {
1183 sk_sp<SkImageFilterLight> light(
1184 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
1185 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1186 std::move(input), cropRect);
1187}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001188
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001189void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001190 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001191 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001192 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001193}
1194
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001195///////////////////////////////////////////////////////////////////////////////
1196
robertphillips12fa47d2016-04-08 16:28:09 -07001197sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1198 SkScalar surfaceScale,
1199 SkScalar kd,
1200 sk_sp<SkImageFilter> input,
1201 const CropRect* cropRect) {
1202 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001203 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001204 }
1205 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001206 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001207 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001208 // According to the spec, kd can be any non-negative number :
1209 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001210 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001211 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001212 }
robertphillips12fa47d2016-04-08 16:28:09 -07001213 return sk_sp<SkImageFilter>(new SkDiffuseLightingImageFilter(std::move(light), surfaceScale,
1214 kd, std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001215}
1216
robertphillips12fa47d2016-04-08 16:28:09 -07001217SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001218 SkScalar surfaceScale,
1219 SkScalar kd,
robertphillips12fa47d2016-04-08 16:28:09 -07001220 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001221 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001222 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1223 , fKD(kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001224}
1225
reed60c9b582016-04-03 09:11:13 -07001226sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001227 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001228 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001229 SkScalar surfaceScale = buffer.readScalar();
1230 SkScalar kd = buffer.readScalar();
robertphillips12fa47d2016-04-08 16:28:09 -07001231 return Make(std::move(light), surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001232}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001233
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001234void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001235 this->INHERITED::flatten(buffer);
1236 buffer.writeScalar(fKD);
1237}
1238
robertphillipsad3dc0d2016-04-15 05:06:11 -07001239sk_sp<SkSpecialImage> SkDiffuseLightingImageFilter::onFilterImage(SkSpecialImage* source,
1240 const Context& ctx,
1241 SkIPoint* offset) const {
1242 SkIPoint inputOffset = SkIPoint::Make(0, 0);
1243 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
1244 if (!input) {
1245 return nullptr;
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001246 }
1247
robertphillipsad3dc0d2016-04-15 05:06:11 -07001248 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1249 input->width(), input->height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001250 SkIRect bounds;
robertphillipsad3dc0d2016-04-15 05:06:11 -07001251 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1252 return nullptr;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001253 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001254
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001255 offset->fX = bounds.left();
1256 offset->fY = bounds.top();
robertphillipsad3dc0d2016-04-15 05:06:11 -07001257 bounds.offset(-inputOffset);
1258
1259#if SK_SUPPORT_GPU
1260 if (source->isTextureBacked()) {
1261 SkMatrix matrix(ctx.ctm());
1262 matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1263
1264 return this->filterImageGPU(source, input.get(), bounds, matrix);
1265 }
1266#endif
1267
1268 if (bounds.width() < 2 || bounds.height() < 2) {
1269 return nullptr;
1270 }
1271
1272 SkBitmap inputBM;
1273
1274 if (!input->getROPixels(&inputBM)) {
1275 return nullptr;
1276 }
1277
1278 if (inputBM.colorType() != kN32_SkColorType) {
1279 return nullptr;
1280 }
1281
1282 SkAutoLockPixels alp(inputBM);
1283 if (!inputBM.getPixels()) {
1284 return nullptr;
1285 }
1286
1287 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1288
1289 SkBitmap dst;
1290 if (!dst.tryAllocPixels(info)) {
1291 return nullptr;
1292 }
1293
1294 SkAutoLockPixels dstLock(dst);
1295
1296 SkMatrix matrix(ctx.ctm());
1297 matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1298
1299 sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1300
1301 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001302 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001303 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001304 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001305 transformedLight.get(),
1306 inputBM,
1307 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001308 surfaceScale(),
1309 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001310 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001311 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001312 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001313 transformedLight.get(),
1314 inputBM,
1315 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001316 surfaceScale(),
1317 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001318 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001319 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001320 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001321 transformedLight.get(),
1322 inputBM,
1323 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001324 surfaceScale(),
1325 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001326 break;
1327 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001328
robertphillipsad3dc0d2016-04-15 05:06:11 -07001329 return SkSpecialImage::MakeFromRaster(source->internal_getProxy(),
1330 SkIRect::MakeWH(bounds.width(), bounds.height()),
1331 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
senorblancod0d37ca2015-04-02 04:54:56 -07001343GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001344 GrTexture* texture,
1345 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001346 const SkIRect* srcBounds,
1347 BoundaryMode boundaryMode) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001348 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001349 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
senorblanco9bd5f742016-02-17 10:59:47 -08001350 boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001351}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001352#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001353
1354///////////////////////////////////////////////////////////////////////////////
1355
robertphillips12fa47d2016-04-08 16:28:09 -07001356sk_sp<SkImageFilter> SkSpecularLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1357 SkScalar surfaceScale,
1358 SkScalar ks,
1359 SkScalar shininess,
1360 sk_sp<SkImageFilter> input,
1361 const CropRect* cropRect) {
1362 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001363 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001364 }
1365 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001366 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001367 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001368 // According to the spec, ks can be any non-negative number :
1369 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001370 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001371 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001372 }
robertphillips12fa47d2016-04-08 16:28:09 -07001373 return sk_sp<SkImageFilter>(new SkSpecularLightingImageFilter(std::move(light), surfaceScale,
1374 ks, shininess,
1375 std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001376}
1377
robertphillips12fa47d2016-04-08 16:28:09 -07001378SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001379 SkScalar surfaceScale,
1380 SkScalar ks,
1381 SkScalar shininess,
robertphillips12fa47d2016-04-08 16:28:09 -07001382 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001383 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001384 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1385 , fKS(ks)
1386 , fShininess(shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001387}
1388
reed60c9b582016-04-03 09:11:13 -07001389sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001390 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001391 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001392 SkScalar surfaceScale = buffer.readScalar();
1393 SkScalar ks = buffer.readScalar();
1394 SkScalar shine = buffer.readScalar();
robertphillips12fa47d2016-04-08 16:28:09 -07001395 return Make(std::move(light), surfaceScale, ks, shine, common.getInput(0),
1396 &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001397}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001398
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001399void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001400 this->INHERITED::flatten(buffer);
1401 buffer.writeScalar(fKS);
1402 buffer.writeScalar(fShininess);
1403}
1404
robertphillipsad3dc0d2016-04-15 05:06:11 -07001405sk_sp<SkSpecialImage> SkSpecularLightingImageFilter::onFilterImage(SkSpecialImage* source,
1406 const Context& ctx,
1407 SkIPoint* offset) const {
1408 SkIPoint inputOffset = SkIPoint::Make(0, 0);
1409 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
1410 if (!input) {
1411 return nullptr;
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001412 }
1413
robertphillipsad3dc0d2016-04-15 05:06:11 -07001414 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1415 input->width(), input->height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001416 SkIRect bounds;
robertphillipsad3dc0d2016-04-15 05:06:11 -07001417 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1418 return nullptr;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001419 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001420
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001421 offset->fX = bounds.left();
1422 offset->fY = bounds.top();
robertphillipsad3dc0d2016-04-15 05:06:11 -07001423 bounds.offset(-inputOffset);
1424
1425#if SK_SUPPORT_GPU
1426 if (source->isTextureBacked()) {
1427 SkMatrix matrix(ctx.ctm());
1428 matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1429
1430 return this->filterImageGPU(source, input.get(), bounds, matrix);
1431 }
1432#endif
1433
1434 if (bounds.width() < 2 || bounds.height() < 2) {
1435 return nullptr;
1436 }
1437
1438 SkBitmap inputBM;
1439
1440 if (!input->getROPixels(&inputBM)) {
1441 return nullptr;
1442 }
1443
1444 if (inputBM.colorType() != kN32_SkColorType) {
1445 return nullptr;
1446 }
1447
1448 SkAutoLockPixels alp(inputBM);
1449 if (!inputBM.getPixels()) {
1450 return nullptr;
1451 }
1452
1453 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1454
1455 SkBitmap dst;
1456 if (!dst.tryAllocPixels(info)) {
1457 return nullptr;
1458 }
1459
1460 SkAutoLockPixels dstLock(dst);
1461
1462 SpecularLightingType lightingType(fKS, fShininess);
1463
senorblanco7b7ecfc2015-08-26 14:26:40 -07001464 SkMatrix matrix(ctx.ctm());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001465 matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1466
1467 sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1468
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001469 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001470 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001471 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001472 transformedLight.get(),
1473 inputBM,
1474 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001475 surfaceScale(),
1476 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001477 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001478 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001479 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001480 transformedLight.get(),
1481 inputBM,
1482 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001483 surfaceScale(),
1484 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001485 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001486 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001487 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001488 transformedLight.get(),
1489 inputBM,
1490 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001491 surfaceScale(),
1492 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001493 break;
1494 }
robertphillipsad3dc0d2016-04-15 05:06:11 -07001495
1496 return SkSpecialImage::MakeFromRaster(source->internal_getProxy(),
1497 SkIRect::MakeWH(bounds.width(), bounds.height()),
1498 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
senorblancod0d37ca2015-04-02 04:54:56 -07001510GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001511 GrTexture* texture,
1512 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001513 const SkIRect* srcBounds,
joshualitt5f10b5c2015-07-09 10:24:35 -07001514 BoundaryMode boundaryMode) const {
1515 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001516 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
senorblanco9bd5f742016-02-17 10:59:47 -08001517 this->shininess(), boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001519#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001520
1521///////////////////////////////////////////////////////////////////////////////
1522
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001523#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001524
1525namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001526SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001527 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1528 SkScalarToFloat(random->nextSScalar1()),
1529 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001530}
1531
robertphillips2f0dbc72015-08-20 05:15:06 -07001532SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001533 int type = random->nextULessThan(3);
1534 switch (type) {
1535 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001536 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001537 }
1538 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001539 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001540 }
1541 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001542 return new SkSpotLight(random_point3(random), random_point3(random),
1543 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001544 }
1545 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001546 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001547 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001548 }
1549}
1550
senorblancod0d37ca2015-04-02 04:54:56 -07001551SkString emitNormalFunc(BoundaryMode mode,
1552 const char* pointToNormalName,
1553 const char* sobelFuncName) {
1554 SkString result;
1555 switch (mode) {
1556 case kTopLeft_BoundaryMode:
1557 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1558 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1559 "\t surfaceScale);\n",
1560 pointToNormalName, sobelFuncName, gTwoThirds,
1561 sobelFuncName, gTwoThirds);
1562 break;
1563 case kTop_BoundaryMode:
1564 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1565 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1566 "\t surfaceScale);\n",
1567 pointToNormalName, sobelFuncName, gOneThird,
1568 sobelFuncName, gOneHalf);
1569 break;
1570 case kTopRight_BoundaryMode:
1571 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1572 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1573 "\t surfaceScale);\n",
1574 pointToNormalName, sobelFuncName, gTwoThirds,
1575 sobelFuncName, gTwoThirds);
1576 break;
1577 case kLeft_BoundaryMode:
1578 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1579 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1580 "\t surfaceScale);\n",
1581 pointToNormalName, sobelFuncName, gOneHalf,
1582 sobelFuncName, gOneThird);
1583 break;
1584 case kInterior_BoundaryMode:
1585 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1586 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1587 "\t surfaceScale);\n",
1588 pointToNormalName, sobelFuncName, gOneQuarter,
1589 sobelFuncName, gOneQuarter);
1590 break;
1591 case kRight_BoundaryMode:
1592 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1593 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1594 "\t surfaceScale);\n",
1595 pointToNormalName, sobelFuncName, gOneHalf,
1596 sobelFuncName, gOneThird);
1597 break;
1598 case kBottomLeft_BoundaryMode:
1599 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1600 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1601 "\t surfaceScale);\n",
1602 pointToNormalName, sobelFuncName, gTwoThirds,
1603 sobelFuncName, gTwoThirds);
1604 break;
1605 case kBottom_BoundaryMode:
1606 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1607 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1608 "\t surfaceScale);\n",
1609 pointToNormalName, sobelFuncName, gOneThird,
1610 sobelFuncName, gOneHalf);
1611 break;
1612 case kBottomRight_BoundaryMode:
1613 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1614 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1615 "\t surfaceScale);\n",
1616 pointToNormalName, sobelFuncName, gTwoThirds,
1617 sobelFuncName, gTwoThirds);
1618 break;
1619 default:
1620 SkASSERT(false);
1621 break;
1622 }
1623 return result;
1624}
1625
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001626}
1627
egdaniel64c47282015-11-13 06:54:19 -08001628class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001629public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001630 GrGLLightingEffect() : fLight(nullptr) { }
1631 virtual ~GrGLLightingEffect() { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001632
wangyix7c157a92015-07-22 15:08:53 -07001633 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001634
jvanverthcfc18862015-04-28 08:48:20 -07001635 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001636
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001637protected:
wangyixb1daa862015-08-18 11:29:31 -07001638 /**
1639 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1640 */
egdaniel018fb622015-10-28 07:26:40 -07001641 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001642
egdaniel7ea439b2015-12-03 09:20:44 -08001643 virtual void emitLightFunc(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -08001644 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -08001645 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001646
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001647private:
egdaniel64c47282015-11-13 06:54:19 -08001648 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001649
senorblanco9bd5f742016-02-17 10:59:47 -08001650 UniformHandle fImageIncrementUni;
1651 UniformHandle fSurfaceScaleUni;
1652 GrTextureDomain::GLDomain fDomain;
1653 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001654};
1655
1656///////////////////////////////////////////////////////////////////////////////
1657
1658class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1659public:
cdalton85285412016-02-18 12:37:07 -08001660 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001661
1662protected:
egdaniel018fb622015-10-28 07:26:40 -07001663 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001664
1665private:
1666 typedef GrGLLightingEffect INHERITED;
1667
bsalomon@google.com032b2212012-07-16 13:36:18 +00001668 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001669};
1670
1671///////////////////////////////////////////////////////////////////////////////
1672
1673class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1674public:
cdalton85285412016-02-18 12:37:07 -08001675 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001676
1677protected:
egdaniel018fb622015-10-28 07:26:40 -07001678 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001679
1680private:
1681 typedef GrGLLightingEffect INHERITED;
1682
bsalomon@google.com032b2212012-07-16 13:36:18 +00001683 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001684 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001685};
1686
1687///////////////////////////////////////////////////////////////////////////////
1688
senorblanco9bd5f742016-02-17 10:59:47 -08001689namespace {
1690
1691GrTextureDomain create_domain(GrTexture* texture, const SkIRect* srcBounds,
1692 GrTextureDomain::Mode mode) {
1693 if (srcBounds) {
1694 SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(texture, *srcBounds, mode);
1695 return GrTextureDomain(texelDomain, mode);
1696 } else {
1697 return GrTextureDomain(SkRect::MakeEmpty(), GrTextureDomain::kIgnore_Mode);
1698 }
1699}
1700
1701};
1702
bsalomon4a339522015-10-06 08:40:50 -07001703GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001704 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001705 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001706 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001707 BoundaryMode boundaryMode,
1708 const SkIRect* srcBounds)
bsalomon4a339522015-10-06 08:40:50 -07001709 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001710 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001711 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001712 , fFilterMatrix(matrix)
senorblanco9bd5f742016-02-17 10:59:47 -08001713 , fBoundaryMode(boundaryMode)
1714 , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001715 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001716 if (light->requiresFragmentPosition()) {
1717 this->setWillReadFragmentPosition();
1718 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001719}
1720
1721GrLightingEffect::~GrLightingEffect() {
1722 fLight->unref();
1723}
1724
bsalomon0e08fc12014-10-15 08:19:04 -07001725bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001726 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001727 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001728 fSurfaceScale == s.fSurfaceScale &&
1729 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001730}
1731
1732///////////////////////////////////////////////////////////////////////////////
1733
bsalomon4a339522015-10-06 08:40:50 -07001734GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001735 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001736 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001737 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001738 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -08001739 BoundaryMode boundaryMode,
1740 const SkIRect* srcBounds)
1741 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001742 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001743}
1744
bsalomon0e08fc12014-10-15 08:19:04 -07001745bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001746 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001747 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001748}
1749
egdaniel57d3b032015-11-13 11:57:27 -08001750void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1751 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001752 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1753}
1754
egdaniel57d3b032015-11-13 11:57:27 -08001755GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001756 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001757}
1758
joshualittb0a8a372014-09-23 09:50:21 -07001759GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001760
bsalomonc21b09e2015-08-28 18:46:56 -07001761const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
senorblanco9bd5f742016-02-17 10:59:47 -08001762 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
1763 GrProcessorUnitTest::kAlphaTextureIdx;
1764 GrTexture* tex = d->fTextures[texIdx];
joshualitt0067ff52015-07-08 14:26:19 -07001765 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1766 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001767 SkAutoTUnref<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 }
senorblanco9bd5f742016-02-17 10:59:47 -08001772 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()),
1773 d->fRandom->nextRangeU(0, tex->height()),
1774 d->fRandom->nextRangeU(0, tex->width()),
1775 d->fRandom->nextRangeU(0, tex->height()));
joshualitt0067ff52015-07-08 14:26:19 -07001776 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
senorblanco9bd5f742016-02-17 10:59:47 -08001777 return GrDiffuseLightingEffect::Create(tex, light, surfaceScale, matrix, kd, mode, &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001778}
1779
1780
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001781///////////////////////////////////////////////////////////////////////////////
1782
wangyix7c157a92015-07-22 15:08:53 -07001783void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001784 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1785 if (!fLight) {
1786 fLight = le.light()->createGLLight();
1787 }
1788
egdaniel7ea439b2015-12-03 09:20:44 -08001789 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
cdalton5e58cee2016-02-11 12:49:47 -08001790 fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001791 kVec2f_GrSLType, kDefault_GrSLPrecision,
1792 "ImageIncrement");
cdalton5e58cee2016-02-11 12:49:47 -08001793 fSurfaceScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001794 kFloat_GrSLType, kDefault_GrSLPrecision,
1795 "SurfaceScale");
1796 fLight->emitLightColorUniform(uniformHandler);
cdalton85285412016-02-18 12:37:07 -08001797 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001798 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001799 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001800 static const GrGLSLShaderVar gSobelArgs[] = {
1801 GrGLSLShaderVar("a", kFloat_GrSLType),
1802 GrGLSLShaderVar("b", kFloat_GrSLType),
1803 GrGLSLShaderVar("c", kFloat_GrSLType),
1804 GrGLSLShaderVar("d", kFloat_GrSLType),
1805 GrGLSLShaderVar("e", kFloat_GrSLType),
1806 GrGLSLShaderVar("f", kFloat_GrSLType),
1807 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001808 };
1809 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001810 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001811
egdaniel4ca2e602015-11-18 08:01:26 -08001812 fragBuilder->emitFunction(kFloat_GrSLType,
1813 "sobel",
1814 SK_ARRAY_COUNT(gSobelArgs),
1815 gSobelArgs,
1816 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1817 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001818 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1819 GrGLSLShaderVar("x", kFloat_GrSLType),
1820 GrGLSLShaderVar("y", kFloat_GrSLType),
1821 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001822 };
1823 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001824 fragBuilder->emitFunction(kVec3f_GrSLType,
1825 "pointToNormal",
1826 SK_ARRAY_COUNT(gPointToNormalArgs),
1827 gPointToNormalArgs,
1828 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1829 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001830
egdaniel0d3f0612015-10-21 10:45:48 -07001831 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1832 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1833 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001834 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001835 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001836 pointToNormalName.c_str(),
1837 sobelFuncName.c_str());
1838 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001839 fragBuilder->emitFunction(kVec3f_GrSLType,
1840 "normal",
1841 SK_ARRAY_COUNT(gInteriorNormalArgs),
1842 gInteriorNormalArgs,
1843 normalBody.c_str(),
1844 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001845
egdaniel4ca2e602015-11-18 08:01:26 -08001846 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1847 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001848
egdaniel7ea439b2015-12-03 09:20:44 -08001849 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1850 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001851
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001852 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001853 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001854 for (int dx = -1; dx <= 1; dx++) {
1855 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001856 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco9bd5f742016-02-17 10:59:47 -08001857 SkString temp;
1858 temp.appendf("temp%d", index);
1859 fragBuilder->codeAppendf("vec4 %s;", temp.c_str());
1860 fDomain.sampleTexture(fragBuilder,
1861 args.fUniformHandler,
1862 args.fGLSLCaps,
1863 le.domain(),
1864 temp.c_str(),
1865 texCoords,
cdalton3f6f76f2016-04-11 12:18:09 -07001866 args.fTexSamplers[0]);
senorblanco9bd5f742016-02-17 10:59:47 -08001867 fragBuilder->codeAppendf("m[%d] = %s.a;", index, temp.c_str());
1868 index++;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001869 }
1870 }
egdaniel4ca2e602015-11-18 08:01:26 -08001871 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001872 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001873 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001874 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001875 fragBuilder->codeAppend(";\n");
1876 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1877 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001878 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001879 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001880 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001881 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001882 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001883}
1884
joshualittb0a8a372014-09-23 09:50:21 -07001885void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001886 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001887 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1888 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco9bd5f742016-02-17 10:59:47 -08001889 b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001890}
1891
egdaniel018fb622015-10-28 07:26:40 -07001892void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1893 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001894 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001895 if (!fLight) {
1896 fLight = lighting.light()->createGLLight();
1897 }
1898
bsalomon@google.comc7818882013-03-20 19:19:53 +00001899 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001900 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001901 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1902 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001903 SkAutoTUnref<SkImageFilterLight> transformedLight(
1904 lighting.light()->transform(lighting.filterMatrix()));
senorblanco9bd5f742016-02-17 10:59:47 -08001905 fDomain.setData(pdman, lighting.domain(), texture->origin());
kkinnunen7510b222014-07-30 00:04:16 -07001906 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001907}
1908
1909///////////////////////////////////////////////////////////////////////////////
1910
1911///////////////////////////////////////////////////////////////////////////////
1912
egdaniel7ea439b2015-12-03 09:20:44 -08001913void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001914 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001915 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001916 const char* kd;
cdalton5e58cee2016-02-11 12:49:47 -08001917 fKDUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
bsalomon422f56f2014-12-09 10:18:12 -08001918 kFloat_GrSLType, kDefault_GrSLPrecision,
1919 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001920
egdaniel0d3f0612015-10-21 10:45:48 -07001921 static const GrGLSLShaderVar gLightArgs[] = {
1922 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1923 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1924 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001925 };
1926 SkString lightBody;
1927 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1928 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001929 fragBuilder->emitFunction(kVec4f_GrSLType,
1930 "light",
1931 SK_ARRAY_COUNT(gLightArgs),
1932 gLightArgs,
1933 lightBody.c_str(),
1934 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001935}
1936
egdaniel018fb622015-10-28 07:26:40 -07001937void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1938 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001939 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001940 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001941 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001942}
1943
1944///////////////////////////////////////////////////////////////////////////////
1945
bsalomon4a339522015-10-06 08:40:50 -07001946GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001947 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001948 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001949 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001950 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001951 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -08001952 BoundaryMode boundaryMode,
1953 const SkIRect* srcBounds)
1954 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds)
robertphillips2f0dbc72015-08-20 05:15:06 -07001955 , fKS(ks)
1956 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001957 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001958}
1959
bsalomon0e08fc12014-10-15 08:19:04 -07001960bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001961 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001962 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001963 this->ks() == s.ks() &&
1964 this->shininess() == s.shininess();
1965}
1966
egdaniel57d3b032015-11-13 11:57:27 -08001967void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1968 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001969 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1970}
1971
egdaniel57d3b032015-11-13 11:57:27 -08001972GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001973 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001974}
1975
joshualittb0a8a372014-09-23 09:50:21 -07001976GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001977
bsalomonc21b09e2015-08-28 18:46:56 -07001978const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
senorblanco9bd5f742016-02-17 10:59:47 -08001979 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
1980 GrProcessorUnitTest::kAlphaTextureIdx;
1981 GrTexture* tex = d->fTextures[texIdx];
joshualitt0067ff52015-07-08 14:26:19 -07001982 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1983 SkScalar ks = d->fRandom->nextUScalar1();
1984 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001985 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001986 SkMatrix matrix;
1987 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001988 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001989 }
joshualitt0067ff52015-07-08 14:26:19 -07001990 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
senorblanco9bd5f742016-02-17 10:59:47 -08001991 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()),
1992 d->fRandom->nextRangeU(0, tex->height()),
1993 d->fRandom->nextRangeU(0, tex->width()),
1994 d->fRandom->nextRangeU(0, tex->height()));
bsalomon4a339522015-10-06 08:40:50 -07001995 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco9bd5f742016-02-17 10:59:47 -08001996 light, surfaceScale, matrix, ks, shininess, mode,
1997 &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001998}
1999
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002000///////////////////////////////////////////////////////////////////////////////
2001
egdaniel7ea439b2015-12-03 09:20:44 -08002002void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002003 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002004 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002005 const char* ks;
2006 const char* shininess;
2007
cdalton5e58cee2016-02-11 12:49:47 -08002008 fKSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002009 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
cdalton5e58cee2016-02-11 12:49:47 -08002010 fShininessUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002011 kFloat_GrSLType,
2012 kDefault_GrSLPrecision,
2013 "Shininess",
2014 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002015
egdaniel0d3f0612015-10-21 10:45:48 -07002016 static const GrGLSLShaderVar gLightArgs[] = {
2017 GrGLSLShaderVar("normal", kVec3f_GrSLType),
2018 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
2019 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002020 };
2021 SkString lightBody;
2022 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
2023 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00002024 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
2025 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08002026 fragBuilder->emitFunction(kVec4f_GrSLType,
2027 "light",
2028 SK_ARRAY_COUNT(gLightArgs),
2029 gLightArgs,
2030 lightBody.c_str(),
2031 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002032}
2033
egdaniel018fb622015-10-28 07:26:40 -07002034void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
2035 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07002036 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07002037 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07002038 pdman.set1f(fKSUni, spec.ks());
2039 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002040}
2041
2042///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08002043void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
cdalton5e58cee2016-02-11 12:49:47 -08002044 fColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002045 kVec3f_GrSLType, kDefault_GrSLPrecision,
2046 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002047}
2048
egdaniel7ea439b2015-12-03 09:20:44 -08002049void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002050 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002051 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08002052 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002053}
2054
egdaniel018fb622015-10-28 07:26:40 -07002055void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002056 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07002057 setUniformPoint3(pdman, fColorUni,
2058 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002059}
2060
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002061///////////////////////////////////////////////////////////////////////////////
2062
egdaniel018fb622015-10-28 07:26:40 -07002063void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002064 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002065 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002066 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002067 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002068 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002069}
2070
egdaniel7ea439b2015-12-03 09:20:44 -08002071void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002072 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002073 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002074 const char* dir;
cdalton5e58cee2016-02-11 12:49:47 -08002075 fDirectionUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002076 kVec3f_GrSLType, kDefault_GrSLPrecision,
2077 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08002078 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002079}
2080
2081///////////////////////////////////////////////////////////////////////////////
2082
egdaniel018fb622015-10-28 07:26:40 -07002083void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002084 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002085 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002086 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002087 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002088 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002089}
2090
egdaniel7ea439b2015-12-03 09:20:44 -08002091void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002092 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002093 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002094 const char* loc;
cdalton5e58cee2016-02-11 12:49:47 -08002095 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002096 kVec3f_GrSLType, kDefault_GrSLPrecision,
2097 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08002098 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2099 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002100}
2101
2102///////////////////////////////////////////////////////////////////////////////
2103
egdaniel018fb622015-10-28 07:26:40 -07002104void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002105 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002106 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002107 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002108 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002109 setUniformPoint3(pdman, fLocationUni, spotLight->location());
2110 pdman.set1f(fExponentUni, spotLight->specularExponent());
2111 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
2112 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
2113 pdman.set1f(fConeScaleUni, spotLight->coneScale());
2114 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002115}
2116
egdaniel7ea439b2015-12-03 09:20:44 -08002117void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002118 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002119 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002120 const char* location;
cdalton5e58cee2016-02-11 12:49:47 -08002121 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002122 kVec3f_GrSLType, kDefault_GrSLPrecision,
2123 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07002124
egdaniel4ca2e602015-11-18 08:01:26 -08002125 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2126 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002127}
2128
egdaniel7ea439b2015-12-03 09:20:44 -08002129void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002130 GrGLSLFPFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002131 const char *surfaceToLight) {
2132
egdaniel7ea439b2015-12-03 09:20:44 -08002133 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002134
2135 const char* exponent;
2136 const char* cosInner;
2137 const char* cosOuter;
2138 const char* coneScale;
2139 const char* s;
cdalton5e58cee2016-02-11 12:49:47 -08002140 fExponentUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002141 kFloat_GrSLType, kDefault_GrSLPrecision,
2142 "Exponent", &exponent);
cdalton5e58cee2016-02-11 12:49:47 -08002143 fCosInnerConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002144 kFloat_GrSLType, kDefault_GrSLPrecision,
2145 "CosInnerConeAngle", &cosInner);
cdalton5e58cee2016-02-11 12:49:47 -08002146 fCosOuterConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002147 kFloat_GrSLType, kDefault_GrSLPrecision,
2148 "CosOuterConeAngle", &cosOuter);
cdalton5e58cee2016-02-11 12:49:47 -08002149 fConeScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002150 kFloat_GrSLType, kDefault_GrSLPrecision,
2151 "ConeScale", &coneScale);
cdalton5e58cee2016-02-11 12:49:47 -08002152 fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002153 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002154
egdaniel0d3f0612015-10-21 10:45:48 -07002155 static const GrGLSLShaderVar gLightColorArgs[] = {
2156 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002157 };
2158 SkString lightColorBody;
2159 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2160 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2161 lightColorBody.appendf("\t\treturn vec3(0);\n");
2162 lightColorBody.appendf("\t}\n");
2163 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2164 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2165 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2166 color, cosOuter, coneScale);
2167 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002168 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002169 fragBuilder->emitFunction(kVec3f_GrSLType,
2170 "lightColor",
2171 SK_ARRAY_COUNT(gLightColorArgs),
2172 gLightColorArgs,
2173 lightColorBody.c_str(),
2174 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002175
egdaniel4ca2e602015-11-18 08:01:26 -08002176 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002177}
2178
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002179#endif
2180
djsollen@google.com08337772012-06-26 14:33:13 +00002181SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2182 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2183 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002184SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END