blob: e60e7ed370b4c4c4c009eb7f1c412e2a0187104a [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:
robertphillips12fa47d2016-04-08 16:28:09 -0700350 SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -0700351 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -0700352 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -0700353 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -0700354 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect) {
355 }
senorblancod0d37ca2015-04-02 04:54:56 -0700356
357#if SK_SUPPORT_GPU
358 bool canFilterImageGPU() const override { return true; }
robertphillips48e78462016-02-17 13:57:16 -0800359 bool filterImageGPUDeprecated(Proxy*, const SkBitmap& src, const Context&,
360 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700361 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700362 const SkMatrix&,
senorblanco9bd5f742016-02-17 10:59:47 -0800363 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700364 BoundaryMode boundaryMode) const = 0;
365#endif
366private:
367#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700368 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700369 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700370 const SkMatrix& matrix,
371 const GrClip& clip,
372 const SkRect& dstRect,
373 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800374 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700375 const SkIRect& bounds) const;
376#endif
377 typedef SkLightingImageFilter INHERITED;
378};
379
380#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700381void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700382 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700383 const SkMatrix& matrix,
384 const GrClip& clip,
385 const SkRect& dstRect,
386 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800387 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700388 const SkIRect& bounds) const {
389 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700390 GrPaint paint;
brianosman898235c2016-04-06 07:38:23 -0700391 // SRGBTODO: AllowSRGBInputs?
senorblanco9bd5f742016-02-17 10:59:47 -0800392 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, srcBounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700393 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800394 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800395 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700396}
397
robertphillips48e78462016-02-17 13:57:16 -0800398bool SkLightingImageFilterInternal::filterImageGPUDeprecated(Proxy* proxy,
399 const SkBitmap& src,
400 const Context& ctx,
401 SkBitmap* result,
402 SkIPoint* offset) const {
senorblancod0d37ca2015-04-02 04:54:56 -0700403 SkBitmap input = src;
404 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -0800405 if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700406 return false;
407 }
senorblanco9bd5f742016-02-17 10:59:47 -0800408 SkIRect srcBounds = input.bounds();
409 srcBounds.offset(srcOffset);
senorblancod0d37ca2015-04-02 04:54:56 -0700410 SkIRect bounds;
senorblanco9bd5f742016-02-17 10:59:47 -0800411 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700412 return false;
413 }
414 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
415 SkIntToScalar(bounds.height()));
416 GrTexture* srcTexture = input.getTexture();
417 GrContext* context = srcTexture->getContext();
418
419 GrSurfaceDesc desc;
420 desc.fFlags = kRenderTarget_GrSurfaceFlag,
421 desc.fWidth = bounds.width();
422 desc.fHeight = bounds.height();
423 desc.fConfig = kRGBA_8888_GrPixelConfig;
424
reed4e23cda2016-01-11 10:56:59 -0800425 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700426 if (!dst) {
427 return false;
428 }
429
430 // setup new clip
431 GrClip clip(dstRect);
432
433 offset->fX = bounds.left();
434 offset->fY = bounds.top();
435 SkMatrix matrix(ctx.ctm());
436 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
437 bounds.offset(-srcOffset);
senorblanco9bd5f742016-02-17 10:59:47 -0800438 srcBounds.offset(-srcOffset);
senorblancod0d37ca2015-04-02 04:54:56 -0700439 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
440 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
441 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
442 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
443 SkRect interior = dstRect.makeInset(1, 1);
444 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
445 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
446 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
447 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700448
robertphillips2e1e51f2015-10-15 08:01:48 -0700449 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700450 if (!drawContext) {
451 return false;
452 }
453
senorblanco9bd5f742016-02-17 10:59:47 -0800454 const SkIRect* pSrcBounds = srcBounds.contains(bounds) ? nullptr : &srcBounds;
455 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode,
456 pSrcBounds, bounds);
457 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode,
458 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700459 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800460 pSrcBounds, bounds);
461 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode,
462 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700463 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800464 pSrcBounds, bounds);
465 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode,
466 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700467 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800468 pSrcBounds, bounds);
469 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode,
470 pSrcBounds, bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700471 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
senorblanco9bd5f742016-02-17 10:59:47 -0800472 kBottomRight_BoundaryMode, pSrcBounds, bounds);
robertphillips1de87df2016-01-14 06:03:29 -0800473 GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
senorblancod0d37ca2015-04-02 04:54:56 -0700474 return true;
475}
476#endif
477
478class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479public:
robertphillips12fa47d2016-04-08 16:28:09 -0700480 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
481 SkScalar surfaceScale,
482 SkScalar kd,
483 sk_sp<SkImageFilter>,
484 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700485
robertphillipsf3f5bad2014-12-19 13:49:15 -0800486 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000487 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000488 SkScalar kd() const { return fKD; }
489
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000490protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700491 SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, SkScalar surfaceScale,
492 SkScalar kd,
493 sk_sp<SkImageFilter> input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700494 void flatten(SkWriteBuffer& buffer) const override;
robertphillips48e78462016-02-17 13:57:16 -0800495 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
496 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000497#if SK_SUPPORT_GPU
senorblanco9bd5f742016-02-17 10:59:47 -0800498 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect* bounds,
bsalomon4a339522015-10-06 08:40:50 -0700499 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000500#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501
502private:
reed9fa60da2014-08-21 07:59:51 -0700503 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700504 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000505 SkScalar fKD;
506};
507
senorblancod0d37ca2015-04-02 04:54:56 -0700508class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000509public:
robertphillips12fa47d2016-04-08 16:28:09 -0700510 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
511 SkScalar surfaceScale,
512 SkScalar ks, SkScalar shininess,
513 sk_sp<SkImageFilter>, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700514
robertphillipsf3f5bad2014-12-19 13:49:15 -0800515 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000516 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
517
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518 SkScalar ks() const { return fKS; }
519 SkScalar shininess() const { return fShininess; }
520
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000521protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700522 SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
523 SkScalar surfaceScale, SkScalar ks,
524 SkScalar shininess,
525 sk_sp<SkImageFilter> input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700526 void flatten(SkWriteBuffer& buffer) const override;
robertphillips48e78462016-02-17 13:57:16 -0800527 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
528 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000529#if SK_SUPPORT_GPU
senorblanco9bd5f742016-02-17 10:59:47 -0800530 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect* bounds,
bsalomon4a339522015-10-06 08:40:50 -0700531 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000532#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000533
534private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000535 SkScalar fKS;
536 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700537 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700538 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539};
540
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000541#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000542
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000543class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000544public:
bsalomon4a339522015-10-06 08:40:50 -0700545 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco9bd5f742016-02-17 10:59:47 -0800546 const SkMatrix& matrix, BoundaryMode boundaryMode, const SkIRect* srcBounds);
robertphillipse004bfc2015-11-16 09:06:59 -0800547 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000548
robertphillips2f0dbc72015-08-20 05:15:06 -0700549 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000550 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000551 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700552 BoundaryMode boundaryMode() const { return fBoundaryMode; }
senorblanco9bd5f742016-02-17 10:59:47 -0800553 const GrTextureDomain& domain() const { return fDomain; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000554
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000555protected:
mtklein36352bf2015-03-25 18:17:31 -0700556 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000557
mtklein36352bf2015-03-25 18:17:31 -0700558 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700559 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800560 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700561 }
562
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000563private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700564 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000566 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700567 BoundaryMode fBoundaryMode;
senorblanco9bd5f742016-02-17 10:59:47 -0800568 GrTextureDomain fDomain;
robertphillips2f0dbc72015-08-20 05:15:06 -0700569
570 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000571};
572
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000573class GrDiffuseLightingEffect : public GrLightingEffect {
574public:
bsalomon4a339522015-10-06 08:40:50 -0700575 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700576 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700577 SkScalar surfaceScale,
578 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700579 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800580 BoundaryMode boundaryMode,
581 const SkIRect* srcBounds) {
582 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode,
583 srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000584 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000585
mtklein36352bf2015-03-25 18:17:31 -0700586 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000587
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000588 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000589
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000590private:
egdaniel57d3b032015-11-13 11:57:27 -0800591 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700592
egdaniel57d3b032015-11-13 11:57:27 -0800593 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700594
mtklein36352bf2015-03-25 18:17:31 -0700595 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000596
bsalomon4a339522015-10-06 08:40:50 -0700597 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700598 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000599 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000600 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700601 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800602 BoundaryMode boundaryMode,
603 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000604
joshualittb0a8a372014-09-23 09:50:21 -0700605 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000606 typedef GrLightingEffect INHERITED;
607 SkScalar fKD;
608};
609
610class GrSpecularLightingEffect : public GrLightingEffect {
611public:
bsalomon4a339522015-10-06 08:40:50 -0700612 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700613 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700614 SkScalar surfaceScale,
615 const SkMatrix& matrix,
616 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700617 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800618 BoundaryMode boundaryMode,
619 const SkIRect* srcBounds) {
bsalomon4a339522015-10-06 08:40:50 -0700620 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800621 boundaryMode, srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000622 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000623
mtklein36352bf2015-03-25 18:17:31 -0700624 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625
egdaniel57d3b032015-11-13 11:57:27 -0800626 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800627
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628 SkScalar ks() const { return fKS; }
629 SkScalar shininess() const { return fShininess; }
630
631private:
egdaniel57d3b032015-11-13 11:57:27 -0800632 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700633
mtklein36352bf2015-03-25 18:17:31 -0700634 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000635
bsalomon4a339522015-10-06 08:40:50 -0700636 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700637 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000638 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000639 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000640 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700641 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800642 BoundaryMode boundaryMode,
643 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000644
joshualittb0a8a372014-09-23 09:50:21 -0700645 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000646 typedef GrLightingEffect INHERITED;
647 SkScalar fKS;
648 SkScalar fShininess;
649};
650
651///////////////////////////////////////////////////////////////////////////////
652
653class GrGLLight {
654public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000655 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000656
657 /**
658 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
659 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
660 */
egdaniel7ea439b2015-12-03 09:20:44 -0800661 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000662
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000663 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000664 * These two functions are called from GrGLLightingEffect's emitCode() function.
665 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
666 * the light. The expression will be used in the FS. emitLightColor writes an expression into
667 * the FS that is the color of the light. Either function may add functions and/or uniforms to
668 * the FS. The default of emitLightColor appends the name of the constant light color uniform
669 * and so this function only needs to be overridden if the light color varies spatially.
670 */
egdaniel7ea439b2015-12-03 09:20:44 -0800671 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800672 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -0800673 const char* z) = 0;
674 virtual void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800675 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800676 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000677
678 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
679 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700680 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000681
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000682protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000683 /**
684 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
685 * function.
686 */
687 UniformHandle lightColorUni() const { return fColorUni; }
688
689private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000690 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000691
692 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000693};
694
695///////////////////////////////////////////////////////////////////////////////
696
697class GrGLDistantLight : public GrGLLight {
698public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000699 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700700 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800701 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000702
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000703private:
704 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000705 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000706};
707
708///////////////////////////////////////////////////////////////////////////////
709
710class GrGLPointLight : public GrGLLight {
711public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000712 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700713 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800714 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000715
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000716private:
717 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000718 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000719};
720
721///////////////////////////////////////////////////////////////////////////////
722
723class GrGLSpotLight : public GrGLLight {
724public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000725 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700726 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800727 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
egdaniel7ea439b2015-12-03 09:20:44 -0800728 void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800729 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800730 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000731
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000732private:
733 typedef GrGLLight INHERITED;
734
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000735 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000736 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000737 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000738 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000739 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000740 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000741 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000742};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000743#else
744
745class GrGLLight;
746
747#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000748
749};
750
751///////////////////////////////////////////////////////////////////////////////
752
robertphillips2f0dbc72015-08-20 05:15:06 -0700753class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000754public:
halcanary9d524f22016-03-29 09:03:52 -0700755
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000756
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000757 enum LightType {
758 kDistant_LightType,
759 kPoint_LightType,
760 kSpot_LightType,
761 };
762 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000763 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000764 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700765 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000766 return fColor == other.fColor;
767 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000768 // Called to know whether the generated GrGLLight will require access to the fragment position.
769 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700770 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000771
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000772 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000773 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700774 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000775
djsollen@google.com08337772012-06-26 14:33:13 +0000776protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700777 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700778 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
779 SkIntToScalar(SkColorGetG(color)),
780 SkIntToScalar(SkColorGetB(color)));
781 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700782 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000783 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700784 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000785 fColor = readPoint3(buffer);
786 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000787
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000788 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000789
djsollen@google.com08337772012-06-26 14:33:13 +0000790
791private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000792 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000793 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000794};
795
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000796///////////////////////////////////////////////////////////////////////////////
797
robertphillips2f0dbc72015-08-20 05:15:06 -0700798class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000799public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000800 SkDistantLight(const SkPoint3& direction, SkColor color)
801 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000802 }
djsollen@google.com08337772012-06-26 14:33:13 +0000803
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000804 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
805 return fDirection;
806 };
robertphillips3d32d762015-07-13 13:16:44 -0700807 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700808 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000809 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700810 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000811#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700812 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000813#else
814 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700815 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000816#endif
817 }
mtklein36352bf2015-03-25 18:17:31 -0700818 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000819
robertphillips2f0dbc72015-08-20 05:15:06 -0700820 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000821 if (other.type() != kDistant_LightType) {
822 return false;
823 }
824
825 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
826 return INHERITED::isEqual(other) &&
827 fDirection == o.fDirection;
828 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000829
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000830 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000831 fDirection = readPoint3(buffer);
832 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000833
djsollen@google.com08337772012-06-26 14:33:13 +0000834protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000835 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
836 : INHERITED(color), fDirection(direction) {
837 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700838 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000839 return new SkDistantLight(direction(), color());
840 }
mtklein36352bf2015-03-25 18:17:31 -0700841 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000842 writePoint3(fDirection, buffer);
843 }
844
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000845private:
846 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700847
848 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000849};
850
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000851///////////////////////////////////////////////////////////////////////////////
852
robertphillips2f0dbc72015-08-20 05:15:06 -0700853class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000854public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000855 SkPointLight(const SkPoint3& location, SkColor color)
856 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000857
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000858 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700859 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
860 fLocation.fY - SkIntToScalar(y),
861 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
862 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700863 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000864 return direction;
865 };
robertphillips3d32d762015-07-13 13:16:44 -0700866 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700867 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000868 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700869 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000870#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700871 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000872#else
873 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700874 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000875#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000876 }
mtklein36352bf2015-03-25 18:17:31 -0700877 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700878 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000879 if (other.type() != kPoint_LightType) {
880 return false;
881 }
882 const SkPointLight& o = static_cast<const SkPointLight&>(other);
883 return INHERITED::isEqual(other) &&
884 fLocation == o.fLocation;
885 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700886 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000887 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
888 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000889 // Use X scale and Y scale on Z and average the result
890 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
891 matrix.mapVectors(&locationZ, 1);
halcanary9d524f22016-03-29 09:03:52 -0700892 SkPoint3 location = SkPoint3::Make(location2.fX,
893 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700894 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000895 return new SkPointLight(location, color());
896 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000897
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000898 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000899 fLocation = readPoint3(buffer);
900 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000901
902protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000903 SkPointLight(const SkPoint3& location, const SkPoint3& color)
904 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700905 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000906 writePoint3(fLocation, buffer);
907 }
908
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000909private:
910 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700911
912 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000913};
914
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000915///////////////////////////////////////////////////////////////////////////////
916
robertphillips2f0dbc72015-08-20 05:15:06 -0700917class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000918public:
senorblancod0d37ca2015-04-02 04:54:56 -0700919 SkSpotLight(const SkPoint3& location,
920 const SkPoint3& target,
921 SkScalar specularExponent,
922 SkScalar cutoffAngle,
923 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000924 : INHERITED(color),
925 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000926 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700927 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000928 {
929 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700930 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000931 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000932 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000933 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
934 fConeScale = SkScalarInvert(antiAliasThreshold);
935 }
djsollen@google.com08337772012-06-26 14:33:13 +0000936
robertphillips2f0dbc72015-08-20 05:15:06 -0700937 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000938 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
939 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000940 // Use X scale and Y scale on Z and average the result
941 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
942 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700943 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
944 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000945 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
946 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000947 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
948 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700949 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
950 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000951 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700952 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700953 return new SkSpotLight(location,
954 target,
955 fSpecularExponent,
956 fCosOuterConeAngle,
957 fCosInnerConeAngle,
958 fConeScale,
959 s,
960 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000961 }
962
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000963 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700964 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
965 fLocation.fY - SkIntToScalar(y),
966 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
967 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700968 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000969 return direction;
970 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000971 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000972 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700973 SkScalar scale = 0;
974 if (cosAngle >= fCosOuterConeAngle) {
975 scale = SkScalarPow(cosAngle, fSpecularExponent);
976 if (cosAngle < fCosInnerConeAngle) {
977 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
978 scale *= fConeScale;
979 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980 }
robertphillips3d32d762015-07-13 13:16:44 -0700981 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000982 }
mtklein36352bf2015-03-25 18:17:31 -0700983 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000984#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700985 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000986#else
987 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700988 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000989#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000990 }
mtklein36352bf2015-03-25 18:17:31 -0700991 bool requiresFragmentPosition() const override { return true; }
992 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000993 const SkPoint3& location() const { return fLocation; }
994 const SkPoint3& target() const { return fTarget; }
995 SkScalar specularExponent() const { return fSpecularExponent; }
996 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
997 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
998 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000999 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +00001000
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001001 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +00001002 fLocation = readPoint3(buffer);
1003 fTarget = readPoint3(buffer);
1004 fSpecularExponent = buffer.readScalar();
1005 fCosOuterConeAngle = buffer.readScalar();
1006 fCosInnerConeAngle = buffer.readScalar();
1007 fConeScale = buffer.readScalar();
1008 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001009 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
1010 SkScalarIsFinite(fCosOuterConeAngle) &&
1011 SkScalarIsFinite(fCosInnerConeAngle) &&
1012 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +00001013 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001014protected:
senorblancod0d37ca2015-04-02 04:54:56 -07001015 SkSpotLight(const SkPoint3& location,
1016 const SkPoint3& target,
1017 SkScalar specularExponent,
1018 SkScalar cosOuterConeAngle,
1019 SkScalar cosInnerConeAngle,
1020 SkScalar coneScale,
1021 const SkPoint3& s,
1022 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001023 : INHERITED(color),
1024 fLocation(location),
1025 fTarget(target),
1026 fSpecularExponent(specularExponent),
1027 fCosOuterConeAngle(cosOuterConeAngle),
1028 fCosInnerConeAngle(cosInnerConeAngle),
1029 fConeScale(coneScale),
1030 fS(s)
1031 {
1032 }
mtklein36352bf2015-03-25 18:17:31 -07001033 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +00001034 writePoint3(fLocation, buffer);
1035 writePoint3(fTarget, buffer);
1036 buffer.writeScalar(fSpecularExponent);
1037 buffer.writeScalar(fCosOuterConeAngle);
1038 buffer.writeScalar(fCosInnerConeAngle);
1039 buffer.writeScalar(fConeScale);
1040 writePoint3(fS, buffer);
1041 }
1042
robertphillips2f0dbc72015-08-20 05:15:06 -07001043 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001044 if (other.type() != kSpot_LightType) {
1045 return false;
1046 }
1047
1048 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1049 return INHERITED::isEqual(other) &&
1050 fLocation == o.fLocation &&
1051 fTarget == o.fTarget &&
1052 fSpecularExponent == o.fSpecularExponent &&
1053 fCosOuterConeAngle == o.fCosOuterConeAngle;
1054 }
1055
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001056private:
caryclark0bccd872015-10-20 10:04:03 -07001057 static const SkScalar kSpecularExponentMin;
1058 static const SkScalar kSpecularExponentMax;
1059
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001060 SkPoint3 fLocation;
1061 SkPoint3 fTarget;
1062 SkScalar fSpecularExponent;
1063 SkScalar fCosOuterConeAngle;
1064 SkScalar fCosInnerConeAngle;
1065 SkScalar fConeScale;
1066 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001067
1068 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001069};
1070
caryclark0bccd872015-10-20 10:04:03 -07001071// According to the spec, the specular term should be in the range [1, 128] :
1072// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1073const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1074const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1075
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001076///////////////////////////////////////////////////////////////////////////////
1077
robertphillips2f0dbc72015-08-20 05:15:06 -07001078void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001079 // Write type first, then baseclass, then subclass.
1080 buffer.writeInt(this->type());
1081 writePoint3(fColor, buffer);
1082 this->onFlattenLight(buffer);
1083}
1084
robertphillips2f0dbc72015-08-20 05:15:06 -07001085/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001086 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001087 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001088 switch (type) {
1089 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1090 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001091 case SkImageFilterLight::kDistant_LightType:
1092 return new SkDistantLight(buffer);
1093 case SkImageFilterLight::kPoint_LightType:
1094 return new SkPointLight(buffer);
1095 case SkImageFilterLight::kSpot_LightType:
1096 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001097 default:
1098 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001099 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001100 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001101 }
1102}
1103///////////////////////////////////////////////////////////////////////////////
1104
robertphillips12fa47d2016-04-08 16:28:09 -07001105SkLightingImageFilter::SkLightingImageFilter(sk_sp<SkImageFilterLight> light,
1106 SkScalar surfaceScale,
1107 sk_sp<SkImageFilter> input, const CropRect* cropRect)
1108 : INHERITED(&input, 1, cropRect)
1109 , fLight(std::move(light))
1110 , fSurfaceScale(surfaceScale / 255) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001111}
1112
robertphillips82b043e2016-04-10 14:04:19 -07001113SkLightingImageFilter::~SkLightingImageFilter() {}
1114
robertphillips12fa47d2016-04-08 16:28:09 -07001115sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitDiffuse(const SkPoint3& direction,
1116 SkColor lightColor,
1117 SkScalar surfaceScale,
1118 SkScalar kd,
1119 sk_sp<SkImageFilter> input,
1120 const CropRect* cropRect) {
1121 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1122 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1123 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001124}
1125
robertphillips12fa47d2016-04-08 16:28:09 -07001126sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitDiffuse(const SkPoint3& location,
1127 SkColor lightColor,
1128 SkScalar surfaceScale,
1129 SkScalar kd,
1130 sk_sp<SkImageFilter> input,
1131 const CropRect* cropRect) {
1132 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1133 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1134 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001135}
1136
robertphillips12fa47d2016-04-08 16:28:09 -07001137sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitDiffuse(const SkPoint3& location,
1138 const SkPoint3& target,
1139 SkScalar specularExponent,
1140 SkScalar cutoffAngle,
reed9fa60da2014-08-21 07:59:51 -07001141 SkColor lightColor,
1142 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -07001143 SkScalar kd,
1144 sk_sp<SkImageFilter> input,
reed9fa60da2014-08-21 07:59:51 -07001145 const CropRect* cropRect) {
robertphillips12fa47d2016-04-08 16:28:09 -07001146 sk_sp<SkImageFilterLight> light(
halcanary385fe4d2015-08-26 13:07:48 -07001147 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
robertphillips12fa47d2016-04-08 16:28:09 -07001148 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1149 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001150}
1151
robertphillips12fa47d2016-04-08 16:28:09 -07001152sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitSpecular(const SkPoint3& direction,
1153 SkColor lightColor,
1154 SkScalar surfaceScale,
1155 SkScalar ks,
1156 SkScalar shine,
1157 sk_sp<SkImageFilter> input,
1158 const CropRect* cropRect) {
1159 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1160 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1161 std::move(input), cropRect);
1162}
1163
1164sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitSpecular(const SkPoint3& location,
1165 SkColor lightColor,
1166 SkScalar surfaceScale,
1167 SkScalar ks,
1168 SkScalar shine,
1169 sk_sp<SkImageFilter> input,
1170 const CropRect* cropRect) {
1171 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1172 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1173 std::move(input), cropRect);
1174}
1175
1176sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitSpecular(const SkPoint3& location,
1177 const SkPoint3& target,
1178 SkScalar specularExponent,
1179 SkScalar cutoffAngle,
1180 SkColor lightColor,
1181 SkScalar surfaceScale,
1182 SkScalar ks,
1183 SkScalar shine,
1184 sk_sp<SkImageFilter> input,
1185 const CropRect* cropRect) {
1186 sk_sp<SkImageFilterLight> light(
1187 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
1188 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1189 std::move(input), cropRect);
1190}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001191
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001192void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001193 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001194 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001195 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001196}
1197
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001198///////////////////////////////////////////////////////////////////////////////
1199
robertphillips12fa47d2016-04-08 16:28:09 -07001200sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1201 SkScalar surfaceScale,
1202 SkScalar kd,
1203 sk_sp<SkImageFilter> input,
1204 const CropRect* cropRect) {
1205 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001206 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001207 }
1208 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001209 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001210 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001211 // According to the spec, kd can be any non-negative number :
1212 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001213 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001214 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001215 }
robertphillips12fa47d2016-04-08 16:28:09 -07001216 return sk_sp<SkImageFilter>(new SkDiffuseLightingImageFilter(std::move(light), surfaceScale,
1217 kd, std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001218}
1219
robertphillips12fa47d2016-04-08 16:28:09 -07001220SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001221 SkScalar surfaceScale,
1222 SkScalar kd,
robertphillips12fa47d2016-04-08 16:28:09 -07001223 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001224 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001225 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1226 , fKD(kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001227}
1228
reed60c9b582016-04-03 09:11:13 -07001229sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001230 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001231 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001232 SkScalar surfaceScale = buffer.readScalar();
1233 SkScalar kd = buffer.readScalar();
robertphillips12fa47d2016-04-08 16:28:09 -07001234 return Make(std::move(light), surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001235}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001236
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001237void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001238 this->INHERITED::flatten(buffer);
1239 buffer.writeScalar(fKD);
1240}
1241
robertphillips48e78462016-02-17 13:57:16 -08001242bool SkDiffuseLightingImageFilter::onFilterImageDeprecated(Proxy* proxy,
1243 const SkBitmap& source,
1244 const Context& ctx,
1245 SkBitmap* dst,
1246 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001247 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001248 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -08001249 if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001250 return false;
1251 }
1252
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001253 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001254 return false;
1255 }
senorblanco84f0e742016-02-16 13:26:56 -08001256 SkIRect srcBounds = src.bounds();
1257 srcBounds.offset(srcOffset);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001258 SkIRect bounds;
senorblanco84f0e742016-02-16 13:26:56 -08001259 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001260 return false;
1261 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001262
1263 if (bounds.width() < 2 || bounds.height() < 2) {
1264 return false;
1265 }
1266
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001267 SkAutoLockPixels alp(src);
1268 if (!src.getPixels()) {
1269 return false;
1270 }
1271
senorblanco1d3ff432015-10-20 10:17:34 -07001272 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1273 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001274 return false;
1275 }
senorblanco1d3ff432015-10-20 10:17:34 -07001276 *dst = device->accessBitmap(false);
1277 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001278
senorblanco7b7ecfc2015-08-26 14:26:40 -07001279 SkMatrix matrix(ctx.ctm());
1280 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1281 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001282
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001283 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001284 offset->fX = bounds.left();
1285 offset->fY = bounds.top();
1286 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001287 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001288 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001289 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1290 transformedLight,
1291 src,
1292 dst,
1293 surfaceScale(),
1294 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001295 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001296 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001297 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1298 transformedLight,
1299 src,
1300 dst,
1301 surfaceScale(),
1302 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001303 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001304 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001305 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1306 transformedLight,
1307 src,
1308 dst,
1309 surfaceScale(),
1310 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001311 break;
1312 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001313
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001314 return true;
1315}
1316
robertphillipsf3f5bad2014-12-19 13:49:15 -08001317#ifndef SK_IGNORE_TO_STRING
1318void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1319 str->appendf("SkDiffuseLightingImageFilter: (");
1320 str->appendf("kD: %f\n", fKD);
1321 str->append(")");
1322}
1323#endif
1324
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001325#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001326GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001327 GrTexture* texture,
1328 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001329 const SkIRect* srcBounds,
1330 BoundaryMode boundaryMode) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001331 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001332 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
senorblanco9bd5f742016-02-17 10:59:47 -08001333 boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001334}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001335#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001336
1337///////////////////////////////////////////////////////////////////////////////
1338
robertphillips12fa47d2016-04-08 16:28:09 -07001339sk_sp<SkImageFilter> SkSpecularLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1340 SkScalar surfaceScale,
1341 SkScalar ks,
1342 SkScalar shininess,
1343 sk_sp<SkImageFilter> input,
1344 const CropRect* cropRect) {
1345 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001346 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001347 }
1348 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001349 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001350 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001351 // According to the spec, ks can be any non-negative number :
1352 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001353 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001354 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001355 }
robertphillips12fa47d2016-04-08 16:28:09 -07001356 return sk_sp<SkImageFilter>(new SkSpecularLightingImageFilter(std::move(light), surfaceScale,
1357 ks, shininess,
1358 std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001359}
1360
robertphillips12fa47d2016-04-08 16:28:09 -07001361SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001362 SkScalar surfaceScale,
1363 SkScalar ks,
1364 SkScalar shininess,
robertphillips12fa47d2016-04-08 16:28:09 -07001365 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001366 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001367 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1368 , fKS(ks)
1369 , fShininess(shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001370}
1371
reed60c9b582016-04-03 09:11:13 -07001372sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001373 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001374 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001375 SkScalar surfaceScale = buffer.readScalar();
1376 SkScalar ks = buffer.readScalar();
1377 SkScalar shine = buffer.readScalar();
robertphillips12fa47d2016-04-08 16:28:09 -07001378 return Make(std::move(light), surfaceScale, ks, shine, common.getInput(0),
1379 &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001380}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001381
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001382void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001383 this->INHERITED::flatten(buffer);
1384 buffer.writeScalar(fKS);
1385 buffer.writeScalar(fShininess);
1386}
1387
robertphillips48e78462016-02-17 13:57:16 -08001388bool SkSpecularLightingImageFilter::onFilterImageDeprecated(Proxy* proxy,
1389 const SkBitmap& source,
1390 const Context& ctx,
1391 SkBitmap* dst,
1392 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001393 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001394 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -08001395 if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001396 return false;
1397 }
1398
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001399 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001400 return false;
1401 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001402
senorblanco84f0e742016-02-16 13:26:56 -08001403 SkIRect srcBounds = src.bounds();
1404 srcBounds.offset(srcOffset);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001405 SkIRect bounds;
senorblanco84f0e742016-02-16 13:26:56 -08001406 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001407 return false;
1408 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001409
1410 if (bounds.width() < 2 || bounds.height() < 2) {
1411 return false;
1412 }
1413
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001414 SkAutoLockPixels alp(src);
1415 if (!src.getPixels()) {
1416 return false;
1417 }
1418
senorblanco1d3ff432015-10-20 10:17:34 -07001419 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1420 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001421 return false;
1422 }
senorblanco1d3ff432015-10-20 10:17:34 -07001423 *dst = device->accessBitmap(false);
1424 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001425
1426 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001427 offset->fX = bounds.left();
1428 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001429 SkMatrix matrix(ctx.ctm());
1430 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1431 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001432 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001433 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001434 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001435 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1436 transformedLight,
1437 src,
1438 dst,
1439 surfaceScale(),
1440 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001441 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001442 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001443 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1444 transformedLight,
1445 src,
1446 dst,
1447 surfaceScale(),
1448 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001449 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001450 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001451 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1452 transformedLight,
1453 src,
1454 dst,
1455 surfaceScale(),
1456 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001457 break;
1458 }
1459 return true;
1460}
1461
robertphillipsf3f5bad2014-12-19 13:49:15 -08001462#ifndef SK_IGNORE_TO_STRING
1463void SkSpecularLightingImageFilter::toString(SkString* str) const {
1464 str->appendf("SkSpecularLightingImageFilter: (");
1465 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1466 str->append(")");
1467}
1468#endif
1469
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001470#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001471GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001472 GrTexture* texture,
1473 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001474 const SkIRect* srcBounds,
joshualitt5f10b5c2015-07-09 10:24:35 -07001475 BoundaryMode boundaryMode) const {
1476 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001477 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
senorblanco9bd5f742016-02-17 10:59:47 -08001478 this->shininess(), boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001479}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001480#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001481
1482///////////////////////////////////////////////////////////////////////////////
1483
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001484#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001485
1486namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001487SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001488 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1489 SkScalarToFloat(random->nextSScalar1()),
1490 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001491}
1492
robertphillips2f0dbc72015-08-20 05:15:06 -07001493SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001494 int type = random->nextULessThan(3);
1495 switch (type) {
1496 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001497 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001498 }
1499 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001500 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001501 }
1502 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001503 return new SkSpotLight(random_point3(random), random_point3(random),
1504 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001505 }
1506 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001507 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001508 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001509 }
1510}
1511
senorblancod0d37ca2015-04-02 04:54:56 -07001512SkString emitNormalFunc(BoundaryMode mode,
1513 const char* pointToNormalName,
1514 const char* sobelFuncName) {
1515 SkString result;
1516 switch (mode) {
1517 case kTopLeft_BoundaryMode:
1518 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1519 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1520 "\t surfaceScale);\n",
1521 pointToNormalName, sobelFuncName, gTwoThirds,
1522 sobelFuncName, gTwoThirds);
1523 break;
1524 case kTop_BoundaryMode:
1525 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1526 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1527 "\t surfaceScale);\n",
1528 pointToNormalName, sobelFuncName, gOneThird,
1529 sobelFuncName, gOneHalf);
1530 break;
1531 case kTopRight_BoundaryMode:
1532 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1533 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1534 "\t surfaceScale);\n",
1535 pointToNormalName, sobelFuncName, gTwoThirds,
1536 sobelFuncName, gTwoThirds);
1537 break;
1538 case kLeft_BoundaryMode:
1539 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1540 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1541 "\t surfaceScale);\n",
1542 pointToNormalName, sobelFuncName, gOneHalf,
1543 sobelFuncName, gOneThird);
1544 break;
1545 case kInterior_BoundaryMode:
1546 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1547 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1548 "\t surfaceScale);\n",
1549 pointToNormalName, sobelFuncName, gOneQuarter,
1550 sobelFuncName, gOneQuarter);
1551 break;
1552 case kRight_BoundaryMode:
1553 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1554 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1555 "\t surfaceScale);\n",
1556 pointToNormalName, sobelFuncName, gOneHalf,
1557 sobelFuncName, gOneThird);
1558 break;
1559 case kBottomLeft_BoundaryMode:
1560 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1561 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1562 "\t surfaceScale);\n",
1563 pointToNormalName, sobelFuncName, gTwoThirds,
1564 sobelFuncName, gTwoThirds);
1565 break;
1566 case kBottom_BoundaryMode:
1567 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1568 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1569 "\t surfaceScale);\n",
1570 pointToNormalName, sobelFuncName, gOneThird,
1571 sobelFuncName, gOneHalf);
1572 break;
1573 case kBottomRight_BoundaryMode:
1574 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1575 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1576 "\t surfaceScale);\n",
1577 pointToNormalName, sobelFuncName, gTwoThirds,
1578 sobelFuncName, gTwoThirds);
1579 break;
1580 default:
1581 SkASSERT(false);
1582 break;
1583 }
1584 return result;
1585}
1586
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001587}
1588
egdaniel64c47282015-11-13 06:54:19 -08001589class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001590public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001591 GrGLLightingEffect() : fLight(nullptr) { }
1592 virtual ~GrGLLightingEffect() { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001593
wangyix7c157a92015-07-22 15:08:53 -07001594 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001595
jvanverthcfc18862015-04-28 08:48:20 -07001596 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001597
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001598protected:
wangyixb1daa862015-08-18 11:29:31 -07001599 /**
1600 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1601 */
egdaniel018fb622015-10-28 07:26:40 -07001602 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001603
egdaniel7ea439b2015-12-03 09:20:44 -08001604 virtual void emitLightFunc(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -08001605 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -08001606 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001607
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001608private:
egdaniel64c47282015-11-13 06:54:19 -08001609 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001610
senorblanco9bd5f742016-02-17 10:59:47 -08001611 UniformHandle fImageIncrementUni;
1612 UniformHandle fSurfaceScaleUni;
1613 GrTextureDomain::GLDomain fDomain;
1614 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001615};
1616
1617///////////////////////////////////////////////////////////////////////////////
1618
1619class GrGLDiffuseLightingEffect : 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 fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001630};
1631
1632///////////////////////////////////////////////////////////////////////////////
1633
1634class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1635public:
cdalton85285412016-02-18 12:37:07 -08001636 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001637
1638protected:
egdaniel018fb622015-10-28 07:26:40 -07001639 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001640
1641private:
1642 typedef GrGLLightingEffect INHERITED;
1643
bsalomon@google.com032b2212012-07-16 13:36:18 +00001644 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001645 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001646};
1647
1648///////////////////////////////////////////////////////////////////////////////
1649
senorblanco9bd5f742016-02-17 10:59:47 -08001650namespace {
1651
1652GrTextureDomain create_domain(GrTexture* texture, const SkIRect* srcBounds,
1653 GrTextureDomain::Mode mode) {
1654 if (srcBounds) {
1655 SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(texture, *srcBounds, mode);
1656 return GrTextureDomain(texelDomain, mode);
1657 } else {
1658 return GrTextureDomain(SkRect::MakeEmpty(), GrTextureDomain::kIgnore_Mode);
1659 }
1660}
1661
1662};
1663
bsalomon4a339522015-10-06 08:40:50 -07001664GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001665 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001666 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001667 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001668 BoundaryMode boundaryMode,
1669 const SkIRect* srcBounds)
bsalomon4a339522015-10-06 08:40:50 -07001670 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001671 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001672 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001673 , fFilterMatrix(matrix)
senorblanco9bd5f742016-02-17 10:59:47 -08001674 , fBoundaryMode(boundaryMode)
1675 , fDomain(create_domain(texture, srcBounds, GrTextureDomain::kDecal_Mode)) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001676 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001677 if (light->requiresFragmentPosition()) {
1678 this->setWillReadFragmentPosition();
1679 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001680}
1681
1682GrLightingEffect::~GrLightingEffect() {
1683 fLight->unref();
1684}
1685
bsalomon0e08fc12014-10-15 08:19:04 -07001686bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001687 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001688 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001689 fSurfaceScale == s.fSurfaceScale &&
1690 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001691}
1692
1693///////////////////////////////////////////////////////////////////////////////
1694
bsalomon4a339522015-10-06 08:40:50 -07001695GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001696 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001697 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001698 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001699 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -08001700 BoundaryMode boundaryMode,
1701 const SkIRect* srcBounds)
1702 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001703 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001704}
1705
bsalomon0e08fc12014-10-15 08:19:04 -07001706bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001707 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001708 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001709}
1710
egdaniel57d3b032015-11-13 11:57:27 -08001711void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1712 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001713 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1714}
1715
egdaniel57d3b032015-11-13 11:57:27 -08001716GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001717 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001718}
1719
joshualittb0a8a372014-09-23 09:50:21 -07001720GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001721
bsalomonc21b09e2015-08-28 18:46:56 -07001722const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
senorblanco9bd5f742016-02-17 10:59:47 -08001723 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
1724 GrProcessorUnitTest::kAlphaTextureIdx;
1725 GrTexture* tex = d->fTextures[texIdx];
joshualitt0067ff52015-07-08 14:26:19 -07001726 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1727 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001728 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001729 SkMatrix matrix;
1730 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001731 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001732 }
senorblanco9bd5f742016-02-17 10:59:47 -08001733 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()),
1734 d->fRandom->nextRangeU(0, tex->height()),
1735 d->fRandom->nextRangeU(0, tex->width()),
1736 d->fRandom->nextRangeU(0, tex->height()));
joshualitt0067ff52015-07-08 14:26:19 -07001737 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
senorblanco9bd5f742016-02-17 10:59:47 -08001738 return GrDiffuseLightingEffect::Create(tex, light, surfaceScale, matrix, kd, mode, &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001739}
1740
1741
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001742///////////////////////////////////////////////////////////////////////////////
1743
wangyix7c157a92015-07-22 15:08:53 -07001744void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001745 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1746 if (!fLight) {
1747 fLight = le.light()->createGLLight();
1748 }
1749
egdaniel7ea439b2015-12-03 09:20:44 -08001750 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
cdalton5e58cee2016-02-11 12:49:47 -08001751 fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001752 kVec2f_GrSLType, kDefault_GrSLPrecision,
1753 "ImageIncrement");
cdalton5e58cee2016-02-11 12:49:47 -08001754 fSurfaceScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001755 kFloat_GrSLType, kDefault_GrSLPrecision,
1756 "SurfaceScale");
1757 fLight->emitLightColorUniform(uniformHandler);
cdalton85285412016-02-18 12:37:07 -08001758 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001759 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001760 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001761 static const GrGLSLShaderVar gSobelArgs[] = {
1762 GrGLSLShaderVar("a", kFloat_GrSLType),
1763 GrGLSLShaderVar("b", kFloat_GrSLType),
1764 GrGLSLShaderVar("c", kFloat_GrSLType),
1765 GrGLSLShaderVar("d", kFloat_GrSLType),
1766 GrGLSLShaderVar("e", kFloat_GrSLType),
1767 GrGLSLShaderVar("f", kFloat_GrSLType),
1768 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001769 };
1770 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001771 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001772
egdaniel4ca2e602015-11-18 08:01:26 -08001773 fragBuilder->emitFunction(kFloat_GrSLType,
1774 "sobel",
1775 SK_ARRAY_COUNT(gSobelArgs),
1776 gSobelArgs,
1777 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1778 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001779 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1780 GrGLSLShaderVar("x", kFloat_GrSLType),
1781 GrGLSLShaderVar("y", kFloat_GrSLType),
1782 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001783 };
1784 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001785 fragBuilder->emitFunction(kVec3f_GrSLType,
1786 "pointToNormal",
1787 SK_ARRAY_COUNT(gPointToNormalArgs),
1788 gPointToNormalArgs,
1789 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1790 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001791
egdaniel0d3f0612015-10-21 10:45:48 -07001792 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1793 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1794 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001795 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001796 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001797 pointToNormalName.c_str(),
1798 sobelFuncName.c_str());
1799 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001800 fragBuilder->emitFunction(kVec3f_GrSLType,
1801 "normal",
1802 SK_ARRAY_COUNT(gInteriorNormalArgs),
1803 gInteriorNormalArgs,
1804 normalBody.c_str(),
1805 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001806
egdaniel4ca2e602015-11-18 08:01:26 -08001807 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1808 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001809
egdaniel7ea439b2015-12-03 09:20:44 -08001810 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1811 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001812
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001813 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001814 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001815 for (int dx = -1; dx <= 1; dx++) {
1816 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001817 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
senorblanco9bd5f742016-02-17 10:59:47 -08001818 SkString temp;
1819 temp.appendf("temp%d", index);
1820 fragBuilder->codeAppendf("vec4 %s;", temp.c_str());
1821 fDomain.sampleTexture(fragBuilder,
1822 args.fUniformHandler,
1823 args.fGLSLCaps,
1824 le.domain(),
1825 temp.c_str(),
1826 texCoords,
cdalton3f6f76f2016-04-11 12:18:09 -07001827 args.fTexSamplers[0]);
senorblanco9bd5f742016-02-17 10:59:47 -08001828 fragBuilder->codeAppendf("m[%d] = %s.a;", index, temp.c_str());
1829 index++;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001830 }
1831 }
egdaniel4ca2e602015-11-18 08:01:26 -08001832 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001833 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001834 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001835 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001836 fragBuilder->codeAppend(";\n");
1837 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1838 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001839 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001840 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001841 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001842 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001843 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001844}
1845
joshualittb0a8a372014-09-23 09:50:21 -07001846void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001847 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001848 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1849 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco9bd5f742016-02-17 10:59:47 -08001850 b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001851}
1852
egdaniel018fb622015-10-28 07:26:40 -07001853void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1854 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001855 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001856 if (!fLight) {
1857 fLight = lighting.light()->createGLLight();
1858 }
1859
bsalomon@google.comc7818882013-03-20 19:19:53 +00001860 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001861 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001862 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1863 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001864 SkAutoTUnref<SkImageFilterLight> transformedLight(
1865 lighting.light()->transform(lighting.filterMatrix()));
senorblanco9bd5f742016-02-17 10:59:47 -08001866 fDomain.setData(pdman, lighting.domain(), texture->origin());
kkinnunen7510b222014-07-30 00:04:16 -07001867 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001868}
1869
1870///////////////////////////////////////////////////////////////////////////////
1871
1872///////////////////////////////////////////////////////////////////////////////
1873
egdaniel7ea439b2015-12-03 09:20:44 -08001874void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001875 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001876 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001877 const char* kd;
cdalton5e58cee2016-02-11 12:49:47 -08001878 fKDUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
bsalomon422f56f2014-12-09 10:18:12 -08001879 kFloat_GrSLType, kDefault_GrSLPrecision,
1880 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001881
egdaniel0d3f0612015-10-21 10:45:48 -07001882 static const GrGLSLShaderVar gLightArgs[] = {
1883 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1884 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1885 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001886 };
1887 SkString lightBody;
1888 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1889 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001890 fragBuilder->emitFunction(kVec4f_GrSLType,
1891 "light",
1892 SK_ARRAY_COUNT(gLightArgs),
1893 gLightArgs,
1894 lightBody.c_str(),
1895 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001896}
1897
egdaniel018fb622015-10-28 07:26:40 -07001898void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1899 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001900 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001901 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001902 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001903}
1904
1905///////////////////////////////////////////////////////////////////////////////
1906
bsalomon4a339522015-10-06 08:40:50 -07001907GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001908 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001909 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001910 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001911 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001912 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -08001913 BoundaryMode boundaryMode,
1914 const SkIRect* srcBounds)
1915 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode, srcBounds)
robertphillips2f0dbc72015-08-20 05:15:06 -07001916 , fKS(ks)
1917 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001918 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001919}
1920
bsalomon0e08fc12014-10-15 08:19:04 -07001921bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001922 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001923 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001924 this->ks() == s.ks() &&
1925 this->shininess() == s.shininess();
1926}
1927
egdaniel57d3b032015-11-13 11:57:27 -08001928void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1929 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001930 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1931}
1932
egdaniel57d3b032015-11-13 11:57:27 -08001933GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001934 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001935}
1936
joshualittb0a8a372014-09-23 09:50:21 -07001937GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001938
bsalomonc21b09e2015-08-28 18:46:56 -07001939const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
senorblanco9bd5f742016-02-17 10:59:47 -08001940 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
1941 GrProcessorUnitTest::kAlphaTextureIdx;
1942 GrTexture* tex = d->fTextures[texIdx];
joshualitt0067ff52015-07-08 14:26:19 -07001943 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1944 SkScalar ks = d->fRandom->nextUScalar1();
1945 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001946 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001947 SkMatrix matrix;
1948 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001949 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001950 }
joshualitt0067ff52015-07-08 14:26:19 -07001951 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
senorblanco9bd5f742016-02-17 10:59:47 -08001952 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, tex->width()),
1953 d->fRandom->nextRangeU(0, tex->height()),
1954 d->fRandom->nextRangeU(0, tex->width()),
1955 d->fRandom->nextRangeU(0, tex->height()));
bsalomon4a339522015-10-06 08:40:50 -07001956 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco9bd5f742016-02-17 10:59:47 -08001957 light, surfaceScale, matrix, ks, shininess, mode,
1958 &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001959}
1960
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001961///////////////////////////////////////////////////////////////////////////////
1962
egdaniel7ea439b2015-12-03 09:20:44 -08001963void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001964 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001965 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001966 const char* ks;
1967 const char* shininess;
1968
cdalton5e58cee2016-02-11 12:49:47 -08001969 fKSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001970 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
cdalton5e58cee2016-02-11 12:49:47 -08001971 fShininessUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001972 kFloat_GrSLType,
1973 kDefault_GrSLPrecision,
1974 "Shininess",
1975 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001976
egdaniel0d3f0612015-10-21 10:45:48 -07001977 static const GrGLSLShaderVar gLightArgs[] = {
1978 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1979 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1980 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001981 };
1982 SkString lightBody;
1983 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1984 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001985 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1986 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001987 fragBuilder->emitFunction(kVec4f_GrSLType,
1988 "light",
1989 SK_ARRAY_COUNT(gLightArgs),
1990 gLightArgs,
1991 lightBody.c_str(),
1992 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001993}
1994
egdaniel018fb622015-10-28 07:26:40 -07001995void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1996 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001997 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001998 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001999 pdman.set1f(fKSUni, spec.ks());
2000 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002001}
2002
2003///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08002004void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
cdalton5e58cee2016-02-11 12:49:47 -08002005 fColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002006 kVec3f_GrSLType, kDefault_GrSLPrecision,
2007 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002008}
2009
egdaniel7ea439b2015-12-03 09:20:44 -08002010void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002011 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002012 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08002013 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002014}
2015
egdaniel018fb622015-10-28 07:26:40 -07002016void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002017 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07002018 setUniformPoint3(pdman, fColorUni,
2019 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002020}
2021
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002022///////////////////////////////////////////////////////////////////////////////
2023
egdaniel018fb622015-10-28 07:26:40 -07002024void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002025 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002026 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002027 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002028 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002029 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002030}
2031
egdaniel7ea439b2015-12-03 09:20:44 -08002032void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002033 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002034 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002035 const char* dir;
cdalton5e58cee2016-02-11 12:49:47 -08002036 fDirectionUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002037 kVec3f_GrSLType, kDefault_GrSLPrecision,
2038 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08002039 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002040}
2041
2042///////////////////////////////////////////////////////////////////////////////
2043
egdaniel018fb622015-10-28 07:26:40 -07002044void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002045 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002046 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002047 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002048 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002049 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002050}
2051
egdaniel7ea439b2015-12-03 09:20:44 -08002052void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002053 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002054 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002055 const char* loc;
cdalton5e58cee2016-02-11 12:49:47 -08002056 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002057 kVec3f_GrSLType, kDefault_GrSLPrecision,
2058 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08002059 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2060 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002061}
2062
2063///////////////////////////////////////////////////////////////////////////////
2064
egdaniel018fb622015-10-28 07:26:40 -07002065void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002066 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002067 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002068 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002069 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002070 setUniformPoint3(pdman, fLocationUni, spotLight->location());
2071 pdman.set1f(fExponentUni, spotLight->specularExponent());
2072 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
2073 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
2074 pdman.set1f(fConeScaleUni, spotLight->coneScale());
2075 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002076}
2077
egdaniel7ea439b2015-12-03 09:20:44 -08002078void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002079 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002080 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002081 const char* location;
cdalton5e58cee2016-02-11 12:49:47 -08002082 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002083 kVec3f_GrSLType, kDefault_GrSLPrecision,
2084 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07002085
egdaniel4ca2e602015-11-18 08:01:26 -08002086 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2087 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002088}
2089
egdaniel7ea439b2015-12-03 09:20:44 -08002090void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002091 GrGLSLFPFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002092 const char *surfaceToLight) {
2093
egdaniel7ea439b2015-12-03 09:20:44 -08002094 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002095
2096 const char* exponent;
2097 const char* cosInner;
2098 const char* cosOuter;
2099 const char* coneScale;
2100 const char* s;
cdalton5e58cee2016-02-11 12:49:47 -08002101 fExponentUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002102 kFloat_GrSLType, kDefault_GrSLPrecision,
2103 "Exponent", &exponent);
cdalton5e58cee2016-02-11 12:49:47 -08002104 fCosInnerConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002105 kFloat_GrSLType, kDefault_GrSLPrecision,
2106 "CosInnerConeAngle", &cosInner);
cdalton5e58cee2016-02-11 12:49:47 -08002107 fCosOuterConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002108 kFloat_GrSLType, kDefault_GrSLPrecision,
2109 "CosOuterConeAngle", &cosOuter);
cdalton5e58cee2016-02-11 12:49:47 -08002110 fConeScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002111 kFloat_GrSLType, kDefault_GrSLPrecision,
2112 "ConeScale", &coneScale);
cdalton5e58cee2016-02-11 12:49:47 -08002113 fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002114 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002115
egdaniel0d3f0612015-10-21 10:45:48 -07002116 static const GrGLSLShaderVar gLightColorArgs[] = {
2117 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002118 };
2119 SkString lightColorBody;
2120 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2121 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2122 lightColorBody.appendf("\t\treturn vec3(0);\n");
2123 lightColorBody.appendf("\t}\n");
2124 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2125 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2126 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2127 color, cosOuter, coneScale);
2128 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002129 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002130 fragBuilder->emitFunction(kVec3f_GrSLType,
2131 "lightColor",
2132 SK_ARRAY_COUNT(gLightColorArgs),
2133 gLightColorArgs,
2134 lightColorBody.c_str(),
2135 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002136
egdaniel4ca2e602015-11-18 08:01:26 -08002137 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002138}
2139
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002140#endif
2141
djsollen@google.com08337772012-06-26 14:33:13 +00002142SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2143 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2144 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002145SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END