blob: 4be9f17db5f2be984ecc889fe81c8ff2cb6510ba [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"
egdaniel64c47282015-11-13 06:54:19 -080025#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080026#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080028#include "glsl/GrGLSLUniformHandler.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000029
30class GrGLDiffuseLightingEffect;
31class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000032
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000033// For brevity
egdaniel018fb622015-10-28 07:26:40 -070034typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000035#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000036
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037namespace {
38
reed80ea19c2015-05-12 10:37:34 -070039const SkScalar gOneThird = SkIntToScalar(1) / 3;
40const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000041const SkScalar gOneHalf = 0.5f;
42const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000043
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000044#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070045void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070046 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070047 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070048 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000049}
50
egdaniel018fb622015-10-28 07:26:40 -070051void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070052 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070053 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000054}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000055#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000056
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000057// Shift matrix components to the left, as we advance pixels to the right.
58inline void shiftMatrixLeft(int m[9]) {
59 m[0] = m[1];
60 m[3] = m[4];
61 m[6] = m[7];
62 m[1] = m[2];
63 m[4] = m[5];
64 m[7] = m[8];
65}
66
jvanverth992c7612015-07-17 07:22:30 -070067static inline void fast_normalize(SkPoint3* vector) {
68 // add a tiny bit so we don't have to worry about divide-by-zero
69 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
70 SkScalar scale = sk_float_rsqrt(magSq);
71 vector->fX *= scale;
72 vector->fY *= scale;
73 vector->fZ *= scale;
74}
75
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000076class DiffuseLightingType {
77public:
78 DiffuseLightingType(SkScalar kd)
79 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070080 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
81 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000082 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
83 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070084 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000086 SkClampMax(SkScalarRoundToInt(color.fX), 255),
87 SkClampMax(SkScalarRoundToInt(color.fY), 255),
88 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000089 }
90private:
91 SkScalar fKD;
92};
93
robertphillips3d32d762015-07-13 13:16:44 -070094static SkScalar max_component(const SkPoint3& p) {
95 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
96}
97
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000098class SpecularLightingType {
99public:
100 SpecularLightingType(SkScalar ks, SkScalar shininess)
101 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700102 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
103 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000104 SkPoint3 halfDir(surfaceTolight);
105 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700106 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000107 SkScalar colorScale = SkScalarMul(fKS,
108 SkScalarPow(normal.dot(halfDir), fShininess));
109 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700110 SkPoint3 color = lightColor.makeScale(colorScale);
111 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000112 SkClampMax(SkScalarRoundToInt(color.fX), 255),
113 SkClampMax(SkScalarRoundToInt(color.fY), 255),
114 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000115 }
116private:
117 SkScalar fKS;
118 SkScalar fShininess;
119};
120
121inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
122 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
123}
124
125inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700126 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
127 SkScalarMul(-y, surfaceScale),
128 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700129 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000130 return vector;
131}
132
133inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
134 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
135 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
136 surfaceScale);
137}
138
139inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
141 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
142 surfaceScale);
143}
144
145inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
147 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
148 surfaceScale);
149}
150
151inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
153 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
154 surfaceScale);
155}
156
157
158inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
160 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
161 surfaceScale);
162}
163
164inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
165 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
166 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
167 surfaceScale);
168}
169
170inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
171 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
172 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
173 surfaceScale);
174}
175
176inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
177 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
178 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
179 surfaceScale);
180}
181
182inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
183 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
184 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
185 surfaceScale);
186}
187
senorblanco84f0e742016-02-16 13:26:56 -0800188
189class UncheckedPixelFetcher {
190public:
191 static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
192 return SkGetPackedA32(*src.getAddr32(x, y));
193 }
194};
195
196// The DecalPixelFetcher is used when the destination crop rect exceeds the input bitmap bounds.
197class DecalPixelFetcher {
198public:
199 static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
200 if (x < bounds.fLeft || x >= bounds.fRight || y < bounds.fTop || y >= bounds.fBottom) {
201 return 0;
202 } else {
203 return SkGetPackedA32(*src.getAddr32(x, y));
204 }
205 }
206};
207
208template <class LightingType, class LightType, class PixelFetcher>
209void lightBitmap(const LightingType& lightingType,
210 const SkImageFilterLight* light,
211 const SkBitmap& src,
212 SkBitmap* dst,
213 SkScalar surfaceScale,
214 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000215 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000217 int left = bounds.left(), right = bounds.right();
218 int bottom = bounds.bottom();
219 int y = bounds.top();
senorblanco84f0e742016-02-16 13:26:56 -0800220 SkIRect srcBounds = src.bounds();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000221 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000222 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000223 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000224 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800225 m[4] = PixelFetcher::Fetch(src, x, y, srcBounds);
226 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
227 m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds);
228 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000229 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700230 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
231 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000232 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 {
234 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800235 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
236 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000237 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700238 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
239 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 }
241 shiftMatrixLeft(m);
242 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700243 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
244 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000245 }
246
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000247 for (++y; y < bottom - 1; ++y) {
248 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000249 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800250 m[1] = PixelFetcher::Fetch(src, x, y - 1, srcBounds);
251 m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
252 m[4] = PixelFetcher::Fetch(src, x, y, srcBounds);
253 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
254 m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds);
255 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000256 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700257 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
258 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000259 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000260 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800261 m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
262 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
263 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700265 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
266 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000267 }
268 shiftMatrixLeft(m);
269 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700270 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
271 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000272 }
273
274 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000275 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000276 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800277 m[1] = PixelFetcher::Fetch(src, x, bottom - 2, srcBounds);
278 m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
279 m[4] = PixelFetcher::Fetch(src, x, bottom - 1, srcBounds);
280 m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000281 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700282 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
283 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000284 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000285 {
286 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800287 m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
288 m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700290 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
291 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000292 }
293 shiftMatrixLeft(m);
294 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700295 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
296 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297 }
298}
299
senorblanco84f0e742016-02-16 13:26:56 -0800300template <class LightingType, class LightType>
301void lightBitmap(const LightingType& lightingType,
302 const SkImageFilterLight* light,
303 const SkBitmap& src,
304 SkBitmap* dst,
305 SkScalar surfaceScale,
306 const SkIRect& bounds) {
307 if (src.bounds().contains(bounds)) {
308 lightBitmap<LightingType, LightType, UncheckedPixelFetcher>(
309 lightingType, light, src, dst, surfaceScale, bounds);
310 } else {
311 lightBitmap<LightingType, LightType, DecalPixelFetcher>(
312 lightingType, light, src, dst, surfaceScale, bounds);
313 }
314}
315
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000316SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000317 SkPoint3 point;
318 point.fX = buffer.readScalar();
319 point.fY = buffer.readScalar();
320 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000321 buffer.validate(SkScalarIsFinite(point.fX) &&
322 SkScalarIsFinite(point.fY) &&
323 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000324 return point;
325};
326
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000327void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000328 buffer.writeScalar(point.fX);
329 buffer.writeScalar(point.fY);
330 buffer.writeScalar(point.fZ);
331};
332
senorblancod0d37ca2015-04-02 04:54:56 -0700333enum BoundaryMode {
334 kTopLeft_BoundaryMode,
335 kTop_BoundaryMode,
336 kTopRight_BoundaryMode,
337 kLeft_BoundaryMode,
338 kInterior_BoundaryMode,
339 kRight_BoundaryMode,
340 kBottomLeft_BoundaryMode,
341 kBottom_BoundaryMode,
342 kBottomRight_BoundaryMode,
343
344 kBoundaryModeCount,
345};
346
347class SkLightingImageFilterInternal : public SkLightingImageFilter {
348protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700349 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700350 SkScalar surfaceScale,
351 SkImageFilter* input,
352 const CropRect* cropRect)
353 : INHERITED(light, surfaceScale, input, cropRect) {}
354
355#if SK_SUPPORT_GPU
356 bool canFilterImageGPU() const override { return true; }
357 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
358 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700359 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700360 const SkMatrix&,
361 const SkIRect& bounds,
362 BoundaryMode boundaryMode) const = 0;
363#endif
364private:
365#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700366 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700367 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700368 const SkMatrix& matrix,
369 const GrClip& clip,
370 const SkRect& dstRect,
371 BoundaryMode boundaryMode,
372 const SkIRect& bounds) const;
373#endif
374 typedef SkLightingImageFilter INHERITED;
375};
376
377#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700378void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700379 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700380 const SkMatrix& matrix,
381 const GrClip& clip,
382 const SkRect& dstRect,
383 BoundaryMode boundaryMode,
384 const SkIRect& bounds) const {
385 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700386 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700387 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700388 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800389 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800390 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700391}
392
393bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
394 const SkBitmap& src,
395 const Context& ctx,
396 SkBitmap* result,
397 SkIPoint* offset) const {
398 SkBitmap input = src;
399 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700400 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700401 return false;
402 }
403 SkIRect bounds;
404 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
405 return false;
406 }
407 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
408 SkIntToScalar(bounds.height()));
409 GrTexture* srcTexture = input.getTexture();
410 GrContext* context = srcTexture->getContext();
411
412 GrSurfaceDesc desc;
413 desc.fFlags = kRenderTarget_GrSurfaceFlag,
414 desc.fWidth = bounds.width();
415 desc.fHeight = bounds.height();
416 desc.fConfig = kRGBA_8888_GrPixelConfig;
417
reed4e23cda2016-01-11 10:56:59 -0800418 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700419 if (!dst) {
420 return false;
421 }
422
423 // setup new clip
424 GrClip clip(dstRect);
425
426 offset->fX = bounds.left();
427 offset->fY = bounds.top();
428 SkMatrix matrix(ctx.ctm());
429 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
430 bounds.offset(-srcOffset);
431 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
432 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
433 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
434 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
435 SkRect interior = dstRect.makeInset(1, 1);
436 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
437 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
438 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
439 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700440
robertphillips2e1e51f2015-10-15 08:01:48 -0700441 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700442 if (!drawContext) {
443 return false;
444 }
445
robertphillips2e1e51f2015-10-15 08:01:48 -0700446 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
447 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
448 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700449 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700450 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
451 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700452 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700453 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
454 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700455 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700456 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
457 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700458 kBottomRight_BoundaryMode, bounds);
robertphillips1de87df2016-01-14 06:03:29 -0800459 GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
senorblancod0d37ca2015-04-02 04:54:56 -0700460 return true;
461}
462#endif
463
464class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000465public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700466 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
467 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700468 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700469
robertphillipsf3f5bad2014-12-19 13:49:15 -0800470 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000472 SkScalar kd() const { return fKD; }
473
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700475 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700476 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700477 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700478 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
479 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000480#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700481 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
482 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000483#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000484
485private:
reed9fa60da2014-08-21 07:59:51 -0700486 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700487 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000488 SkScalar fKD;
489};
490
senorblancod0d37ca2015-04-02 04:54:56 -0700491class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000492public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700493 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700494 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700495
robertphillipsf3f5bad2014-12-19 13:49:15 -0800496 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000497 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
498
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000499 SkScalar ks() const { return fKS; }
500 SkScalar shininess() const { return fShininess; }
501
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000502protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700503 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700504 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700505 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700506 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
507 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000508#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700509 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
510 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000511#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000512
513private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000514 SkScalar fKS;
515 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700516 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700517 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000518};
519
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000520#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000521
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000522class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000523public:
bsalomon4a339522015-10-06 08:40:50 -0700524 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
525 const SkMatrix& matrix, BoundaryMode boundaryMode);
robertphillipse004bfc2015-11-16 09:06:59 -0800526 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527
robertphillips2f0dbc72015-08-20 05:15:06 -0700528 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000530 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700531 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000532
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000533protected:
mtklein36352bf2015-03-25 18:17:31 -0700534 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000535
mtklein36352bf2015-03-25 18:17:31 -0700536 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700537 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800538 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700539 }
540
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000541private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700542 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000543 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000544 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700545 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700546
547 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000548};
549
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000550class GrDiffuseLightingEffect : public GrLightingEffect {
551public:
bsalomon4a339522015-10-06 08:40:50 -0700552 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700553 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700554 SkScalar surfaceScale,
555 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700556 SkScalar kd,
557 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700558 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000559 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000560
mtklein36352bf2015-03-25 18:17:31 -0700561 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000562
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000563 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000564
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565private:
egdaniel57d3b032015-11-13 11:57:27 -0800566 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700567
egdaniel57d3b032015-11-13 11:57:27 -0800568 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700569
mtklein36352bf2015-03-25 18:17:31 -0700570 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000571
bsalomon4a339522015-10-06 08:40:50 -0700572 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700573 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000574 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000575 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700576 SkScalar kd,
577 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000578
joshualittb0a8a372014-09-23 09:50:21 -0700579 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000580 typedef GrLightingEffect INHERITED;
581 SkScalar fKD;
582};
583
584class GrSpecularLightingEffect : public GrLightingEffect {
585public:
bsalomon4a339522015-10-06 08:40:50 -0700586 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700587 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700588 SkScalar surfaceScale,
589 const SkMatrix& matrix,
590 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700591 SkScalar shininess,
592 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700593 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
594 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000595 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000596
mtklein36352bf2015-03-25 18:17:31 -0700597 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000598
egdaniel57d3b032015-11-13 11:57:27 -0800599 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800600
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000601 SkScalar ks() const { return fKS; }
602 SkScalar shininess() const { return fShininess; }
603
604private:
egdaniel57d3b032015-11-13 11:57:27 -0800605 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700606
mtklein36352bf2015-03-25 18:17:31 -0700607 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000608
bsalomon4a339522015-10-06 08:40:50 -0700609 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700610 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000611 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000612 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000613 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700614 SkScalar shininess,
615 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000616
joshualittb0a8a372014-09-23 09:50:21 -0700617 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000618 typedef GrLightingEffect INHERITED;
619 SkScalar fKS;
620 SkScalar fShininess;
621};
622
623///////////////////////////////////////////////////////////////////////////////
624
625class GrGLLight {
626public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000627 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000628
629 /**
630 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
631 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
632 */
egdaniel7ea439b2015-12-03 09:20:44 -0800633 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000634
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000635 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000636 * These two functions are called from GrGLLightingEffect's emitCode() function.
637 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
638 * the light. The expression will be used in the FS. emitLightColor writes an expression into
639 * the FS that is the color of the light. Either function may add functions and/or uniforms to
640 * the FS. The default of emitLightColor appends the name of the constant light color uniform
641 * and so this function only needs to be overridden if the light color varies spatially.
642 */
egdaniel7ea439b2015-12-03 09:20:44 -0800643 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
644 GrGLSLFragmentBuilder*,
645 const char* z) = 0;
646 virtual void emitLightColor(GrGLSLUniformHandler*,
egdaniel4ca2e602015-11-18 08:01:26 -0800647 GrGLSLFragmentBuilder*,
648 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000649
650 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
651 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700652 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000653
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000654protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000655 /**
656 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
657 * function.
658 */
659 UniformHandle lightColorUni() const { return fColorUni; }
660
661private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000662 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000663
664 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000665};
666
667///////////////////////////////////////////////////////////////////////////////
668
669class GrGLDistantLight : public GrGLLight {
670public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000671 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700672 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800673 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000674
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000675private:
676 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000677 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000678};
679
680///////////////////////////////////////////////////////////////////////////////
681
682class GrGLPointLight : public GrGLLight {
683public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000684 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700685 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800686 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000687
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000688private:
689 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000690 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000691};
692
693///////////////////////////////////////////////////////////////////////////////
694
695class GrGLSpotLight : public GrGLLight {
696public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000697 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700698 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800699 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
700 void emitLightColor(GrGLSLUniformHandler*,
egdaniel4ca2e602015-11-18 08:01:26 -0800701 GrGLSLFragmentBuilder*,
702 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000703
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000704private:
705 typedef GrGLLight INHERITED;
706
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000707 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000708 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000709 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000710 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000711 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000712 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000713 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000714};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000715#else
716
717class GrGLLight;
718
719#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000720
721};
722
723///////////////////////////////////////////////////////////////////////////////
724
robertphillips2f0dbc72015-08-20 05:15:06 -0700725class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000726public:
caryclark0bccd872015-10-20 10:04:03 -0700727
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000728
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000729 enum LightType {
730 kDistant_LightType,
731 kPoint_LightType,
732 kSpot_LightType,
733 };
734 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000735 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000736 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700737 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000738 return fColor == other.fColor;
739 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000740 // Called to know whether the generated GrGLLight will require access to the fragment position.
741 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700742 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000744 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000745 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700746 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000747
djsollen@google.com08337772012-06-26 14:33:13 +0000748protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700749 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700750 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
751 SkIntToScalar(SkColorGetG(color)),
752 SkIntToScalar(SkColorGetB(color)));
753 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700754 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000755 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700756 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000757 fColor = readPoint3(buffer);
758 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000759
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000760 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000761
djsollen@google.com08337772012-06-26 14:33:13 +0000762
763private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000764 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000765 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000766};
767
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000768///////////////////////////////////////////////////////////////////////////////
769
robertphillips2f0dbc72015-08-20 05:15:06 -0700770class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000771public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000772 SkDistantLight(const SkPoint3& direction, SkColor color)
773 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774 }
djsollen@google.com08337772012-06-26 14:33:13 +0000775
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000776 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
777 return fDirection;
778 };
robertphillips3d32d762015-07-13 13:16:44 -0700779 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700780 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000781 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700782 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000783#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700784 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000785#else
786 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700787 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000788#endif
789 }
mtklein36352bf2015-03-25 18:17:31 -0700790 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000791
robertphillips2f0dbc72015-08-20 05:15:06 -0700792 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000793 if (other.type() != kDistant_LightType) {
794 return false;
795 }
796
797 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
798 return INHERITED::isEqual(other) &&
799 fDirection == o.fDirection;
800 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000801
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000802 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000803 fDirection = readPoint3(buffer);
804 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000805
djsollen@google.com08337772012-06-26 14:33:13 +0000806protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000807 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
808 : INHERITED(color), fDirection(direction) {
809 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700810 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000811 return new SkDistantLight(direction(), color());
812 }
mtklein36352bf2015-03-25 18:17:31 -0700813 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000814 writePoint3(fDirection, buffer);
815 }
816
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000817private:
818 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700819
820 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000821};
822
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000823///////////////////////////////////////////////////////////////////////////////
824
robertphillips2f0dbc72015-08-20 05:15:06 -0700825class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000826public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000827 SkPointLight(const SkPoint3& location, SkColor color)
828 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000829
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000830 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700831 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
832 fLocation.fY - SkIntToScalar(y),
833 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
834 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700835 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000836 return direction;
837 };
robertphillips3d32d762015-07-13 13:16:44 -0700838 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700839 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000840 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700841 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000842#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700843 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000844#else
845 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700846 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000847#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000848 }
mtklein36352bf2015-03-25 18:17:31 -0700849 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700850 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000851 if (other.type() != kPoint_LightType) {
852 return false;
853 }
854 const SkPointLight& o = static_cast<const SkPointLight&>(other);
855 return INHERITED::isEqual(other) &&
856 fLocation == o.fLocation;
857 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700858 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000859 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
860 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000861 // Use X scale and Y scale on Z and average the result
862 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
863 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700864 SkPoint3 location = SkPoint3::Make(location2.fX,
865 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700866 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000867 return new SkPointLight(location, color());
868 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000869
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000870 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000871 fLocation = readPoint3(buffer);
872 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000873
874protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000875 SkPointLight(const SkPoint3& location, const SkPoint3& color)
876 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700877 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000878 writePoint3(fLocation, buffer);
879 }
880
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000881private:
882 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700883
884 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000885};
886
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000887///////////////////////////////////////////////////////////////////////////////
888
robertphillips2f0dbc72015-08-20 05:15:06 -0700889class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000890public:
senorblancod0d37ca2015-04-02 04:54:56 -0700891 SkSpotLight(const SkPoint3& location,
892 const SkPoint3& target,
893 SkScalar specularExponent,
894 SkScalar cutoffAngle,
895 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000896 : INHERITED(color),
897 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000898 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700899 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000900 {
901 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700902 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000903 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000904 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000905 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
906 fConeScale = SkScalarInvert(antiAliasThreshold);
907 }
djsollen@google.com08337772012-06-26 14:33:13 +0000908
robertphillips2f0dbc72015-08-20 05:15:06 -0700909 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000910 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
911 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000912 // Use X scale and Y scale on Z and average the result
913 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
914 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700915 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
916 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000917 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
918 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000919 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
920 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700921 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
922 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000923 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700924 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700925 return new SkSpotLight(location,
926 target,
927 fSpecularExponent,
928 fCosOuterConeAngle,
929 fCosInnerConeAngle,
930 fConeScale,
931 s,
932 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000933 }
934
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000935 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700936 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
937 fLocation.fY - SkIntToScalar(y),
938 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
939 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700940 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000941 return direction;
942 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000943 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000944 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700945 SkScalar scale = 0;
946 if (cosAngle >= fCosOuterConeAngle) {
947 scale = SkScalarPow(cosAngle, fSpecularExponent);
948 if (cosAngle < fCosInnerConeAngle) {
949 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
950 scale *= fConeScale;
951 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000952 }
robertphillips3d32d762015-07-13 13:16:44 -0700953 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000954 }
mtklein36352bf2015-03-25 18:17:31 -0700955 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000956#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700957 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000958#else
959 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700960 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000961#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000962 }
mtklein36352bf2015-03-25 18:17:31 -0700963 bool requiresFragmentPosition() const override { return true; }
964 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000965 const SkPoint3& location() const { return fLocation; }
966 const SkPoint3& target() const { return fTarget; }
967 SkScalar specularExponent() const { return fSpecularExponent; }
968 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
969 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
970 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000971 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000972
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000973 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000974 fLocation = readPoint3(buffer);
975 fTarget = readPoint3(buffer);
976 fSpecularExponent = buffer.readScalar();
977 fCosOuterConeAngle = buffer.readScalar();
978 fCosInnerConeAngle = buffer.readScalar();
979 fConeScale = buffer.readScalar();
980 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000981 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
982 SkScalarIsFinite(fCosOuterConeAngle) &&
983 SkScalarIsFinite(fCosInnerConeAngle) &&
984 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000985 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000986protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700987 SkSpotLight(const SkPoint3& location,
988 const SkPoint3& target,
989 SkScalar specularExponent,
990 SkScalar cosOuterConeAngle,
991 SkScalar cosInnerConeAngle,
992 SkScalar coneScale,
993 const SkPoint3& s,
994 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000995 : INHERITED(color),
996 fLocation(location),
997 fTarget(target),
998 fSpecularExponent(specularExponent),
999 fCosOuterConeAngle(cosOuterConeAngle),
1000 fCosInnerConeAngle(cosInnerConeAngle),
1001 fConeScale(coneScale),
1002 fS(s)
1003 {
1004 }
mtklein36352bf2015-03-25 18:17:31 -07001005 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +00001006 writePoint3(fLocation, buffer);
1007 writePoint3(fTarget, buffer);
1008 buffer.writeScalar(fSpecularExponent);
1009 buffer.writeScalar(fCosOuterConeAngle);
1010 buffer.writeScalar(fCosInnerConeAngle);
1011 buffer.writeScalar(fConeScale);
1012 writePoint3(fS, buffer);
1013 }
1014
robertphillips2f0dbc72015-08-20 05:15:06 -07001015 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001016 if (other.type() != kSpot_LightType) {
1017 return false;
1018 }
1019
1020 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1021 return INHERITED::isEqual(other) &&
1022 fLocation == o.fLocation &&
1023 fTarget == o.fTarget &&
1024 fSpecularExponent == o.fSpecularExponent &&
1025 fCosOuterConeAngle == o.fCosOuterConeAngle;
1026 }
1027
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001028private:
caryclark0bccd872015-10-20 10:04:03 -07001029 static const SkScalar kSpecularExponentMin;
1030 static const SkScalar kSpecularExponentMax;
1031
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001032 SkPoint3 fLocation;
1033 SkPoint3 fTarget;
1034 SkScalar fSpecularExponent;
1035 SkScalar fCosOuterConeAngle;
1036 SkScalar fCosInnerConeAngle;
1037 SkScalar fConeScale;
1038 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001039
1040 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001041};
1042
caryclark0bccd872015-10-20 10:04:03 -07001043// According to the spec, the specular term should be in the range [1, 128] :
1044// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1045const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1046const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1047
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001048///////////////////////////////////////////////////////////////////////////////
1049
robertphillips2f0dbc72015-08-20 05:15:06 -07001050void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001051 // Write type first, then baseclass, then subclass.
1052 buffer.writeInt(this->type());
1053 writePoint3(fColor, buffer);
1054 this->onFlattenLight(buffer);
1055}
1056
robertphillips2f0dbc72015-08-20 05:15:06 -07001057/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001058 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001059 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001060 switch (type) {
1061 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1062 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001063 case SkImageFilterLight::kDistant_LightType:
1064 return new SkDistantLight(buffer);
1065 case SkImageFilterLight::kPoint_LightType:
1066 return new SkPointLight(buffer);
1067 case SkImageFilterLight::kSpot_LightType:
1068 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001069 default:
1070 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001071 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001072 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001073 }
1074}
1075///////////////////////////////////////////////////////////////////////////////
1076
robertphillips2f0dbc72015-08-20 05:15:06 -07001077SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001078 SkImageFilter* input, const CropRect* cropRect)
1079 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001080 , fLight(SkRef(light))
1081 , fSurfaceScale(surfaceScale / 255)
1082{}
1083
1084SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1085 SkColor lightColor,
1086 SkScalar surfaceScale,
1087 SkScalar kd,
1088 SkImageFilter* input,
1089 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001090 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001091 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001092}
1093
reed9fa60da2014-08-21 07:59:51 -07001094SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1095 SkColor lightColor,
1096 SkScalar surfaceScale,
1097 SkScalar kd,
1098 SkImageFilter* input,
1099 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001100 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001101 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001102}
1103
reed9fa60da2014-08-21 07:59:51 -07001104SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1105 const SkPoint3& target,
1106 SkScalar specularExponent,
1107 SkScalar cutoffAngle,
1108 SkColor lightColor,
1109 SkScalar surfaceScale,
1110 SkScalar kd,
1111 SkImageFilter* input,
1112 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001113 SkAutoTUnref<SkImageFilterLight> light(
1114 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001115 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001116}
1117
reed9fa60da2014-08-21 07:59:51 -07001118SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1119 SkColor lightColor,
1120 SkScalar surfaceScale,
1121 SkScalar ks,
1122 SkScalar shine,
1123 SkImageFilter* input,
1124 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001125 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001126 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001127}
1128
reed9fa60da2014-08-21 07:59:51 -07001129SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1130 SkColor lightColor,
1131 SkScalar surfaceScale,
1132 SkScalar ks,
1133 SkScalar shine,
1134 SkImageFilter* input,
1135 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001136 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001137 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001138}
1139
reed9fa60da2014-08-21 07:59:51 -07001140SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1141 const SkPoint3& target,
1142 SkScalar specularExponent,
1143 SkScalar cutoffAngle,
1144 SkColor lightColor,
1145 SkScalar surfaceScale,
1146 SkScalar ks,
1147 SkScalar shine,
1148 SkImageFilter* input,
1149 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001150 SkAutoTUnref<SkImageFilterLight> light(
1151 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001152 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001153}
1154
reed9fa60da2014-08-21 07:59:51 -07001155SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001156
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001157void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001158 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001159 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001160 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001161}
1162
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001163///////////////////////////////////////////////////////////////////////////////
1164
robertphillips2f0dbc72015-08-20 05:15:06 -07001165SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1166 SkScalar surfaceScale,
1167 SkScalar kd,
1168 SkImageFilter* input,
1169 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001170 if (nullptr == light) {
1171 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001172 }
1173 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001174 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001175 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001176 // According to the spec, kd can be any non-negative number :
1177 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001178 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001179 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001180 }
halcanary385fe4d2015-08-26 13:07:48 -07001181 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001182}
1183
robertphillips2f0dbc72015-08-20 05:15:06 -07001184SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001185 SkScalar surfaceScale,
1186 SkScalar kd,
1187 SkImageFilter* input,
1188 const CropRect* cropRect)
1189 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001190 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001191{
1192}
1193
reed9fa60da2014-08-21 07:59:51 -07001194SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1195 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001196 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001197 SkScalar surfaceScale = buffer.readScalar();
1198 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001199 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001200}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001201
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001202void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001203 this->INHERITED::flatten(buffer);
1204 buffer.writeScalar(fKD);
1205}
1206
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001207bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1208 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001209 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001210 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001211 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001212 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001213 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001214 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001215 return false;
1216 }
1217
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001218 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001219 return false;
1220 }
senorblanco84f0e742016-02-16 13:26:56 -08001221 SkIRect srcBounds = src.bounds();
1222 srcBounds.offset(srcOffset);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001223 SkIRect bounds;
senorblanco84f0e742016-02-16 13:26:56 -08001224 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001225 return false;
1226 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001227
1228 if (bounds.width() < 2 || bounds.height() < 2) {
1229 return false;
1230 }
1231
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001232 SkAutoLockPixels alp(src);
1233 if (!src.getPixels()) {
1234 return false;
1235 }
1236
senorblanco1d3ff432015-10-20 10:17:34 -07001237 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1238 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001239 return false;
1240 }
senorblanco1d3ff432015-10-20 10:17:34 -07001241 *dst = device->accessBitmap(false);
1242 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001243
senorblanco7b7ecfc2015-08-26 14:26:40 -07001244 SkMatrix matrix(ctx.ctm());
1245 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1246 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001247
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001248 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001249 offset->fX = bounds.left();
1250 offset->fY = bounds.top();
1251 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001252 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001253 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001254 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1255 transformedLight,
1256 src,
1257 dst,
1258 surfaceScale(),
1259 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001260 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001261 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001262 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1263 transformedLight,
1264 src,
1265 dst,
1266 surfaceScale(),
1267 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001268 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001269 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001270 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1271 transformedLight,
1272 src,
1273 dst,
1274 surfaceScale(),
1275 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001276 break;
1277 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001278
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001279 return true;
1280}
1281
robertphillipsf3f5bad2014-12-19 13:49:15 -08001282#ifndef SK_IGNORE_TO_STRING
1283void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1284 str->appendf("SkDiffuseLightingImageFilter: (");
1285 str->appendf("kD: %f\n", fKD);
1286 str->append(")");
1287}
1288#endif
1289
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001290#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001291GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001292 GrTexture* texture,
1293 const SkMatrix& matrix,
1294 const SkIRect&,
1295 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001296) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001297 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001298 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1299 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001300}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001301#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001302
1303///////////////////////////////////////////////////////////////////////////////
1304
robertphillips2f0dbc72015-08-20 05:15:06 -07001305SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1306 SkScalar surfaceScale,
1307 SkScalar ks,
1308 SkScalar shininess,
1309 SkImageFilter* input,
1310 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001311 if (nullptr == light) {
1312 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001313 }
1314 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001315 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001316 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001317 // According to the spec, ks can be any non-negative number :
1318 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001319 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001320 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001321 }
halcanary385fe4d2015-08-26 13:07:48 -07001322 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001323}
1324
robertphillips2f0dbc72015-08-20 05:15:06 -07001325SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001326 SkScalar surfaceScale,
1327 SkScalar ks,
1328 SkScalar shininess,
1329 SkImageFilter* input,
1330 const CropRect* cropRect)
1331 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001332 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001333 fShininess(shininess)
1334{
1335}
1336
reed9fa60da2014-08-21 07:59:51 -07001337SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1338 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001339 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001340 SkScalar surfaceScale = buffer.readScalar();
1341 SkScalar ks = buffer.readScalar();
1342 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001343 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001344}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001345
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001346void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001347 this->INHERITED::flatten(buffer);
1348 buffer.writeScalar(fKS);
1349 buffer.writeScalar(fShininess);
1350}
1351
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001352bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1353 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001354 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001355 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001356 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001357 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001358 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001359 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001360 return false;
1361 }
1362
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001363 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001364 return false;
1365 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001366
senorblanco84f0e742016-02-16 13:26:56 -08001367 SkIRect srcBounds = src.bounds();
1368 srcBounds.offset(srcOffset);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001369 SkIRect bounds;
senorblanco84f0e742016-02-16 13:26:56 -08001370 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001371 return false;
1372 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001373
1374 if (bounds.width() < 2 || bounds.height() < 2) {
1375 return false;
1376 }
1377
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001378 SkAutoLockPixels alp(src);
1379 if (!src.getPixels()) {
1380 return false;
1381 }
1382
senorblanco1d3ff432015-10-20 10:17:34 -07001383 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1384 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001385 return false;
1386 }
senorblanco1d3ff432015-10-20 10:17:34 -07001387 *dst = device->accessBitmap(false);
1388 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001389
1390 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001391 offset->fX = bounds.left();
1392 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001393 SkMatrix matrix(ctx.ctm());
1394 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1395 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001396 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001397 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001398 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001399 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1400 transformedLight,
1401 src,
1402 dst,
1403 surfaceScale(),
1404 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001405 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001406 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001407 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1408 transformedLight,
1409 src,
1410 dst,
1411 surfaceScale(),
1412 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001413 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001414 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001415 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1416 transformedLight,
1417 src,
1418 dst,
1419 surfaceScale(),
1420 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001421 break;
1422 }
1423 return true;
1424}
1425
robertphillipsf3f5bad2014-12-19 13:49:15 -08001426#ifndef SK_IGNORE_TO_STRING
1427void SkSpecularLightingImageFilter::toString(SkString* str) const {
1428 str->appendf("SkSpecularLightingImageFilter: (");
1429 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1430 str->append(")");
1431}
1432#endif
1433
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001434#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001435GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001436 GrTexture* texture,
1437 const SkMatrix& matrix,
1438 const SkIRect&,
1439 BoundaryMode boundaryMode) const {
1440 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001441 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1442 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001443}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001444#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001445
1446///////////////////////////////////////////////////////////////////////////////
1447
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001448#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001449
1450namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001451SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001452 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1453 SkScalarToFloat(random->nextSScalar1()),
1454 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001455}
1456
robertphillips2f0dbc72015-08-20 05:15:06 -07001457SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001458 int type = random->nextULessThan(3);
1459 switch (type) {
1460 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001461 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001462 }
1463 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001464 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001465 }
1466 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001467 return new SkSpotLight(random_point3(random), random_point3(random),
1468 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001469 }
1470 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001471 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001472 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001473 }
1474}
1475
senorblancod0d37ca2015-04-02 04:54:56 -07001476SkString emitNormalFunc(BoundaryMode mode,
1477 const char* pointToNormalName,
1478 const char* sobelFuncName) {
1479 SkString result;
1480 switch (mode) {
1481 case kTopLeft_BoundaryMode:
1482 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1483 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1484 "\t surfaceScale);\n",
1485 pointToNormalName, sobelFuncName, gTwoThirds,
1486 sobelFuncName, gTwoThirds);
1487 break;
1488 case kTop_BoundaryMode:
1489 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1490 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1491 "\t surfaceScale);\n",
1492 pointToNormalName, sobelFuncName, gOneThird,
1493 sobelFuncName, gOneHalf);
1494 break;
1495 case kTopRight_BoundaryMode:
1496 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1497 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1498 "\t surfaceScale);\n",
1499 pointToNormalName, sobelFuncName, gTwoThirds,
1500 sobelFuncName, gTwoThirds);
1501 break;
1502 case kLeft_BoundaryMode:
1503 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1504 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1505 "\t surfaceScale);\n",
1506 pointToNormalName, sobelFuncName, gOneHalf,
1507 sobelFuncName, gOneThird);
1508 break;
1509 case kInterior_BoundaryMode:
1510 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1511 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1512 "\t surfaceScale);\n",
1513 pointToNormalName, sobelFuncName, gOneQuarter,
1514 sobelFuncName, gOneQuarter);
1515 break;
1516 case kRight_BoundaryMode:
1517 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1518 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1519 "\t surfaceScale);\n",
1520 pointToNormalName, sobelFuncName, gOneHalf,
1521 sobelFuncName, gOneThird);
1522 break;
1523 case kBottomLeft_BoundaryMode:
1524 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1525 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1526 "\t surfaceScale);\n",
1527 pointToNormalName, sobelFuncName, gTwoThirds,
1528 sobelFuncName, gTwoThirds);
1529 break;
1530 case kBottom_BoundaryMode:
1531 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1532 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1533 "\t surfaceScale);\n",
1534 pointToNormalName, sobelFuncName, gOneThird,
1535 sobelFuncName, gOneHalf);
1536 break;
1537 case kBottomRight_BoundaryMode:
1538 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1539 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1540 "\t surfaceScale);\n",
1541 pointToNormalName, sobelFuncName, gTwoThirds,
1542 sobelFuncName, gTwoThirds);
1543 break;
1544 default:
1545 SkASSERT(false);
1546 break;
1547 }
1548 return result;
1549}
1550
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001551}
1552
egdaniel64c47282015-11-13 06:54:19 -08001553class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001554public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001555 GrGLLightingEffect() : fLight(nullptr) { }
1556 virtual ~GrGLLightingEffect() { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001557
wangyix7c157a92015-07-22 15:08:53 -07001558 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001559
jvanverthcfc18862015-04-28 08:48:20 -07001560 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001561
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001562protected:
wangyixb1daa862015-08-18 11:29:31 -07001563 /**
1564 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1565 */
egdaniel018fb622015-10-28 07:26:40 -07001566 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001567
egdaniel7ea439b2015-12-03 09:20:44 -08001568 virtual void emitLightFunc(GrGLSLUniformHandler*,
1569 GrGLSLFragmentBuilder*,
1570 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001571
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001572private:
egdaniel64c47282015-11-13 06:54:19 -08001573 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001574
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001575 UniformHandle fImageIncrementUni;
1576 UniformHandle fSurfaceScaleUni;
1577 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001578};
1579
1580///////////////////////////////////////////////////////////////////////////////
1581
1582class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1583public:
egdaniel7ea439b2015-12-03 09:20:44 -08001584 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001585
1586protected:
egdaniel018fb622015-10-28 07:26:40 -07001587 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001588
1589private:
1590 typedef GrGLLightingEffect INHERITED;
1591
bsalomon@google.com032b2212012-07-16 13:36:18 +00001592 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001593};
1594
1595///////////////////////////////////////////////////////////////////////////////
1596
1597class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1598public:
egdaniel7ea439b2015-12-03 09:20:44 -08001599 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001600
1601protected:
egdaniel018fb622015-10-28 07:26:40 -07001602 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001603
1604private:
1605 typedef GrGLLightingEffect INHERITED;
1606
bsalomon@google.com032b2212012-07-16 13:36:18 +00001607 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001608 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001609};
1610
1611///////////////////////////////////////////////////////////////////////////////
1612
bsalomon4a339522015-10-06 08:40:50 -07001613GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001614 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001615 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001616 const SkMatrix& matrix,
1617 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001618 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001619 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001620 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001621 , fFilterMatrix(matrix)
1622 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001623 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001624 if (light->requiresFragmentPosition()) {
1625 this->setWillReadFragmentPosition();
1626 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001627}
1628
1629GrLightingEffect::~GrLightingEffect() {
1630 fLight->unref();
1631}
1632
bsalomon0e08fc12014-10-15 08:19:04 -07001633bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001634 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001635 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001636 fSurfaceScale == s.fSurfaceScale &&
1637 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638}
1639
1640///////////////////////////////////////////////////////////////////////////////
1641
bsalomon4a339522015-10-06 08:40:50 -07001642GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001643 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001644 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001645 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001646 SkScalar kd,
1647 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001648 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001649 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001650}
1651
bsalomon0e08fc12014-10-15 08:19:04 -07001652bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001653 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001654 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001655}
1656
egdaniel57d3b032015-11-13 11:57:27 -08001657void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1658 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001659 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1660}
1661
egdaniel57d3b032015-11-13 11:57:27 -08001662GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001663 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001664}
1665
joshualittb0a8a372014-09-23 09:50:21 -07001666GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001667
bsalomonc21b09e2015-08-28 18:46:56 -07001668const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001669 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1670 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001671 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001672 SkMatrix matrix;
1673 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001674 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001675 }
joshualitt0067ff52015-07-08 14:26:19 -07001676 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001677 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001678 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001679}
1680
1681
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001682///////////////////////////////////////////////////////////////////////////////
1683
wangyix7c157a92015-07-22 15:08:53 -07001684void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001685 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1686 if (!fLight) {
1687 fLight = le.light()->createGLLight();
1688 }
1689
egdaniel7ea439b2015-12-03 09:20:44 -08001690 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
cdalton5e58cee2016-02-11 12:49:47 -08001691 fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001692 kVec2f_GrSLType, kDefault_GrSLPrecision,
1693 "ImageIncrement");
cdalton5e58cee2016-02-11 12:49:47 -08001694 fSurfaceScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001695 kFloat_GrSLType, kDefault_GrSLPrecision,
1696 "SurfaceScale");
1697 fLight->emitLightColorUniform(uniformHandler);
egdaniel4ca2e602015-11-18 08:01:26 -08001698 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001699 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001700 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001701 static const GrGLSLShaderVar gSobelArgs[] = {
1702 GrGLSLShaderVar("a", kFloat_GrSLType),
1703 GrGLSLShaderVar("b", kFloat_GrSLType),
1704 GrGLSLShaderVar("c", kFloat_GrSLType),
1705 GrGLSLShaderVar("d", kFloat_GrSLType),
1706 GrGLSLShaderVar("e", kFloat_GrSLType),
1707 GrGLSLShaderVar("f", kFloat_GrSLType),
1708 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001709 };
1710 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001711 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001712
egdaniel4ca2e602015-11-18 08:01:26 -08001713 fragBuilder->emitFunction(kFloat_GrSLType,
1714 "sobel",
1715 SK_ARRAY_COUNT(gSobelArgs),
1716 gSobelArgs,
1717 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1718 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001719 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1720 GrGLSLShaderVar("x", kFloat_GrSLType),
1721 GrGLSLShaderVar("y", kFloat_GrSLType),
1722 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001723 };
1724 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001725 fragBuilder->emitFunction(kVec3f_GrSLType,
1726 "pointToNormal",
1727 SK_ARRAY_COUNT(gPointToNormalArgs),
1728 gPointToNormalArgs,
1729 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1730 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001731
egdaniel0d3f0612015-10-21 10:45:48 -07001732 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1733 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1734 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001735 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001736 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001737 pointToNormalName.c_str(),
1738 sobelFuncName.c_str());
1739 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001740 fragBuilder->emitFunction(kVec3f_GrSLType,
1741 "normal",
1742 SK_ARRAY_COUNT(gInteriorNormalArgs),
1743 gInteriorNormalArgs,
1744 normalBody.c_str(),
1745 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001746
egdaniel4ca2e602015-11-18 08:01:26 -08001747 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1748 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001749
egdaniel7ea439b2015-12-03 09:20:44 -08001750 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1751 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001752
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001753 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001754 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001755 for (int dx = -1; dx <= 1; dx++) {
1756 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001757 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
egdaniel4ca2e602015-11-18 08:01:26 -08001758 fragBuilder->codeAppendf("\t\tm[%d] = ", index++);
1759 fragBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
1760 fragBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001761 }
1762 }
egdaniel4ca2e602015-11-18 08:01:26 -08001763 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001764 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001765 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001766 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001767 fragBuilder->codeAppend(";\n");
1768 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1769 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001770 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001771 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001772 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001773 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001774 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001775}
1776
joshualittb0a8a372014-09-23 09:50:21 -07001777void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001778 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001779 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1780 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001781}
1782
egdaniel018fb622015-10-28 07:26:40 -07001783void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1784 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001785 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001786 if (!fLight) {
1787 fLight = lighting.light()->createGLLight();
1788 }
1789
bsalomon@google.comc7818882013-03-20 19:19:53 +00001790 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001791 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001792 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1793 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001794 SkAutoTUnref<SkImageFilterLight> transformedLight(
1795 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001796 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001797}
1798
1799///////////////////////////////////////////////////////////////////////////////
1800
1801///////////////////////////////////////////////////////////////////////////////
1802
egdaniel7ea439b2015-12-03 09:20:44 -08001803void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001804 GrGLSLFragmentBuilder* fragBuilder,
1805 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001806 const char* kd;
cdalton5e58cee2016-02-11 12:49:47 -08001807 fKDUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
bsalomon422f56f2014-12-09 10:18:12 -08001808 kFloat_GrSLType, kDefault_GrSLPrecision,
1809 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001810
egdaniel0d3f0612015-10-21 10:45:48 -07001811 static const GrGLSLShaderVar gLightArgs[] = {
1812 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1813 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1814 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001815 };
1816 SkString lightBody;
1817 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1818 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001819 fragBuilder->emitFunction(kVec4f_GrSLType,
1820 "light",
1821 SK_ARRAY_COUNT(gLightArgs),
1822 gLightArgs,
1823 lightBody.c_str(),
1824 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001825}
1826
egdaniel018fb622015-10-28 07:26:40 -07001827void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1828 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001829 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001830 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001831 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001832}
1833
1834///////////////////////////////////////////////////////////////////////////////
1835
bsalomon4a339522015-10-06 08:40:50 -07001836GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001837 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001838 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001839 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001840 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001841 SkScalar shininess,
1842 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001843 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001844 , fKS(ks)
1845 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001846 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001847}
1848
bsalomon0e08fc12014-10-15 08:19:04 -07001849bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001850 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001851 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001852 this->ks() == s.ks() &&
1853 this->shininess() == s.shininess();
1854}
1855
egdaniel57d3b032015-11-13 11:57:27 -08001856void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1857 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001858 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1859}
1860
egdaniel57d3b032015-11-13 11:57:27 -08001861GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001862 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001863}
1864
joshualittb0a8a372014-09-23 09:50:21 -07001865GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001866
bsalomonc21b09e2015-08-28 18:46:56 -07001867const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001868 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1869 SkScalar ks = d->fRandom->nextUScalar1();
1870 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001871 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001872 SkMatrix matrix;
1873 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001874 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001875 }
joshualitt0067ff52015-07-08 14:26:19 -07001876 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001877 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001878 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001879}
1880
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001881///////////////////////////////////////////////////////////////////////////////
1882
egdaniel7ea439b2015-12-03 09:20:44 -08001883void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001884 GrGLSLFragmentBuilder* fragBuilder,
1885 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001886 const char* ks;
1887 const char* shininess;
1888
cdalton5e58cee2016-02-11 12:49:47 -08001889 fKSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001890 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
cdalton5e58cee2016-02-11 12:49:47 -08001891 fShininessUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001892 kFloat_GrSLType,
1893 kDefault_GrSLPrecision,
1894 "Shininess",
1895 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001896
egdaniel0d3f0612015-10-21 10:45:48 -07001897 static const GrGLSLShaderVar gLightArgs[] = {
1898 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1899 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1900 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001901 };
1902 SkString lightBody;
1903 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1904 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001905 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1906 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001907 fragBuilder->emitFunction(kVec4f_GrSLType,
1908 "light",
1909 SK_ARRAY_COUNT(gLightArgs),
1910 gLightArgs,
1911 lightBody.c_str(),
1912 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001913}
1914
egdaniel018fb622015-10-28 07:26:40 -07001915void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1916 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001917 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001918 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001919 pdman.set1f(fKSUni, spec.ks());
1920 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001921}
1922
1923///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08001924void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
cdalton5e58cee2016-02-11 12:49:47 -08001925 fColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001926 kVec3f_GrSLType, kDefault_GrSLPrecision,
1927 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001928}
1929
egdaniel7ea439b2015-12-03 09:20:44 -08001930void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001931 GrGLSLFragmentBuilder* fragBuilder,
1932 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08001933 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001934}
1935
egdaniel018fb622015-10-28 07:26:40 -07001936void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001937 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001938 setUniformPoint3(pdman, fColorUni,
1939 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001940}
1941
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001942///////////////////////////////////////////////////////////////////////////////
1943
egdaniel018fb622015-10-28 07:26:40 -07001944void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001945 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001946 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001947 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001948 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001949 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001950}
1951
egdaniel7ea439b2015-12-03 09:20:44 -08001952void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001953 GrGLSLFragmentBuilder* fragBuilder,
1954 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001955 const char* dir;
cdalton5e58cee2016-02-11 12:49:47 -08001956 fDirectionUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001957 kVec3f_GrSLType, kDefault_GrSLPrecision,
1958 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08001959 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001960}
1961
1962///////////////////////////////////////////////////////////////////////////////
1963
egdaniel018fb622015-10-28 07:26:40 -07001964void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001965 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001966 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001967 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001968 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001969 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001970}
1971
egdaniel7ea439b2015-12-03 09:20:44 -08001972void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001973 GrGLSLFragmentBuilder* fragBuilder,
1974 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001975 const char* loc;
cdalton5e58cee2016-02-11 12:49:47 -08001976 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001977 kVec3f_GrSLType, kDefault_GrSLPrecision,
1978 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08001979 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1980 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001981}
1982
1983///////////////////////////////////////////////////////////////////////////////
1984
egdaniel018fb622015-10-28 07:26:40 -07001985void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001986 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001987 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001988 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001989 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001990 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1991 pdman.set1f(fExponentUni, spotLight->specularExponent());
1992 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1993 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1994 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1995 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001996}
1997
egdaniel7ea439b2015-12-03 09:20:44 -08001998void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001999 GrGLSLFragmentBuilder* fragBuilder,
2000 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002001 const char* location;
cdalton5e58cee2016-02-11 12:49:47 -08002002 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002003 kVec3f_GrSLType, kDefault_GrSLPrecision,
2004 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07002005
egdaniel4ca2e602015-11-18 08:01:26 -08002006 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
2007 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002008}
2009
egdaniel7ea439b2015-12-03 09:20:44 -08002010void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08002011 GrGLSLFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002012 const char *surfaceToLight) {
2013
egdaniel7ea439b2015-12-03 09:20:44 -08002014 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002015
2016 const char* exponent;
2017 const char* cosInner;
2018 const char* cosOuter;
2019 const char* coneScale;
2020 const char* s;
cdalton5e58cee2016-02-11 12:49:47 -08002021 fExponentUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002022 kFloat_GrSLType, kDefault_GrSLPrecision,
2023 "Exponent", &exponent);
cdalton5e58cee2016-02-11 12:49:47 -08002024 fCosInnerConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002025 kFloat_GrSLType, kDefault_GrSLPrecision,
2026 "CosInnerConeAngle", &cosInner);
cdalton5e58cee2016-02-11 12:49:47 -08002027 fCosOuterConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002028 kFloat_GrSLType, kDefault_GrSLPrecision,
2029 "CosOuterConeAngle", &cosOuter);
cdalton5e58cee2016-02-11 12:49:47 -08002030 fConeScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002031 kFloat_GrSLType, kDefault_GrSLPrecision,
2032 "ConeScale", &coneScale);
cdalton5e58cee2016-02-11 12:49:47 -08002033 fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08002034 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002035
egdaniel0d3f0612015-10-21 10:45:48 -07002036 static const GrGLSLShaderVar gLightColorArgs[] = {
2037 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002038 };
2039 SkString lightColorBody;
2040 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2041 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2042 lightColorBody.appendf("\t\treturn vec3(0);\n");
2043 lightColorBody.appendf("\t}\n");
2044 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2045 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2046 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2047 color, cosOuter, coneScale);
2048 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002049 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002050 fragBuilder->emitFunction(kVec3f_GrSLType,
2051 "lightColor",
2052 SK_ARRAY_COUNT(gLightColorArgs),
2053 gLightColorArgs,
2054 lightColorBody.c_str(),
2055 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002056
egdaniel4ca2e602015-11-18 08:01:26 -08002057 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002058}
2059
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002060#endif
2061
djsollen@google.com08337772012-06-26 14:33:13 +00002062SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2063 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2064 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002065SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END