blob: e276dc0fde1b7ba3b10126a5d375d7f7b25166e0 [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
senorblanco1d3ff432015-10-20 10:17:34 -070011#include "SkDevice.h"
robertphillips3d32d762015-07-13 13:16:44 -070012#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070015#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070018#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070019#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
21#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070022#include "GrPaint.h"
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:
robertphillips2f0dbc72015-08-20 05:15:06 -0700350 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700351 SkScalar surfaceScale,
352 SkImageFilter* input,
353 const CropRect* cropRect)
354 : INHERITED(light, surfaceScale, input, cropRect) {}
355
356#if SK_SUPPORT_GPU
357 bool canFilterImageGPU() const override { return true; }
robertphillips48e78462016-02-17 13:57:16 -0800358 bool filterImageGPUDeprecated(Proxy*, const SkBitmap& src, const Context&,
359 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700360 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700361 const SkMatrix&,
senorblanco9bd5f742016-02-17 10:59:47 -0800362 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700363 BoundaryMode boundaryMode) const = 0;
364#endif
365private:
366#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700367 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700368 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700369 const SkMatrix& matrix,
370 const GrClip& clip,
371 const SkRect& dstRect,
372 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800373 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700374 const SkIRect& bounds) const;
375#endif
376 typedef SkLightingImageFilter INHERITED;
377};
378
379#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700380void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700381 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700382 const SkMatrix& matrix,
383 const GrClip& clip,
384 const SkRect& dstRect,
385 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800386 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700387 const SkIRect& bounds) const {
388 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700389 GrPaint paint;
brianosman898235c2016-04-06 07:38:23 -0700390 // SRGBTODO: AllowSRGBInputs?
senorblanco9bd5f742016-02-17 10:59:47 -0800391 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, srcBounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700392 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800393 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800394 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700395}
396
robertphillips48e78462016-02-17 13:57:16 -0800397bool SkLightingImageFilterInternal::filterImageGPUDeprecated(Proxy* proxy,
398 const SkBitmap& src,
399 const Context& ctx,
400 SkBitmap* result,
401 SkIPoint* offset) const {
senorblancod0d37ca2015-04-02 04:54:56 -0700402 SkBitmap input = src;
403 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -0800404 if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700405 return false;
406 }
senorblanco9bd5f742016-02-17 10:59:47 -0800407 SkIRect srcBounds = input.bounds();
408 srcBounds.offset(srcOffset);
senorblancod0d37ca2015-04-02 04:54:56 -0700409 SkIRect bounds;
senorblanco9bd5f742016-02-17 10:59:47 -0800410 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700411 return false;
412 }
413 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
414 SkIntToScalar(bounds.height()));
415 GrTexture* srcTexture = input.getTexture();
416 GrContext* context = srcTexture->getContext();
417
418 GrSurfaceDesc desc;
419 desc.fFlags = kRenderTarget_GrSurfaceFlag,
420 desc.fWidth = bounds.width();
421 desc.fHeight = bounds.height();
422 desc.fConfig = kRGBA_8888_GrPixelConfig;
423
reed4e23cda2016-01-11 10:56:59 -0800424 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700425 if (!dst) {
426 return false;
427 }
428
429 // setup new clip
430 GrClip clip(dstRect);
431
432 offset->fX = bounds.left();
433 offset->fY = bounds.top();
434 SkMatrix matrix(ctx.ctm());
435 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
436 bounds.offset(-srcOffset);
senorblanco9bd5f742016-02-17 10:59:47 -0800437 srcBounds.offset(-srcOffset);
senorblancod0d37ca2015-04-02 04:54:56 -0700438 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
439 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
440 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
441 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
442 SkRect interior = dstRect.makeInset(1, 1);
443 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
444 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
445 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
446 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700447
robertphillips2e1e51f2015-10-15 08:01:48 -0700448 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700449 if (!drawContext) {
450 return false;
451 }
452
senorblanco9bd5f742016-02-17 10:59:47 -0800453 const SkIRect* pSrcBounds = srcBounds.contains(bounds) ? nullptr : &srcBounds;
454 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode,
455 pSrcBounds, bounds);
456 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode,
457 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700458 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800459 pSrcBounds, bounds);
460 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode,
461 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700462 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800463 pSrcBounds, bounds);
464 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode,
465 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700466 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800467 pSrcBounds, bounds);
468 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode,
469 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700470 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
senorblanco9bd5f742016-02-17 10:59:47 -0800471 kBottomRight_BoundaryMode, pSrcBounds, bounds);
robertphillips1de87df2016-01-14 06:03:29 -0800472 GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
senorblancod0d37ca2015-04-02 04:54:56 -0700473 return true;
474}
475#endif
476
477class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000478public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700479 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
480 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700481 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700482
robertphillipsf3f5bad2014-12-19 13:49:15 -0800483 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000484 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000485 SkScalar kd() const { return fKD; }
486
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000487protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700488 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700489 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700490 void flatten(SkWriteBuffer& buffer) const override;
robertphillips48e78462016-02-17 13:57:16 -0800491 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
492 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000493#if SK_SUPPORT_GPU
senorblanco9bd5f742016-02-17 10:59:47 -0800494 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect* bounds,
bsalomon4a339522015-10-06 08:40:50 -0700495 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000496#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000497
498private:
reed9fa60da2014-08-21 07:59:51 -0700499 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700500 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501 SkScalar fKD;
502};
503
senorblancod0d37ca2015-04-02 04:54:56 -0700504class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000505public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700506 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700507 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700508
robertphillipsf3f5bad2014-12-19 13:49:15 -0800509 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000510 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
511
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000512 SkScalar ks() const { return fKS; }
513 SkScalar shininess() const { return fShininess; }
514
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700516 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700517 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700518 void flatten(SkWriteBuffer& buffer) const override;
robertphillips48e78462016-02-17 13:57:16 -0800519 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
520 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000521#if SK_SUPPORT_GPU
senorblanco9bd5f742016-02-17 10:59:47 -0800522 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect* bounds,
bsalomon4a339522015-10-06 08:40:50 -0700523 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000524#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000525
526private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000527 SkScalar fKS;
528 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700529 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700530 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000531};
532
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000533#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000535class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536public:
bsalomon4a339522015-10-06 08:40:50 -0700537 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco9bd5f742016-02-17 10:59:47 -0800538 const SkMatrix& matrix, BoundaryMode boundaryMode, const SkIRect* srcBounds);
robertphillipse004bfc2015-11-16 09:06:59 -0800539 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000540
robertphillips2f0dbc72015-08-20 05:15:06 -0700541 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000542 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000543 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700544 BoundaryMode boundaryMode() const { return fBoundaryMode; }
senorblanco9bd5f742016-02-17 10:59:47 -0800545 const GrTextureDomain& domain() const { return fDomain; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000546
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000547protected:
mtklein36352bf2015-03-25 18:17:31 -0700548 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000549
mtklein36352bf2015-03-25 18:17:31 -0700550 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700551 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800552 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700553 }
554
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000555private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700556 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000557 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000558 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700559 BoundaryMode fBoundaryMode;
senorblanco9bd5f742016-02-17 10:59:47 -0800560 GrTextureDomain fDomain;
robertphillips2f0dbc72015-08-20 05:15:06 -0700561
562 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000563};
564
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565class GrDiffuseLightingEffect : public GrLightingEffect {
566public:
bsalomon4a339522015-10-06 08:40:50 -0700567 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700568 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700569 SkScalar surfaceScale,
570 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700571 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800572 BoundaryMode boundaryMode,
573 const SkIRect* srcBounds) {
574 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode,
575 srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000576 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000577
mtklein36352bf2015-03-25 18:17:31 -0700578 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000579
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000580 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000581
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000582private:
egdaniel57d3b032015-11-13 11:57:27 -0800583 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700584
egdaniel57d3b032015-11-13 11:57:27 -0800585 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700586
mtklein36352bf2015-03-25 18:17:31 -0700587 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000588
bsalomon4a339522015-10-06 08:40:50 -0700589 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700590 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000591 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000592 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700593 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800594 BoundaryMode boundaryMode,
595 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000596
joshualittb0a8a372014-09-23 09:50:21 -0700597 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000598 typedef GrLightingEffect INHERITED;
599 SkScalar fKD;
600};
601
602class GrSpecularLightingEffect : public GrLightingEffect {
603public:
bsalomon4a339522015-10-06 08:40:50 -0700604 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700605 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700606 SkScalar surfaceScale,
607 const SkMatrix& matrix,
608 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700609 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800610 BoundaryMode boundaryMode,
611 const SkIRect* srcBounds) {
bsalomon4a339522015-10-06 08:40:50 -0700612 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800613 boundaryMode, srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000614 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000615
mtklein36352bf2015-03-25 18:17:31 -0700616 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000617
egdaniel57d3b032015-11-13 11:57:27 -0800618 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800619
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000620 SkScalar ks() const { return fKS; }
621 SkScalar shininess() const { return fShininess; }
622
623private:
egdaniel57d3b032015-11-13 11:57:27 -0800624 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700625
mtklein36352bf2015-03-25 18:17:31 -0700626 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000627
bsalomon4a339522015-10-06 08:40:50 -0700628 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700629 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000630 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000631 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000632 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700633 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800634 BoundaryMode boundaryMode,
635 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000636
joshualittb0a8a372014-09-23 09:50:21 -0700637 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638 typedef GrLightingEffect INHERITED;
639 SkScalar fKS;
640 SkScalar fShininess;
641};
642
643///////////////////////////////////////////////////////////////////////////////
644
645class GrGLLight {
646public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000647 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000648
649 /**
650 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
651 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
652 */
egdaniel7ea439b2015-12-03 09:20:44 -0800653 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000654
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000655 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000656 * These two functions are called from GrGLLightingEffect's emitCode() function.
657 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
658 * the light. The expression will be used in the FS. emitLightColor writes an expression into
659 * the FS that is the color of the light. Either function may add functions and/or uniforms to
660 * the FS. The default of emitLightColor appends the name of the constant light color uniform
661 * and so this function only needs to be overridden if the light color varies spatially.
662 */
egdaniel7ea439b2015-12-03 09:20:44 -0800663 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800664 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -0800665 const char* z) = 0;
666 virtual void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800667 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800668 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000669
670 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
671 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700672 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000673
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000674protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000675 /**
676 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
677 * function.
678 */
679 UniformHandle lightColorUni() const { return fColorUni; }
680
681private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000682 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000683
684 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000685};
686
687///////////////////////////////////////////////////////////////////////////////
688
689class GrGLDistantLight : public GrGLLight {
690public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000691 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700692 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800693 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000694
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000695private:
696 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000697 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000698};
699
700///////////////////////////////////////////////////////////////////////////////
701
702class GrGLPointLight : public GrGLLight {
703public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000704 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700705 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800706 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000707
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000708private:
709 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000710 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000711};
712
713///////////////////////////////////////////////////////////////////////////////
714
715class GrGLSpotLight : public GrGLLight {
716public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000717 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700718 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800719 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
egdaniel7ea439b2015-12-03 09:20:44 -0800720 void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800721 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800722 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000723
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000724private:
725 typedef GrGLLight INHERITED;
726
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000727 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000728 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000729 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000730 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000731 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000732 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000733 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000734};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000735#else
736
737class GrGLLight;
738
739#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000740
741};
742
743///////////////////////////////////////////////////////////////////////////////
744
robertphillips2f0dbc72015-08-20 05:15:06 -0700745class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000746public:
halcanary9d524f22016-03-29 09:03:52 -0700747
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000748
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000749 enum LightType {
750 kDistant_LightType,
751 kPoint_LightType,
752 kSpot_LightType,
753 };
754 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000755 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000756 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700757 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000758 return fColor == other.fColor;
759 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000760 // Called to know whether the generated GrGLLight will require access to the fragment position.
761 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700762 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000763
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000764 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000765 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700766 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000767
djsollen@google.com08337772012-06-26 14:33:13 +0000768protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700769 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700770 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
771 SkIntToScalar(SkColorGetG(color)),
772 SkIntToScalar(SkColorGetB(color)));
773 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700774 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000775 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700776 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000777 fColor = readPoint3(buffer);
778 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000779
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000780 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000781
djsollen@google.com08337772012-06-26 14:33:13 +0000782
783private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000784 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000785 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786};
787
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000788///////////////////////////////////////////////////////////////////////////////
789
robertphillips2f0dbc72015-08-20 05:15:06 -0700790class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000791public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000792 SkDistantLight(const SkPoint3& direction, SkColor color)
793 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000794 }
djsollen@google.com08337772012-06-26 14:33:13 +0000795
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000796 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
797 return fDirection;
798 };
robertphillips3d32d762015-07-13 13:16:44 -0700799 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700800 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000801 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700802 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000803#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700804 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000805#else
806 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700807 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000808#endif
809 }
mtklein36352bf2015-03-25 18:17:31 -0700810 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000811
robertphillips2f0dbc72015-08-20 05:15:06 -0700812 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000813 if (other.type() != kDistant_LightType) {
814 return false;
815 }
816
817 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
818 return INHERITED::isEqual(other) &&
819 fDirection == o.fDirection;
820 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000821
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000822 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000823 fDirection = readPoint3(buffer);
824 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000825
djsollen@google.com08337772012-06-26 14:33:13 +0000826protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000827 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
828 : INHERITED(color), fDirection(direction) {
829 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700830 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000831 return new SkDistantLight(direction(), color());
832 }
mtklein36352bf2015-03-25 18:17:31 -0700833 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000834 writePoint3(fDirection, buffer);
835 }
836
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000837private:
838 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700839
840 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000841};
842
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000843///////////////////////////////////////////////////////////////////////////////
844
robertphillips2f0dbc72015-08-20 05:15:06 -0700845class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000846public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000847 SkPointLight(const SkPoint3& location, SkColor color)
848 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000849
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700851 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
852 fLocation.fY - SkIntToScalar(y),
853 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
854 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700855 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000856 return direction;
857 };
robertphillips3d32d762015-07-13 13:16:44 -0700858 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700859 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000860 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700861 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000862#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700863 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000864#else
865 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700866 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000867#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000868 }
mtklein36352bf2015-03-25 18:17:31 -0700869 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700870 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000871 if (other.type() != kPoint_LightType) {
872 return false;
873 }
874 const SkPointLight& o = static_cast<const SkPointLight&>(other);
875 return INHERITED::isEqual(other) &&
876 fLocation == o.fLocation;
877 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700878 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000879 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
880 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000881 // Use X scale and Y scale on Z and average the result
882 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
883 matrix.mapVectors(&locationZ, 1);
halcanary9d524f22016-03-29 09:03:52 -0700884 SkPoint3 location = SkPoint3::Make(location2.fX,
885 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700886 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000887 return new SkPointLight(location, color());
888 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000889
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000890 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000891 fLocation = readPoint3(buffer);
892 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000893
894protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000895 SkPointLight(const SkPoint3& location, const SkPoint3& color)
896 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700897 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000898 writePoint3(fLocation, buffer);
899 }
900
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000901private:
902 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700903
904 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000905};
906
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000907///////////////////////////////////////////////////////////////////////////////
908
robertphillips2f0dbc72015-08-20 05:15:06 -0700909class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910public:
senorblancod0d37ca2015-04-02 04:54:56 -0700911 SkSpotLight(const SkPoint3& location,
912 const SkPoint3& target,
913 SkScalar specularExponent,
914 SkScalar cutoffAngle,
915 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000916 : INHERITED(color),
917 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000918 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700919 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000920 {
921 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700922 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000924 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000925 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
926 fConeScale = SkScalarInvert(antiAliasThreshold);
927 }
djsollen@google.com08337772012-06-26 14:33:13 +0000928
robertphillips2f0dbc72015-08-20 05:15:06 -0700929 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000930 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
931 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000932 // Use X scale and Y scale on Z and average the result
933 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
934 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700935 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
936 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000937 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
938 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000939 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
940 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700941 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
942 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000943 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700944 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700945 return new SkSpotLight(location,
946 target,
947 fSpecularExponent,
948 fCosOuterConeAngle,
949 fCosInnerConeAngle,
950 fConeScale,
951 s,
952 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000953 }
954
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000955 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700956 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
957 fLocation.fY - SkIntToScalar(y),
958 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
959 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700960 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000961 return direction;
962 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000963 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000964 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700965 SkScalar scale = 0;
966 if (cosAngle >= fCosOuterConeAngle) {
967 scale = SkScalarPow(cosAngle, fSpecularExponent);
968 if (cosAngle < fCosInnerConeAngle) {
969 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
970 scale *= fConeScale;
971 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000972 }
robertphillips3d32d762015-07-13 13:16:44 -0700973 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000974 }
mtklein36352bf2015-03-25 18:17:31 -0700975 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000976#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700977 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000978#else
979 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700980 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000981#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000982 }
mtklein36352bf2015-03-25 18:17:31 -0700983 bool requiresFragmentPosition() const override { return true; }
984 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000985 const SkPoint3& location() const { return fLocation; }
986 const SkPoint3& target() const { return fTarget; }
987 SkScalar specularExponent() const { return fSpecularExponent; }
988 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
989 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
990 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000991 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000992
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000993 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000994 fLocation = readPoint3(buffer);
995 fTarget = readPoint3(buffer);
996 fSpecularExponent = buffer.readScalar();
997 fCosOuterConeAngle = buffer.readScalar();
998 fCosInnerConeAngle = buffer.readScalar();
999 fConeScale = buffer.readScalar();
1000 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001001 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
1002 SkScalarIsFinite(fCosOuterConeAngle) &&
1003 SkScalarIsFinite(fCosInnerConeAngle) &&
1004 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +00001005 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001006protected:
senorblancod0d37ca2015-04-02 04:54:56 -07001007 SkSpotLight(const SkPoint3& location,
1008 const SkPoint3& target,
1009 SkScalar specularExponent,
1010 SkScalar cosOuterConeAngle,
1011 SkScalar cosInnerConeAngle,
1012 SkScalar coneScale,
1013 const SkPoint3& s,
1014 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001015 : INHERITED(color),
1016 fLocation(location),
1017 fTarget(target),
1018 fSpecularExponent(specularExponent),
1019 fCosOuterConeAngle(cosOuterConeAngle),
1020 fCosInnerConeAngle(cosInnerConeAngle),
1021 fConeScale(coneScale),
1022 fS(s)
1023 {
1024 }
mtklein36352bf2015-03-25 18:17:31 -07001025 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +00001026 writePoint3(fLocation, buffer);
1027 writePoint3(fTarget, buffer);
1028 buffer.writeScalar(fSpecularExponent);
1029 buffer.writeScalar(fCosOuterConeAngle);
1030 buffer.writeScalar(fCosInnerConeAngle);
1031 buffer.writeScalar(fConeScale);
1032 writePoint3(fS, buffer);
1033 }
1034
robertphillips2f0dbc72015-08-20 05:15:06 -07001035 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001036 if (other.type() != kSpot_LightType) {
1037 return false;
1038 }
1039
1040 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1041 return INHERITED::isEqual(other) &&
1042 fLocation == o.fLocation &&
1043 fTarget == o.fTarget &&
1044 fSpecularExponent == o.fSpecularExponent &&
1045 fCosOuterConeAngle == o.fCosOuterConeAngle;
1046 }
1047
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001048private:
caryclark0bccd872015-10-20 10:04:03 -07001049 static const SkScalar kSpecularExponentMin;
1050 static const SkScalar kSpecularExponentMax;
1051
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001052 SkPoint3 fLocation;
1053 SkPoint3 fTarget;
1054 SkScalar fSpecularExponent;
1055 SkScalar fCosOuterConeAngle;
1056 SkScalar fCosInnerConeAngle;
1057 SkScalar fConeScale;
1058 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001059
1060 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001061};
1062
caryclark0bccd872015-10-20 10:04:03 -07001063// According to the spec, the specular term should be in the range [1, 128] :
1064// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1065const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1066const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1067
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001068///////////////////////////////////////////////////////////////////////////////
1069
robertphillips2f0dbc72015-08-20 05:15:06 -07001070void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001071 // Write type first, then baseclass, then subclass.
1072 buffer.writeInt(this->type());
1073 writePoint3(fColor, buffer);
1074 this->onFlattenLight(buffer);
1075}
1076
robertphillips2f0dbc72015-08-20 05:15:06 -07001077/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001078 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001079 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001080 switch (type) {
1081 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1082 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001083 case SkImageFilterLight::kDistant_LightType:
1084 return new SkDistantLight(buffer);
1085 case SkImageFilterLight::kPoint_LightType:
1086 return new SkPointLight(buffer);
1087 case SkImageFilterLight::kSpot_LightType:
1088 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001089 default:
1090 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001091 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001092 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001093 }
1094}
1095///////////////////////////////////////////////////////////////////////////////
1096
robertphillips2f0dbc72015-08-20 05:15:06 -07001097SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001098 SkImageFilter* input, const CropRect* cropRect)
1099 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001100 , fLight(SkRef(light))
1101 , fSurfaceScale(surfaceScale / 255)
1102{}
1103
1104SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1105 SkColor lightColor,
1106 SkScalar surfaceScale,
1107 SkScalar kd,
1108 SkImageFilter* input,
1109 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001110 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001111 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001112}
1113
reed9fa60da2014-08-21 07:59:51 -07001114SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1115 SkColor lightColor,
1116 SkScalar surfaceScale,
1117 SkScalar kd,
1118 SkImageFilter* input,
1119 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001120 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001121 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001122}
1123
reed9fa60da2014-08-21 07:59:51 -07001124SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1125 const SkPoint3& target,
1126 SkScalar specularExponent,
1127 SkScalar cutoffAngle,
1128 SkColor lightColor,
1129 SkScalar surfaceScale,
1130 SkScalar kd,
1131 SkImageFilter* input,
1132 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001133 SkAutoTUnref<SkImageFilterLight> light(
1134 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001135 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001136}
1137
reed9fa60da2014-08-21 07:59:51 -07001138SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1139 SkColor lightColor,
1140 SkScalar surfaceScale,
1141 SkScalar ks,
1142 SkScalar shine,
1143 SkImageFilter* input,
1144 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001145 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001146 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001147}
1148
reed9fa60da2014-08-21 07:59:51 -07001149SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1150 SkColor lightColor,
1151 SkScalar surfaceScale,
1152 SkScalar ks,
1153 SkScalar shine,
1154 SkImageFilter* input,
1155 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001156 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001157 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001158}
1159
reed9fa60da2014-08-21 07:59:51 -07001160SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1161 const SkPoint3& target,
1162 SkScalar specularExponent,
1163 SkScalar cutoffAngle,
1164 SkColor lightColor,
1165 SkScalar surfaceScale,
1166 SkScalar ks,
1167 SkScalar shine,
1168 SkImageFilter* input,
1169 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001170 SkAutoTUnref<SkImageFilterLight> light(
1171 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001172 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001173}
1174
reed9fa60da2014-08-21 07:59:51 -07001175SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001176
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001177void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001178 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001179 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001180 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001181}
1182
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001183///////////////////////////////////////////////////////////////////////////////
1184
robertphillips2f0dbc72015-08-20 05:15:06 -07001185SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1186 SkScalar surfaceScale,
1187 SkScalar kd,
1188 SkImageFilter* input,
1189 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001190 if (nullptr == light) {
1191 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001192 }
1193 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001194 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001195 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001196 // According to the spec, kd can be any non-negative number :
1197 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001198 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001199 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001200 }
halcanary385fe4d2015-08-26 13:07:48 -07001201 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001202}
1203
robertphillips2f0dbc72015-08-20 05:15:06 -07001204SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001205 SkScalar surfaceScale,
1206 SkScalar kd,
1207 SkImageFilter* input,
1208 const CropRect* cropRect)
1209 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001210 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001211{
1212}
1213
reed60c9b582016-04-03 09:11:13 -07001214sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001215 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001216 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001217 SkScalar surfaceScale = buffer.readScalar();
1218 SkScalar kd = buffer.readScalar();
reed60c9b582016-04-03 09:11:13 -07001219 return sk_sp<SkFlattenable>(Create(light, surfaceScale, kd, common.getInput(0).get(),
1220 &common.cropRect()));
reed9fa60da2014-08-21 07:59:51 -07001221}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001222
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001223void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001224 this->INHERITED::flatten(buffer);
1225 buffer.writeScalar(fKD);
1226}
1227
robertphillips48e78462016-02-17 13:57:16 -08001228bool SkDiffuseLightingImageFilter::onFilterImageDeprecated(Proxy* proxy,
1229 const SkBitmap& source,
1230 const Context& ctx,
1231 SkBitmap* dst,
1232 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001233 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001234 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -08001235 if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001236 return false;
1237 }
1238
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001239 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001240 return false;
1241 }
senorblanco84f0e742016-02-16 13:26:56 -08001242 SkIRect srcBounds = src.bounds();
1243 srcBounds.offset(srcOffset);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001244 SkIRect bounds;
senorblanco84f0e742016-02-16 13:26:56 -08001245 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001246 return false;
1247 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001248
1249 if (bounds.width() < 2 || bounds.height() < 2) {
1250 return false;
1251 }
1252
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001253 SkAutoLockPixels alp(src);
1254 if (!src.getPixels()) {
1255 return false;
1256 }
1257
senorblanco1d3ff432015-10-20 10:17:34 -07001258 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1259 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001260 return false;
1261 }
senorblanco1d3ff432015-10-20 10:17:34 -07001262 *dst = device->accessBitmap(false);
1263 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001264
senorblanco7b7ecfc2015-08-26 14:26:40 -07001265 SkMatrix matrix(ctx.ctm());
1266 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1267 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001268
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001269 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001270 offset->fX = bounds.left();
1271 offset->fY = bounds.top();
1272 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001273 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001274 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001275 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1276 transformedLight,
1277 src,
1278 dst,
1279 surfaceScale(),
1280 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001281 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001282 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001283 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1284 transformedLight,
1285 src,
1286 dst,
1287 surfaceScale(),
1288 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001289 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001290 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001291 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1292 transformedLight,
1293 src,
1294 dst,
1295 surfaceScale(),
1296 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001297 break;
1298 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001299
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001300 return true;
1301}
1302
robertphillipsf3f5bad2014-12-19 13:49:15 -08001303#ifndef SK_IGNORE_TO_STRING
1304void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1305 str->appendf("SkDiffuseLightingImageFilter: (");
1306 str->appendf("kD: %f\n", fKD);
1307 str->append(")");
1308}
1309#endif
1310
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001311#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001312GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001313 GrTexture* texture,
1314 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001315 const SkIRect* srcBounds,
1316 BoundaryMode boundaryMode) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001317 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001318 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
senorblanco9bd5f742016-02-17 10:59:47 -08001319 boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001320}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001321#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001322
1323///////////////////////////////////////////////////////////////////////////////
1324
robertphillips2f0dbc72015-08-20 05:15:06 -07001325SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1326 SkScalar surfaceScale,
1327 SkScalar ks,
1328 SkScalar shininess,
1329 SkImageFilter* input,
1330 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001331 if (nullptr == light) {
1332 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001333 }
1334 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001335 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001336 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001337 // According to the spec, ks can be any non-negative number :
1338 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001339 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001340 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001341 }
halcanary385fe4d2015-08-26 13:07:48 -07001342 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001343}
1344
robertphillips2f0dbc72015-08-20 05:15:06 -07001345SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001346 SkScalar surfaceScale,
1347 SkScalar ks,
1348 SkScalar shininess,
1349 SkImageFilter* input,
1350 const CropRect* cropRect)
1351 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001352 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001353 fShininess(shininess)
1354{
1355}
1356
reed60c9b582016-04-03 09:11:13 -07001357sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001358 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001359 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001360 SkScalar surfaceScale = buffer.readScalar();
1361 SkScalar ks = buffer.readScalar();
1362 SkScalar shine = buffer.readScalar();
reed60c9b582016-04-03 09:11:13 -07001363 return sk_sp<SkFlattenable>(Create(light, surfaceScale, ks, shine, common.getInput(0).get(),
1364 &common.cropRect()));
reed9fa60da2014-08-21 07:59:51 -07001365}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001366
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001367void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001368 this->INHERITED::flatten(buffer);
1369 buffer.writeScalar(fKS);
1370 buffer.writeScalar(fShininess);
1371}
1372
robertphillips48e78462016-02-17 13:57:16 -08001373bool SkSpecularLightingImageFilter::onFilterImageDeprecated(Proxy* proxy,
1374 const SkBitmap& source,
1375 const Context& ctx,
1376 SkBitmap* dst,
1377 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001378 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001379 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -08001380 if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001381 return false;
1382 }
1383
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001384 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001385 return false;
1386 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001387
senorblanco84f0e742016-02-16 13:26:56 -08001388 SkIRect srcBounds = src.bounds();
1389 srcBounds.offset(srcOffset);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001390 SkIRect bounds;
senorblanco84f0e742016-02-16 13:26:56 -08001391 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001392 return false;
1393 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001394
1395 if (bounds.width() < 2 || bounds.height() < 2) {
1396 return false;
1397 }
1398
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001399 SkAutoLockPixels alp(src);
1400 if (!src.getPixels()) {
1401 return false;
1402 }
1403
senorblanco1d3ff432015-10-20 10:17:34 -07001404 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1405 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001406 return false;
1407 }
senorblanco1d3ff432015-10-20 10:17:34 -07001408 *dst = device->accessBitmap(false);
1409 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001410
1411 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001412 offset->fX = bounds.left();
1413 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001414 SkMatrix matrix(ctx.ctm());
1415 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1416 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001417 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001418 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001419 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001420 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1421 transformedLight,
1422 src,
1423 dst,
1424 surfaceScale(),
1425 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001426 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001427 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001428 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1429 transformedLight,
1430 src,
1431 dst,
1432 surfaceScale(),
1433 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001434 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001435 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001436 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1437 transformedLight,
1438 src,
1439 dst,
1440 surfaceScale(),
1441 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001442 break;
1443 }
1444 return true;
1445}
1446
robertphillipsf3f5bad2014-12-19 13:49:15 -08001447#ifndef SK_IGNORE_TO_STRING
1448void SkSpecularLightingImageFilter::toString(SkString* str) const {
1449 str->appendf("SkSpecularLightingImageFilter: (");
1450 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1451 str->append(")");
1452}
1453#endif
1454
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001455#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001456GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001457 GrTexture* texture,
1458 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001459 const SkIRect* srcBounds,
joshualitt5f10b5c2015-07-09 10:24:35 -07001460 BoundaryMode boundaryMode) const {
1461 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001462 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
senorblanco9bd5f742016-02-17 10:59:47 -08001463 this->shininess(), boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001464}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001465#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001466
1467///////////////////////////////////////////////////////////////////////////////
1468
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001469#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001470
1471namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001472SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001473 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1474 SkScalarToFloat(random->nextSScalar1()),
1475 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001476}
1477
robertphillips2f0dbc72015-08-20 05:15:06 -07001478SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001479 int type = random->nextULessThan(3);
1480 switch (type) {
1481 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001482 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001483 }
1484 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001485 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001486 }
1487 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001488 return new SkSpotLight(random_point3(random), random_point3(random),
1489 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001490 }
1491 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001492 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001493 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001494 }
1495}
1496
senorblancod0d37ca2015-04-02 04:54:56 -07001497SkString emitNormalFunc(BoundaryMode mode,
1498 const char* pointToNormalName,
1499 const char* sobelFuncName) {
1500 SkString result;
1501 switch (mode) {
1502 case kTopLeft_BoundaryMode:
1503 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1504 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1505 "\t surfaceScale);\n",
1506 pointToNormalName, sobelFuncName, gTwoThirds,
1507 sobelFuncName, gTwoThirds);
1508 break;
1509 case kTop_BoundaryMode:
1510 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1511 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1512 "\t surfaceScale);\n",
1513 pointToNormalName, sobelFuncName, gOneThird,
1514 sobelFuncName, gOneHalf);
1515 break;
1516 case kTopRight_BoundaryMode:
1517 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1518 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1519 "\t surfaceScale);\n",
1520 pointToNormalName, sobelFuncName, gTwoThirds,
1521 sobelFuncName, gTwoThirds);
1522 break;
1523 case kLeft_BoundaryMode:
1524 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1525 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1526 "\t surfaceScale);\n",
1527 pointToNormalName, sobelFuncName, gOneHalf,
1528 sobelFuncName, gOneThird);
1529 break;
1530 case kInterior_BoundaryMode:
1531 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1532 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1533 "\t surfaceScale);\n",
1534 pointToNormalName, sobelFuncName, gOneQuarter,
1535 sobelFuncName, gOneQuarter);
1536 break;
1537 case kRight_BoundaryMode:
1538 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1539 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1540 "\t surfaceScale);\n",
1541 pointToNormalName, sobelFuncName, gOneHalf,
1542 sobelFuncName, gOneThird);
1543 break;
1544 case kBottomLeft_BoundaryMode:
1545 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1546 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1547 "\t surfaceScale);\n",
1548 pointToNormalName, sobelFuncName, gTwoThirds,
1549 sobelFuncName, gTwoThirds);
1550 break;
1551 case kBottom_BoundaryMode:
1552 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1553 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1554 "\t surfaceScale);\n",
1555 pointToNormalName, sobelFuncName, gOneThird,
1556 sobelFuncName, gOneHalf);
1557 break;
1558 case kBottomRight_BoundaryMode:
1559 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1560 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1561 "\t surfaceScale);\n",
1562 pointToNormalName, sobelFuncName, gTwoThirds,
1563 sobelFuncName, gTwoThirds);
1564 break;
1565 default:
1566 SkASSERT(false);
1567 break;
1568 }
1569 return result;
1570}
1571
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001572}
1573
egdaniel64c47282015-11-13 06:54:19 -08001574class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001575public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001576 GrGLLightingEffect() : fLight(nullptr) { }
1577 virtual ~GrGLLightingEffect() { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001578
wangyix7c157a92015-07-22 15:08:53 -07001579 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001580
jvanverthcfc18862015-04-28 08:48:20 -07001581 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001582
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001583protected:
wangyixb1daa862015-08-18 11:29:31 -07001584 /**
1585 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1586 */
egdaniel018fb622015-10-28 07:26:40 -07001587 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001588
egdaniel7ea439b2015-12-03 09:20:44 -08001589 virtual void emitLightFunc(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -08001590 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -08001591 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001592
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001593private:
egdaniel64c47282015-11-13 06:54:19 -08001594 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001595
senorblanco9bd5f742016-02-17 10:59:47 -08001596 UniformHandle fImageIncrementUni;
1597 UniformHandle fSurfaceScaleUni;
1598 GrTextureDomain::GLDomain fDomain;
1599 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001600};
1601
1602///////////////////////////////////////////////////////////////////////////////
1603
1604class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1605public:
cdalton85285412016-02-18 12:37:07 -08001606 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001607
1608protected:
egdaniel018fb622015-10-28 07:26:40 -07001609 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001610
1611private:
1612 typedef GrGLLightingEffect INHERITED;
1613
bsalomon@google.com032b2212012-07-16 13:36:18 +00001614 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001615};
1616
1617///////////////////////////////////////////////////////////////////////////////
1618
1619class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1620public:
cdalton85285412016-02-18 12:37:07 -08001621 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001622
1623protected:
egdaniel018fb622015-10-28 07:26:40 -07001624 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001625
1626private:
1627 typedef GrGLLightingEffect INHERITED;
1628
bsalomon@google.com032b2212012-07-16 13:36:18 +00001629 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001630 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001631};
1632
1633///////////////////////////////////////////////////////////////////////////////
1634
senorblanco9bd5f742016-02-17 10:59:47 -08001635namespace {
1636
1637GrTextureDomain create_domain(GrTexture* texture, const SkIRect* srcBounds,
1638 GrTextureDomain::Mode mode) {
1639 if (srcBounds) {
1640 SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(texture, *srcBounds, mode);
1641 return GrTextureDomain(texelDomain, mode);
1642 } else {
1643 return GrTextureDomain(SkRect::MakeEmpty(), GrTextureDomain::kIgnore_Mode);
1644 }
1645}
1646
1647};
1648
bsalomon4a339522015-10-06 08:40:50 -07001649GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001650 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001651 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001652 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001653 BoundaryMode boundaryMode,
1654 const SkIRect* srcBounds)
bsalomon4a339522015-10-06 08:40:50 -07001655 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001656 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001657 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001658 , fFilterMatrix(matrix)
senorblanco9bd5f742016-02-17 10:59:47 -08001659 , fBoundaryMode(boundaryMode)
1660 , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001661 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001662 if (light->requiresFragmentPosition()) {
1663 this->setWillReadFragmentPosition();
1664 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001665}
1666
1667GrLightingEffect::~GrLightingEffect() {
1668 fLight->unref();
1669}
1670
bsalomon0e08fc12014-10-15 08:19:04 -07001671bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001672 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001673 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001674 fSurfaceScale == s.fSurfaceScale &&
1675 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001676}
1677
1678///////////////////////////////////////////////////////////////////////////////
1679
bsalomon4a339522015-10-06 08:40:50 -07001680GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001681 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001682 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001683 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001684 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -08001685 BoundaryMode boundaryMode,
1686 const SkIRect* srcBounds)
1687 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001688 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001689}
1690
bsalomon0e08fc12014-10-15 08:19:04 -07001691bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001692 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001693 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001694}
1695
egdaniel57d3b032015-11-13 11:57:27 -08001696void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1697 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001698 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1699}
1700
egdaniel57d3b032015-11-13 11:57:27 -08001701GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001702 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001703}
1704
joshualittb0a8a372014-09-23 09:50:21 -07001705GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001706
bsalomonc21b09e2015-08-28 18:46:56 -07001707const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
senorblanco9bd5f742016-02-17 10:59:47 -08001708 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
1709 GrProcessorUnitTest::kAlphaTextureIdx;
1710 GrTexture* tex = d->fTextures[texIdx];
joshualitt0067ff52015-07-08 14:26:19 -07001711 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1712 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001713 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001714 SkMatrix matrix;
1715 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001716 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001717 }
senorblanco9bd5f742016-02-17 10:59:47 -08001718 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()),
1719 d->fRandom->nextRangeU(0, tex->height()),
1720 d->fRandom->nextRangeU(0, tex->width()),
1721 d->fRandom->nextRangeU(0, tex->height()));
joshualitt0067ff52015-07-08 14:26:19 -07001722 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
senorblanco9bd5f742016-02-17 10:59:47 -08001723 return GrDiffuseLightingEffect::Create(tex, light, surfaceScale, matrix, kd, mode, &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001724}
1725
1726
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001727///////////////////////////////////////////////////////////////////////////////
1728
wangyix7c157a92015-07-22 15:08:53 -07001729void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001730 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1731 if (!fLight) {
1732 fLight = le.light()->createGLLight();
1733 }
1734
egdaniel7ea439b2015-12-03 09:20:44 -08001735 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
cdalton5e58cee2016-02-11 12:49:47 -08001736 fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001737 kVec2f_GrSLType, kDefault_GrSLPrecision,
1738 "ImageIncrement");
cdalton5e58cee2016-02-11 12:49:47 -08001739 fSurfaceScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001740 kFloat_GrSLType, kDefault_GrSLPrecision,
1741 "SurfaceScale");
1742 fLight->emitLightColorUniform(uniformHandler);
cdalton85285412016-02-18 12:37:07 -08001743 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001744 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001745 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001746 static const GrGLSLShaderVar gSobelArgs[] = {
1747 GrGLSLShaderVar("a", kFloat_GrSLType),
1748 GrGLSLShaderVar("b", kFloat_GrSLType),
1749 GrGLSLShaderVar("c", kFloat_GrSLType),
1750 GrGLSLShaderVar("d", kFloat_GrSLType),
1751 GrGLSLShaderVar("e", kFloat_GrSLType),
1752 GrGLSLShaderVar("f", kFloat_GrSLType),
1753 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001754 };
1755 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001756 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001757
egdaniel4ca2e602015-11-18 08:01:26 -08001758 fragBuilder->emitFunction(kFloat_GrSLType,
1759 "sobel",
1760 SK_ARRAY_COUNT(gSobelArgs),
1761 gSobelArgs,
1762 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1763 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001764 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1765 GrGLSLShaderVar("x", kFloat_GrSLType),
1766 GrGLSLShaderVar("y", kFloat_GrSLType),
1767 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001768 };
1769 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001770 fragBuilder->emitFunction(kVec3f_GrSLType,
1771 "pointToNormal",
1772 SK_ARRAY_COUNT(gPointToNormalArgs),
1773 gPointToNormalArgs,
1774 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1775 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001776
egdaniel0d3f0612015-10-21 10:45:48 -07001777 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1778 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1779 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001780 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001781 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001782 pointToNormalName.c_str(),
1783 sobelFuncName.c_str());
1784 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001785 fragBuilder->emitFunction(kVec3f_GrSLType,
1786 "normal",
1787 SK_ARRAY_COUNT(gInteriorNormalArgs),
1788 gInteriorNormalArgs,
1789 normalBody.c_str(),
1790 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001791
egdaniel4ca2e602015-11-18 08:01:26 -08001792 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1793 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001794
egdaniel7ea439b2015-12-03 09:20:44 -08001795 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1796 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001797
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001798 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001799 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001800 for (int dx = -1; dx <= 1; dx++) {
1801 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001802 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco9bd5f742016-02-17 10:59:47 -08001803 SkString temp;
1804 temp.appendf("temp%d", index);
1805 fragBuilder->codeAppendf("vec4 %s;", temp.c_str());
1806 fDomain.sampleTexture(fragBuilder,
1807 args.fUniformHandler,
1808 args.fGLSLCaps,
1809 le.domain(),
1810 temp.c_str(),
1811 texCoords,
1812 args.fSamplers[0]);
1813 fragBuilder->codeAppendf("m[%d] = %s.a;", index, temp.c_str());
1814 index++;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001815 }
1816 }
egdaniel4ca2e602015-11-18 08:01:26 -08001817 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001818 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001819 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001820 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001821 fragBuilder->codeAppend(";\n");
1822 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1823 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001824 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001825 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001826 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001827 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001828 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001829}
1830
joshualittb0a8a372014-09-23 09:50:21 -07001831void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001832 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001833 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1834 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco9bd5f742016-02-17 10:59:47 -08001835 b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001836}
1837
egdaniel018fb622015-10-28 07:26:40 -07001838void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1839 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001840 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001841 if (!fLight) {
1842 fLight = lighting.light()->createGLLight();
1843 }
1844
bsalomon@google.comc7818882013-03-20 19:19:53 +00001845 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001846 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001847 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1848 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001849 SkAutoTUnref<SkImageFilterLight> transformedLight(
1850 lighting.light()->transform(lighting.filterMatrix()));
senorblanco9bd5f742016-02-17 10:59:47 -08001851 fDomain.setData(pdman, lighting.domain(), texture->origin());
kkinnunen7510b222014-07-30 00:04:16 -07001852 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001853}
1854
1855///////////////////////////////////////////////////////////////////////////////
1856
1857///////////////////////////////////////////////////////////////////////////////
1858
egdaniel7ea439b2015-12-03 09:20:44 -08001859void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001860 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001861 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001862 const char* kd;
cdalton5e58cee2016-02-11 12:49:47 -08001863 fKDUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
bsalomon422f56f2014-12-09 10:18:12 -08001864 kFloat_GrSLType, kDefault_GrSLPrecision,
1865 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001866
egdaniel0d3f0612015-10-21 10:45:48 -07001867 static const GrGLSLShaderVar gLightArgs[] = {
1868 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1869 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1870 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001871 };
1872 SkString lightBody;
1873 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1874 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001875 fragBuilder->emitFunction(kVec4f_GrSLType,
1876 "light",
1877 SK_ARRAY_COUNT(gLightArgs),
1878 gLightArgs,
1879 lightBody.c_str(),
1880 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001881}
1882
egdaniel018fb622015-10-28 07:26:40 -07001883void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1884 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001885 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001886 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001887 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001888}
1889
1890///////////////////////////////////////////////////////////////////////////////
1891
bsalomon4a339522015-10-06 08:40:50 -07001892GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001893 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001894 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001895 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001896 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001897 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -08001898 BoundaryMode boundaryMode,
1899 const SkIRect* srcBounds)
1900 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds)
robertphillips2f0dbc72015-08-20 05:15:06 -07001901 , fKS(ks)
1902 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001903 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001904}
1905
bsalomon0e08fc12014-10-15 08:19:04 -07001906bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001907 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001908 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001909 this->ks() == s.ks() &&
1910 this->shininess() == s.shininess();
1911}
1912
egdaniel57d3b032015-11-13 11:57:27 -08001913void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1914 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001915 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1916}
1917
egdaniel57d3b032015-11-13 11:57:27 -08001918GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001919 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001920}
1921
joshualittb0a8a372014-09-23 09:50:21 -07001922GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001923
bsalomonc21b09e2015-08-28 18:46:56 -07001924const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
senorblanco9bd5f742016-02-17 10:59:47 -08001925 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
1926 GrProcessorUnitTest::kAlphaTextureIdx;
1927 GrTexture* tex = d->fTextures[texIdx];
joshualitt0067ff52015-07-08 14:26:19 -07001928 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1929 SkScalar ks = d->fRandom->nextUScalar1();
1930 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001931 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001932 SkMatrix matrix;
1933 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001934 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001935 }
joshualitt0067ff52015-07-08 14:26:19 -07001936 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
senorblanco9bd5f742016-02-17 10:59:47 -08001937 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()),
1938 d->fRandom->nextRangeU(0, tex->height()),
1939 d->fRandom->nextRangeU(0, tex->width()),
1940 d->fRandom->nextRangeU(0, tex->height()));
bsalomon4a339522015-10-06 08:40:50 -07001941 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco9bd5f742016-02-17 10:59:47 -08001942 light, surfaceScale, matrix, ks, shininess, mode,
1943 &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001944}
1945
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001946///////////////////////////////////////////////////////////////////////////////
1947
egdaniel7ea439b2015-12-03 09:20:44 -08001948void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001949 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001950 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001951 const char* ks;
1952 const char* shininess;
1953
cdalton5e58cee2016-02-11 12:49:47 -08001954 fKSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001955 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
cdalton5e58cee2016-02-11 12:49:47 -08001956 fShininessUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001957 kFloat_GrSLType,
1958 kDefault_GrSLPrecision,
1959 "Shininess",
1960 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001961
egdaniel0d3f0612015-10-21 10:45:48 -07001962 static const GrGLSLShaderVar gLightArgs[] = {
1963 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1964 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1965 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001966 };
1967 SkString lightBody;
1968 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1969 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001970 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1971 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001972 fragBuilder->emitFunction(kVec4f_GrSLType,
1973 "light",
1974 SK_ARRAY_COUNT(gLightArgs),
1975 gLightArgs,
1976 lightBody.c_str(),
1977 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001978}
1979
egdaniel018fb622015-10-28 07:26:40 -07001980void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1981 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001982 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001983 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001984 pdman.set1f(fKSUni, spec.ks());
1985 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001986}
1987
1988///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08001989void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
cdalton5e58cee2016-02-11 12:49:47 -08001990 fColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001991 kVec3f_GrSLType, kDefault_GrSLPrecision,
1992 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001993}
1994
egdaniel7ea439b2015-12-03 09:20:44 -08001995void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001996 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001997 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08001998 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001999}
2000
egdaniel018fb622015-10-28 07:26:40 -07002001void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002002 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07002003 setUniformPoint3(pdman, fColorUni,
2004 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002005}
2006
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002007///////////////////////////////////////////////////////////////////////////////
2008
egdaniel018fb622015-10-28 07:26:40 -07002009void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002010 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002011 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002012 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002013 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002014 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002015}
2016
egdaniel7ea439b2015-12-03 09:20:44 -08002017void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002018 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002019 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002020 const char* dir;
cdalton5e58cee2016-02-11 12:49:47 -08002021 fDirectionUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002022 kVec3f_GrSLType, kDefault_GrSLPrecision,
2023 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08002024 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002025}
2026
2027///////////////////////////////////////////////////////////////////////////////
2028
egdaniel018fb622015-10-28 07:26:40 -07002029void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002030 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002031 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002032 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002033 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002034 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002035}
2036
egdaniel7ea439b2015-12-03 09:20:44 -08002037void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002038 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002039 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002040 const char* loc;
cdalton5e58cee2016-02-11 12:49:47 -08002041 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002042 kVec3f_GrSLType, kDefault_GrSLPrecision,
2043 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08002044 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2045 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002046}
2047
2048///////////////////////////////////////////////////////////////////////////////
2049
egdaniel018fb622015-10-28 07:26:40 -07002050void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002051 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002052 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002053 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002054 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002055 setUniformPoint3(pdman, fLocationUni, spotLight->location());
2056 pdman.set1f(fExponentUni, spotLight->specularExponent());
2057 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
2058 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
2059 pdman.set1f(fConeScaleUni, spotLight->coneScale());
2060 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002061}
2062
egdaniel7ea439b2015-12-03 09:20:44 -08002063void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002064 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002065 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002066 const char* location;
cdalton5e58cee2016-02-11 12:49:47 -08002067 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002068 kVec3f_GrSLType, kDefault_GrSLPrecision,
2069 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07002070
egdaniel4ca2e602015-11-18 08:01:26 -08002071 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2072 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002073}
2074
egdaniel7ea439b2015-12-03 09:20:44 -08002075void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002076 GrGLSLFPFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002077 const char *surfaceToLight) {
2078
egdaniel7ea439b2015-12-03 09:20:44 -08002079 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002080
2081 const char* exponent;
2082 const char* cosInner;
2083 const char* cosOuter;
2084 const char* coneScale;
2085 const char* s;
cdalton5e58cee2016-02-11 12:49:47 -08002086 fExponentUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002087 kFloat_GrSLType, kDefault_GrSLPrecision,
2088 "Exponent", &exponent);
cdalton5e58cee2016-02-11 12:49:47 -08002089 fCosInnerConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002090 kFloat_GrSLType, kDefault_GrSLPrecision,
2091 "CosInnerConeAngle", &cosInner);
cdalton5e58cee2016-02-11 12:49:47 -08002092 fCosOuterConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002093 kFloat_GrSLType, kDefault_GrSLPrecision,
2094 "CosOuterConeAngle", &cosOuter);
cdalton5e58cee2016-02-11 12:49:47 -08002095 fConeScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002096 kFloat_GrSLType, kDefault_GrSLPrecision,
2097 "ConeScale", &coneScale);
cdalton5e58cee2016-02-11 12:49:47 -08002098 fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002099 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002100
egdaniel0d3f0612015-10-21 10:45:48 -07002101 static const GrGLSLShaderVar gLightColorArgs[] = {
2102 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002103 };
2104 SkString lightColorBody;
2105 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2106 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2107 lightColorBody.appendf("\t\treturn vec3(0);\n");
2108 lightColorBody.appendf("\t}\n");
2109 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2110 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2111 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2112 color, cosOuter, coneScale);
2113 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002114 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002115 fragBuilder->emitFunction(kVec3f_GrSLType,
2116 "lightColor",
2117 SK_ARRAY_COUNT(gLightColorArgs),
2118 gLightColorArgs,
2119 lightColorBody.c_str(),
2120 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002121
egdaniel4ca2e602015-11-18 08:01:26 -08002122 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002123}
2124
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002125#endif
2126
djsollen@google.com08337772012-06-26 14:33:13 +00002127SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2128 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2129 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002130SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END