blob: 98b0a132459e4f3b5fe8ef942e478c0c76340e9b [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"
Cary Clarka4083c92017-09-15 11:59:23 -040010#include "SkColorData.h"
Matt Sarett62745a82017-04-17 11:57:29 -040011#include "SkColorSpaceXformer.h"
Cary Clark60aaeb22017-11-03 08:06:09 -040012#include "SkImageFilterPriv.h"
robertphillips3d32d762015-07-13 13:16:44 -070013#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
robertphillipsad3dc0d2016-04-15 05:06:11 -070015#include "SkSpecialImage.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000016#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070017#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000018
19#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070020#include "GrContext.h"
csmartdalton02fa32c2016-08-19 13:29:27 -070021#include "GrFixedClip.h"
joshualitteb2a6762014-12-04 11:35:33 -080022#include "GrFragmentProcessor.h"
kkinnunencabe20c2015-06-01 01:37:26 -070023#include "GrPaint.h"
Robert Phillips7f6cd902016-11-10 17:03:43 -050024#include "GrRenderTargetContext.h"
Robert Phillips646e4292017-06-13 12:44:56 -040025#include "GrTexture.h"
Robert Phillips7f6cd902016-11-10 17:03:43 -050026#include "GrTextureProxy.h"
27
robertphillips1de87df2016-01-14 06:03:29 -080028#include "SkGr.h"
senorblanco9bd5f742016-02-17 10:59:47 -080029#include "effects/GrTextureDomain.h"
egdaniel64c47282015-11-13 06:54:19 -080030#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080031#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070032#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080033#include "glsl/GrGLSLUniformHandler.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050034#include "../private/GrGLSL.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000035
36class GrGLDiffuseLightingEffect;
37class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000038
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000039// For brevity
egdaniel018fb622015-10-28 07:26:40 -070040typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000041#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000042
reed80ea19c2015-05-12 10:37:34 -070043const SkScalar gOneThird = SkIntToScalar(1) / 3;
44const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000045const SkScalar gOneHalf = 0.5f;
46const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000047
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000048#if SK_SUPPORT_GPU
Matt Sarett62745a82017-04-17 11:57:29 -040049static void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
50 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070051 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070052 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000053}
54
Matt Sarett62745a82017-04-17 11:57:29 -040055static void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
56 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070057 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000058}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000059#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000060
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000061// Shift matrix components to the left, as we advance pixels to the right.
Matt Sarett62745a82017-04-17 11:57:29 -040062static inline void shiftMatrixLeft(int m[9]) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000063 m[0] = m[1];
64 m[3] = m[4];
65 m[6] = m[7];
66 m[1] = m[2];
67 m[4] = m[5];
68 m[7] = m[8];
69}
70
jvanverth992c7612015-07-17 07:22:30 -070071static inline void fast_normalize(SkPoint3* vector) {
72 // add a tiny bit so we don't have to worry about divide-by-zero
73 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
74 SkScalar scale = sk_float_rsqrt(magSq);
75 vector->fX *= scale;
76 vector->fY *= scale;
77 vector->fZ *= scale;
78}
79
Robert Phillips959ccc22018-01-23 11:56:12 -050080static SkPoint3 read_point3(SkReadBuffer& buffer) {
Mike Reed0c182fc2017-06-16 16:55:15 -040081 SkPoint3 point;
82 point.fX = buffer.readScalar();
83 point.fY = buffer.readScalar();
84 point.fZ = buffer.readScalar();
85 buffer.validate(SkScalarIsFinite(point.fX) &&
86 SkScalarIsFinite(point.fY) &&
87 SkScalarIsFinite(point.fZ));
88 return point;
89};
90
Robert Phillips959ccc22018-01-23 11:56:12 -050091static void write_point3(const SkPoint3& point, SkWriteBuffer& buffer) {
Mike Reed0c182fc2017-06-16 16:55:15 -040092 buffer.writeScalar(point.fX);
93 buffer.writeScalar(point.fY);
94 buffer.writeScalar(point.fZ);
95};
96
97class GrGLLight;
98class SkImageFilterLight : public SkRefCnt {
99public:
100 enum LightType {
101 kDistant_LightType,
102 kPoint_LightType,
103 kSpot_LightType,
Robert Phillips959ccc22018-01-23 11:56:12 -0500104
105 kLast_LightType = kSpot_LightType
Mike Reed0c182fc2017-06-16 16:55:15 -0400106 };
107 virtual LightType type() const = 0;
108 const SkPoint3& color() const { return fColor; }
109 virtual GrGLLight* createGLLight() const = 0;
110 virtual bool isEqual(const SkImageFilterLight& other) const {
111 return fColor == other.fColor;
112 }
113 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
114
115 virtual sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer*) const = 0;
116
117 // Defined below SkLight's subclasses.
118 void flattenLight(SkWriteBuffer& buffer) const;
119 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
120
121 virtual SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const = 0;
122 virtual SkPoint3 lightColor(const SkPoint3& surfaceToLight) const = 0;
123
124protected:
125 SkImageFilterLight(SkColor color) {
126 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
127 SkIntToScalar(SkColorGetG(color)),
128 SkIntToScalar(SkColorGetB(color)));
129 }
Robert Phillips959ccc22018-01-23 11:56:12 -0500130 SkImageFilterLight(const SkPoint3& color) : fColor(color) {}
131
Mike Reed0c182fc2017-06-16 16:55:15 -0400132 SkImageFilterLight(SkReadBuffer& buffer) {
Robert Phillips959ccc22018-01-23 11:56:12 -0500133 fColor = read_point3(buffer);
Mike Reed0c182fc2017-06-16 16:55:15 -0400134 }
135
136 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
137
138
139private:
140 typedef SkRefCnt INHERITED;
141 SkPoint3 fColor;
142};
143
144class BaseLightingType {
145public:
146 BaseLightingType() {}
147 virtual ~BaseLightingType() {}
148
149 virtual SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
150 const SkPoint3& lightColor) const= 0;
151};
152
153class DiffuseLightingType : public BaseLightingType {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000154public:
155 DiffuseLightingType(SkScalar kd)
156 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -0700157 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
Mike Reed0c182fc2017-06-16 16:55:15 -0400158 const SkPoint3& lightColor) const override {
Mike Reed8be952a2017-02-13 20:44:33 -0500159 SkScalar colorScale = fKD * normal.dot(surfaceTolight);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000160 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700161 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000162 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000163 SkClampMax(SkScalarRoundToInt(color.fX), 255),
164 SkClampMax(SkScalarRoundToInt(color.fY), 255),
165 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000166 }
167private:
168 SkScalar fKD;
169};
170
robertphillips3d32d762015-07-13 13:16:44 -0700171static SkScalar max_component(const SkPoint3& p) {
172 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
173}
174
Mike Reed0c182fc2017-06-16 16:55:15 -0400175class SpecularLightingType : public BaseLightingType {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000176public:
177 SpecularLightingType(SkScalar ks, SkScalar shininess)
178 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700179 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
Mike Reed0c182fc2017-06-16 16:55:15 -0400180 const SkPoint3& lightColor) const override {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000181 SkPoint3 halfDir(surfaceTolight);
182 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700183 fast_normalize(&halfDir);
Mike Reed8be952a2017-02-13 20:44:33 -0500184 SkScalar colorScale = fKS * SkScalarPow(normal.dot(halfDir), fShininess);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000185 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700186 SkPoint3 color = lightColor.makeScale(colorScale);
187 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000188 SkClampMax(SkScalarRoundToInt(color.fX), 255),
189 SkClampMax(SkScalarRoundToInt(color.fY), 255),
190 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 }
192private:
193 SkScalar fKS;
194 SkScalar fShininess;
195};
196
Matt Sarett62745a82017-04-17 11:57:29 -0400197static inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
Mike Reed8be952a2017-02-13 20:44:33 -0500198 return (-a + b - 2 * c + 2 * d -e + f) * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000199}
200
Matt Sarett62745a82017-04-17 11:57:29 -0400201static inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
Mike Reed8be952a2017-02-13 20:44:33 -0500202 SkPoint3 vector = SkPoint3::Make(-x * surfaceScale, -y * surfaceScale, 1);
jvanverth992c7612015-07-17 07:22:30 -0700203 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 return vector;
205}
206
Matt Sarett62745a82017-04-17 11:57:29 -0400207static inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000208 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
209 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
210 surfaceScale);
211}
212
Matt Sarett62745a82017-04-17 11:57:29 -0400213static inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000214 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
215 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
216 surfaceScale);
217}
218
Matt Sarett62745a82017-04-17 11:57:29 -0400219static inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000220 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
221 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
222 surfaceScale);
223}
224
Matt Sarett62745a82017-04-17 11:57:29 -0400225static inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000226 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
227 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
228 surfaceScale);
229}
230
231
Matt Sarett62745a82017-04-17 11:57:29 -0400232static inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
234 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
235 surfaceScale);
236}
237
Matt Sarett62745a82017-04-17 11:57:29 -0400238static inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
240 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
241 surfaceScale);
242}
243
Matt Sarett62745a82017-04-17 11:57:29 -0400244static inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000245 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
246 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
247 surfaceScale);
248}
249
Matt Sarett62745a82017-04-17 11:57:29 -0400250static inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000251 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
252 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
253 surfaceScale);
254}
255
Matt Sarett62745a82017-04-17 11:57:29 -0400256static inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000257 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
258 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
259 surfaceScale);
260}
261
senorblanco84f0e742016-02-16 13:26:56 -0800262
263class UncheckedPixelFetcher {
264public:
265 static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
266 return SkGetPackedA32(*src.getAddr32(x, y));
267 }
268};
269
270// The DecalPixelFetcher is used when the destination crop rect exceeds the input bitmap bounds.
271class DecalPixelFetcher {
272public:
273 static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
274 if (x < bounds.fLeft || x >= bounds.fRight || y < bounds.fTop || y >= bounds.fBottom) {
275 return 0;
276 } else {
277 return SkGetPackedA32(*src.getAddr32(x, y));
278 }
279 }
280};
281
Mike Reed0c182fc2017-06-16 16:55:15 -0400282template <class PixelFetcher>
283static void lightBitmap(const BaseLightingType& lightingType,
284 const SkImageFilterLight* l,
senorblanco84f0e742016-02-16 13:26:56 -0800285 const SkBitmap& src,
286 SkBitmap* dst,
287 SkScalar surfaceScale,
288 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000289 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000290 int left = bounds.left(), right = bounds.right();
291 int bottom = bounds.bottom();
292 int y = bounds.top();
senorblanco84f0e742016-02-16 13:26:56 -0800293 SkIRect srcBounds = src.bounds();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000294 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000295 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000296 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800298 m[4] = PixelFetcher::Fetch(src, x, y, srcBounds);
299 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
300 m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds);
301 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000302 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700303 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
304 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000305 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000306 {
307 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800308 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
309 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000310 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700311 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
312 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000313 }
314 shiftMatrixLeft(m);
315 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700316 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
317 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000318 }
319
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000320 for (++y; y < bottom - 1; ++y) {
321 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000322 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800323 m[1] = PixelFetcher::Fetch(src, x, y - 1, srcBounds);
324 m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
325 m[4] = PixelFetcher::Fetch(src, x, y, srcBounds);
326 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
327 m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds);
328 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000329 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700330 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
331 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000332 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000333 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800334 m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
335 m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds);
336 m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000337 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700338 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
339 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000340 }
341 shiftMatrixLeft(m);
342 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700343 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
344 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000345 }
346
347 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000348 int x = left;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000349 int m[9];
senorblanco84f0e742016-02-16 13:26:56 -0800350 m[1] = PixelFetcher::Fetch(src, x, bottom - 2, srcBounds);
351 m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
352 m[4] = PixelFetcher::Fetch(src, x, bottom - 1, srcBounds);
353 m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000354 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700355 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
356 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000357 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000358 {
359 shiftMatrixLeft(m);
senorblanco84f0e742016-02-16 13:26:56 -0800360 m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
361 m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000362 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700363 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
364 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000365 }
366 shiftMatrixLeft(m);
367 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700368 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
369 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000370 }
371}
372
Mike Reed0c182fc2017-06-16 16:55:15 -0400373static void lightBitmap(const BaseLightingType& lightingType,
senorblanco84f0e742016-02-16 13:26:56 -0800374 const SkImageFilterLight* light,
375 const SkBitmap& src,
376 SkBitmap* dst,
377 SkScalar surfaceScale,
378 const SkIRect& bounds) {
379 if (src.bounds().contains(bounds)) {
Mike Reed0c182fc2017-06-16 16:55:15 -0400380 lightBitmap<UncheckedPixelFetcher>(
senorblanco84f0e742016-02-16 13:26:56 -0800381 lightingType, light, src, dst, surfaceScale, bounds);
382 } else {
Mike Reed0c182fc2017-06-16 16:55:15 -0400383 lightBitmap<DecalPixelFetcher>(
senorblanco84f0e742016-02-16 13:26:56 -0800384 lightingType, light, src, dst, surfaceScale, bounds);
385 }
386}
387
senorblancod0d37ca2015-04-02 04:54:56 -0700388enum BoundaryMode {
389 kTopLeft_BoundaryMode,
390 kTop_BoundaryMode,
391 kTopRight_BoundaryMode,
392 kLeft_BoundaryMode,
393 kInterior_BoundaryMode,
394 kRight_BoundaryMode,
395 kBottomLeft_BoundaryMode,
396 kBottom_BoundaryMode,
397 kBottomRight_BoundaryMode,
398
399 kBoundaryModeCount,
400};
401
402class SkLightingImageFilterInternal : public SkLightingImageFilter {
403protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700404 SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -0700405 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -0700406 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -0700407 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -0700408 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect) {
409 }
senorblancod0d37ca2015-04-02 04:54:56 -0700410
411#if SK_SUPPORT_GPU
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400412 sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700413 SkSpecialImage* input,
414 const SkIRect& bounds,
brianosman2a75e5d2016-09-22 07:15:37 -0700415 const SkMatrix& matrix,
416 const OutputProperties& outputProperties) const;
Brian Salomonaff329b2017-08-11 09:40:37 -0400417 virtual std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(
418 sk_sp<GrTextureProxy>,
419 const SkMatrix&,
420 const SkIRect* srcBounds,
421 BoundaryMode boundaryMode) const = 0;
senorblancod0d37ca2015-04-02 04:54:56 -0700422#endif
423private:
424#if SK_SUPPORT_GPU
Robert Phillips296b1cc2017-03-15 10:42:12 -0400425 void drawRect(GrRenderTargetContext*,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500426 sk_sp<GrTextureProxy> srcProxy,
senorblancod0d37ca2015-04-02 04:54:56 -0700427 const SkMatrix& matrix,
428 const GrClip& clip,
429 const SkRect& dstRect,
430 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800431 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700432 const SkIRect& bounds) const;
433#endif
434 typedef SkLightingImageFilter INHERITED;
435};
436
437#if SK_SUPPORT_GPU
Robert Phillips296b1cc2017-03-15 10:42:12 -0400438void SkLightingImageFilterInternal::drawRect(GrRenderTargetContext* renderTargetContext,
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500439 sk_sp<GrTextureProxy> srcProxy,
senorblancod0d37ca2015-04-02 04:54:56 -0700440 const SkMatrix& matrix,
441 const GrClip& clip,
442 const SkRect& dstRect,
443 BoundaryMode boundaryMode,
senorblanco9bd5f742016-02-17 10:59:47 -0800444 const SkIRect* srcBounds,
senorblancod0d37ca2015-04-02 04:54:56 -0700445 const SkIRect& bounds) const {
446 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700447 GrPaint paint;
Brian Salomonf3569f02017-10-24 12:52:33 -0400448 paint.setGammaCorrect(renderTargetContext->colorSpaceInfo().isGammaCorrect());
Brian Salomonaff329b2017-08-11 09:40:37 -0400449 auto fp = this->makeFragmentProcessor(std::move(srcProxy), matrix, srcBounds, boundaryMode);
bungeman06ca8ec2016-06-09 08:01:03 -0700450 paint.addColorFragmentProcessor(std::move(fp));
reed374772b2016-10-05 17:33:02 -0700451 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon82f44312017-01-11 13:42:54 -0500452 renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect,
453 srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700454}
455
brianosman2a75e5d2016-09-22 07:15:37 -0700456sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(
457 SkSpecialImage* source,
458 SkSpecialImage* input,
459 const SkIRect& offsetBounds,
460 const SkMatrix& matrix,
461 const OutputProperties& outputProperties) const {
robertphillipsad3dc0d2016-04-15 05:06:11 -0700462 SkASSERT(source->isTextureBacked());
463
464 GrContext* context = source->getContext();
465
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500466 sk_sp<GrTextureProxy> inputProxy(input->asTextureProxyRef(context));
467 SkASSERT(inputProxy);
senorblancod0d37ca2015-04-02 04:54:56 -0700468
Robert Phillips7f6cd902016-11-10 17:03:43 -0500469 sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
470 SkBackingFit::kApprox, offsetBounds.width(), offsetBounds.height(),
471 GrRenderableConfigForColorSpace(outputProperties.colorSpace()),
472 sk_ref_sp(outputProperties.colorSpace())));
Brian Osman11052242016-10-27 14:47:55 -0400473 if (!renderTargetContext) {
robertphillipsad3dc0d2016-04-15 05:06:11 -0700474 return nullptr;
475 }
476
cdalton846c0512016-05-13 10:25:00 -0700477 SkIRect dstIRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height());
478 SkRect dstRect = SkRect::Make(dstIRect);
robertphillipsad3dc0d2016-04-15 05:06:11 -0700479
senorblancod0d37ca2015-04-02 04:54:56 -0700480 // setup new clip
cdalton846c0512016-05-13 10:25:00 -0700481 GrFixedClip clip(dstIRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700482
robertphillipsad3dc0d2016-04-15 05:06:11 -0700483 const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
senorblancod0d37ca2015-04-02 04:54:56 -0700484 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
485 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
486 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
487 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
488 SkRect interior = dstRect.makeInset(1, 1);
489 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
490 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
491 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
492 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700493
robertphillipsad3dc0d2016-04-15 05:06:11 -0700494 const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds;
Robert Phillips296b1cc2017-03-15 10:42:12 -0400495 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, topLeft,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700496 kTopLeft_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400497 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, top,
Brian Osman11052242016-10-27 14:47:55 -0400498 kTop_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400499 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, topRight,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700500 kTopRight_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400501 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, left,
Brian Osman11052242016-10-27 14:47:55 -0400502 kLeft_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400503 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, interior,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700504 kInterior_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400505 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, right,
Brian Osman11052242016-10-27 14:47:55 -0400506 kRight_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400507 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottomLeft,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700508 kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400509 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottom,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700510 kBottom_BoundaryMode, pSrcBounds, offsetBounds);
Robert Phillips296b1cc2017-03-15 10:42:12 -0400511 this->drawRect(renderTargetContext.get(), inputProxy, matrix, clip, bottomRight,
robertphillipsad3dc0d2016-04-15 05:06:11 -0700512 kBottomRight_BoundaryMode, pSrcBounds, offsetBounds);
robertphillipsea461502015-05-26 11:38:03 -0700513
Robert Phillips7f6cd902016-11-10 17:03:43 -0500514 return SkSpecialImage::MakeDeferredFromGpu(
Brian Salomonf3569f02017-10-24 12:52:33 -0400515 context,
516 SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()),
517 kNeedNewImageUniqueID_SpecialImage,
518 renderTargetContext->asTextureProxyRef(),
519 renderTargetContext->colorSpaceInfo().refColorSpace());
senorblancod0d37ca2015-04-02 04:54:56 -0700520}
521#endif
522
523class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000524public:
robertphillips12fa47d2016-04-08 16:28:09 -0700525 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
526 SkScalar surfaceScale,
527 SkScalar kd,
528 sk_sp<SkImageFilter>,
529 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700530
robertphillipsf3f5bad2014-12-19 13:49:15 -0800531 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000532 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000533 SkScalar kd() const { return fKD; }
534
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000535protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700536 SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, SkScalar surfaceScale,
537 SkScalar kd,
538 sk_sp<SkImageFilter> input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700539 void flatten(SkWriteBuffer& buffer) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700540
541 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
542 SkIPoint* offset) const override;
Matt Sarett62745a82017-04-17 11:57:29 -0400543 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700544
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000545#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400546 std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(sk_sp<GrTextureProxy>,
547 const SkMatrix&,
548 const SkIRect* bounds,
549 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000550#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000551
552private:
reed9fa60da2014-08-21 07:59:51 -0700553 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000554 SkScalar fKD;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700555
556 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000557};
558
senorblancod0d37ca2015-04-02 04:54:56 -0700559class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000560public:
robertphillips12fa47d2016-04-08 16:28:09 -0700561 static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
562 SkScalar surfaceScale,
563 SkScalar ks, SkScalar shininess,
564 sk_sp<SkImageFilter>, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700565
robertphillipsf3f5bad2014-12-19 13:49:15 -0800566 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000567 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
568
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000569 SkScalar ks() const { return fKS; }
570 SkScalar shininess() const { return fShininess; }
571
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000572protected:
robertphillips12fa47d2016-04-08 16:28:09 -0700573 SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
574 SkScalar surfaceScale, SkScalar ks,
575 SkScalar shininess,
576 sk_sp<SkImageFilter> input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700577 void flatten(SkWriteBuffer& buffer) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700578
579 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
580 SkIPoint* offset) const override;
Matt Sarett62745a82017-04-17 11:57:29 -0400581 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
robertphillipsad3dc0d2016-04-15 05:06:11 -0700582
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000583#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400584 std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(sk_sp<GrTextureProxy>,
585 const SkMatrix&,
586 const SkIRect* bounds,
587 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000588#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000589
590private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000591 SkScalar fKS;
592 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700593 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700594 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000595};
596
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000597#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000598
Brian Salomon6cd51b52017-07-26 19:07:15 -0400599class GrLightingEffect : public GrFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000600public:
Brian Salomon6b17ff62017-07-28 10:16:29 -0400601 const SkImageFilterLight* light() const { return fLight.get(); }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000602 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000603 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700604 BoundaryMode boundaryMode() const { return fBoundaryMode; }
senorblanco9bd5f742016-02-17 10:59:47 -0800605 const GrTextureDomain& domain() const { return fDomain; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000606
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000607protected:
Ethan Nicholasabff9562017-10-09 10:54:08 -0400608 GrLightingEffect(ClassID classID, sk_sp<GrTextureProxy>, sk_sp<const SkImageFilterLight> light,
Brian Salomon6b17ff62017-07-28 10:16:29 -0400609 SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode,
610 const SkIRect* srcBounds);
611
612 GrLightingEffect(const GrLightingEffect& that);
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000613
Robert Phillips1c9686b2017-06-30 08:40:28 -0400614 bool onIsEqual(const GrFragmentProcessor&) const override;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700615
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000616private:
Brian Salomon6cd51b52017-07-26 19:07:15 -0400617 GrCoordTransform fCoordTransform;
618 GrTextureDomain fDomain;
619 TextureSampler fTextureSampler;
Brian Salomon6b17ff62017-07-28 10:16:29 -0400620 sk_sp<const SkImageFilterLight> fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000621 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000622 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700623 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700624
Brian Salomon6cd51b52017-07-26 19:07:15 -0400625 typedef GrFragmentProcessor INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000626};
627
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628class GrDiffuseLightingEffect : public GrLightingEffect {
629public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400630 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
631 sk_sp<const SkImageFilterLight> light,
632 SkScalar surfaceScale,
633 const SkMatrix& matrix,
634 SkScalar kd,
635 BoundaryMode boundaryMode,
636 const SkIRect* srcBounds) {
637 return std::unique_ptr<GrFragmentProcessor>(
Brian Salomon6b17ff62017-07-28 10:16:29 -0400638 new GrDiffuseLightingEffect(std::move(proxy), std::move(light), surfaceScale,
639 matrix, kd, boundaryMode, srcBounds));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000640 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000641
mtklein36352bf2015-03-25 18:17:31 -0700642 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000643
Brian Salomonaff329b2017-08-11 09:40:37 -0400644 std::unique_ptr<GrFragmentProcessor> clone() const override {
645 return std::unique_ptr<GrFragmentProcessor>(new GrDiffuseLightingEffect(*this));
Brian Salomon6b17ff62017-07-28 10:16:29 -0400646 }
647
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000648 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000649
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000650private:
egdaniel57d3b032015-11-13 11:57:27 -0800651 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700652
Brian Salomon94efbf52016-11-29 13:43:05 -0500653 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700654
mtklein36352bf2015-03-25 18:17:31 -0700655 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000656
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400657 GrDiffuseLightingEffect(sk_sp<GrTextureProxy>,
Brian Salomon6b17ff62017-07-28 10:16:29 -0400658 sk_sp<const SkImageFilterLight> light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000659 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000660 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700661 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -0800662 BoundaryMode boundaryMode,
663 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000664
Brian Salomon6b17ff62017-07-28 10:16:29 -0400665 explicit GrDiffuseLightingEffect(const GrDiffuseLightingEffect& that);
666
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400667 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Robert Phillips696b2932017-02-08 12:49:00 +0000668 SkScalar fKD;
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500669
670 typedef GrLightingEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000671};
672
673class GrSpecularLightingEffect : public GrLightingEffect {
674public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400675 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
676 sk_sp<const SkImageFilterLight> light,
677 SkScalar surfaceScale,
678 const SkMatrix& matrix,
679 SkScalar ks,
680 SkScalar shininess,
681 BoundaryMode boundaryMode,
682 const SkIRect* srcBounds) {
683 return std::unique_ptr<GrFragmentProcessor>(
Brian Salomon6b17ff62017-07-28 10:16:29 -0400684 new GrSpecularLightingEffect(std::move(proxy), std::move(light), surfaceScale,
685 matrix, ks, shininess, boundaryMode, srcBounds));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000686 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000687
mtklein36352bf2015-03-25 18:17:31 -0700688 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000689
Brian Salomonaff329b2017-08-11 09:40:37 -0400690 std::unique_ptr<GrFragmentProcessor> clone() const override {
691 return std::unique_ptr<GrFragmentProcessor>(new GrSpecularLightingEffect(*this));
Brian Salomon6b17ff62017-07-28 10:16:29 -0400692 }
693
egdaniel57d3b032015-11-13 11:57:27 -0800694 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800695
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000696 SkScalar ks() const { return fKS; }
697 SkScalar shininess() const { return fShininess; }
698
699private:
Brian Salomon94efbf52016-11-29 13:43:05 -0500700 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700701
mtklein36352bf2015-03-25 18:17:31 -0700702 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000703
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400704 GrSpecularLightingEffect(sk_sp<GrTextureProxy>,
Brian Salomon6b17ff62017-07-28 10:16:29 -0400705 sk_sp<const SkImageFilterLight> light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000706 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000707 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000708 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700709 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -0800710 BoundaryMode boundaryMode,
711 const SkIRect* srcBounds);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000712
Brian Salomon6b17ff62017-07-28 10:16:29 -0400713 explicit GrSpecularLightingEffect(const GrSpecularLightingEffect&);
714
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400715 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000716 SkScalar fKS;
717 SkScalar fShininess;
Robert Phillips8e1c4e62017-02-19 12:27:01 -0500718
719 typedef GrLightingEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000720};
721
722///////////////////////////////////////////////////////////////////////////////
723
724class GrGLLight {
725public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000726 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000727
728 /**
729 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400730 * below. It adds a half3 uniform visible in the FS that represents the constant light color.
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000731 */
egdaniel7ea439b2015-12-03 09:20:44 -0800732 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000733
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000734 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000735 * These two functions are called from GrGLLightingEffect's emitCode() function.
736 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
737 * the light. The expression will be used in the FS. emitLightColor writes an expression into
738 * the FS that is the color of the light. Either function may add functions and/or uniforms to
739 * the FS. The default of emitLightColor appends the name of the constant light color uniform
740 * and so this function only needs to be overridden if the light color varies spatially.
741 */
egdaniel7ea439b2015-12-03 09:20:44 -0800742 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800743 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -0800744 const char* z) = 0;
745 virtual void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800746 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800747 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000748
749 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
750 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700751 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000752
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000753protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000754 /**
755 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
756 * function.
757 */
758 UniformHandle lightColorUni() const { return fColorUni; }
759
760private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000761 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000762
763 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000764};
765
766///////////////////////////////////////////////////////////////////////////////
767
768class GrGLDistantLight : public GrGLLight {
769public:
Brian Salomond3b65972017-03-22 12:05:03 -0400770 ~GrGLDistantLight() override {}
egdaniel018fb622015-10-28 07:26:40 -0700771 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800772 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000773
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000774private:
775 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000776 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000777};
778
779///////////////////////////////////////////////////////////////////////////////
780
781class GrGLPointLight : public GrGLLight {
782public:
Brian Salomond3b65972017-03-22 12:05:03 -0400783 ~GrGLPointLight() override {}
egdaniel018fb622015-10-28 07:26:40 -0700784 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800785 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000786
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000787private:
788 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000789 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000790};
791
792///////////////////////////////////////////////////////////////////////////////
793
794class GrGLSpotLight : public GrGLLight {
795public:
Brian Salomond3b65972017-03-22 12:05:03 -0400796 ~GrGLSpotLight() override {}
egdaniel018fb622015-10-28 07:26:40 -0700797 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
cdalton85285412016-02-18 12:37:07 -0800798 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, const char* z) override;
egdaniel7ea439b2015-12-03 09:20:44 -0800799 void emitLightColor(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -0800800 GrGLSLFPFragmentBuilder*,
egdaniel4ca2e602015-11-18 08:01:26 -0800801 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000802
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000803private:
804 typedef GrGLLight INHERITED;
805
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000806 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000807 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000808 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000809 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000810 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000811 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000812 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000813};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000814#else
815
816class GrGLLight;
817
818#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000819
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000820///////////////////////////////////////////////////////////////////////////////
821
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000822///////////////////////////////////////////////////////////////////////////////
823
Matt Sarett62745a82017-04-17 11:57:29 -0400824static SkColor xform_color(const SkPoint3& color, SkColorSpaceXformer* xformer) {
825 SkColor origColor = SkColorSetARGBInline(0xFF,
826 SkScalarRoundToInt(color.fX),
827 SkScalarRoundToInt(color.fY),
828 SkScalarRoundToInt(color.fZ));
829 return xformer->apply(origColor);
830}
831
robertphillips2f0dbc72015-08-20 05:15:06 -0700832class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000833public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000834 SkDistantLight(const SkPoint3& direction, SkColor color)
835 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000836 }
djsollen@google.com08337772012-06-26 14:33:13 +0000837
Mike Reed0c182fc2017-06-16 16:55:15 -0400838 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000839 return fDirection;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400840 }
Mike Reed0c182fc2017-06-16 16:55:15 -0400841 SkPoint3 lightColor(const SkPoint3&) const override { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700842 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000843 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700844 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000845#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700846 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000847#else
848 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700849 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000850#endif
851 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000852
Matt Sarett62745a82017-04-17 11:57:29 -0400853 sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer* xformer) const override {
854 return sk_make_sp<SkDistantLight>(fDirection, xform_color(this->color(), xformer));
855 }
856
robertphillips2f0dbc72015-08-20 05:15:06 -0700857 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000858 if (other.type() != kDistant_LightType) {
859 return false;
860 }
861
862 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
863 return INHERITED::isEqual(other) &&
864 fDirection == o.fDirection;
865 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000866
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000867 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
Robert Phillips959ccc22018-01-23 11:56:12 -0500868 fDirection = read_point3(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000869 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000870
djsollen@google.com08337772012-06-26 14:33:13 +0000871protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000872 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
873 : INHERITED(color), fDirection(direction) {
874 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700875 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000876 return new SkDistantLight(direction(), color());
877 }
mtklein36352bf2015-03-25 18:17:31 -0700878 void onFlattenLight(SkWriteBuffer& buffer) const override {
Robert Phillips959ccc22018-01-23 11:56:12 -0500879 write_point3(fDirection, buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000880 }
881
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000882private:
883 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700884
885 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000886};
887
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000888///////////////////////////////////////////////////////////////////////////////
889
robertphillips2f0dbc72015-08-20 05:15:06 -0700890class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000891public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000892 SkPointLight(const SkPoint3& location, SkColor color)
893 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000894
Mike Reed0c182fc2017-06-16 16:55:15 -0400895 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override {
robertphillips3d32d762015-07-13 13:16:44 -0700896 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
897 fLocation.fY - SkIntToScalar(y),
Mike Reed8be952a2017-02-13 20:44:33 -0500898 fLocation.fZ - SkIntToScalar(z) * surfaceScale);
jvanverth992c7612015-07-17 07:22:30 -0700899 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000900 return direction;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400901 }
Mike Reed0c182fc2017-06-16 16:55:15 -0400902 SkPoint3 lightColor(const SkPoint3&) const override { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700903 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000904 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700905 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000906#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700907 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000908#else
909 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700910 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000911#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000912 }
Matt Sarett62745a82017-04-17 11:57:29 -0400913
914 sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer* xformer) const override {
915 return sk_make_sp<SkPointLight>(fLocation, xform_color(this->color(), xformer));
916 }
917
robertphillips2f0dbc72015-08-20 05:15:06 -0700918 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000919 if (other.type() != kPoint_LightType) {
920 return false;
921 }
922 const SkPointLight& o = static_cast<const SkPointLight&>(other);
923 return INHERITED::isEqual(other) &&
924 fLocation == o.fLocation;
925 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700926 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000927 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
928 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000929 // Use X scale and Y scale on Z and average the result
930 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
931 matrix.mapVectors(&locationZ, 1);
halcanary9d524f22016-03-29 09:03:52 -0700932 SkPoint3 location = SkPoint3::Make(location2.fX,
933 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700934 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000935 return new SkPointLight(location, color());
936 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000937
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000938 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
Robert Phillips959ccc22018-01-23 11:56:12 -0500939 fLocation = read_point3(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000940 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000941
942protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000943 SkPointLight(const SkPoint3& location, const SkPoint3& color)
944 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700945 void onFlattenLight(SkWriteBuffer& buffer) const override {
Robert Phillips959ccc22018-01-23 11:56:12 -0500946 write_point3(fLocation, buffer);
djsollen@google.com08337772012-06-26 14:33:13 +0000947 }
948
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000949private:
950 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700951
952 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000953};
954
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000955///////////////////////////////////////////////////////////////////////////////
956
robertphillips2f0dbc72015-08-20 05:15:06 -0700957class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000958public:
senorblancod0d37ca2015-04-02 04:54:56 -0700959 SkSpotLight(const SkPoint3& location,
960 const SkPoint3& target,
961 SkScalar specularExponent,
962 SkScalar cutoffAngle,
963 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000964 : INHERITED(color),
965 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000966 fTarget(target),
Matt Sarett62745a82017-04-17 11:57:29 -0400967 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax)),
968 fCutoffAngle(cutoffAngle)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000969 {
970 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700971 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000972 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000973 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000974 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
975 fConeScale = SkScalarInvert(antiAliasThreshold);
976 }
djsollen@google.com08337772012-06-26 14:33:13 +0000977
Matt Sarett62745a82017-04-17 11:57:29 -0400978 sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer* xformer) const override {
979 return sk_make_sp<SkSpotLight>(fLocation, fTarget, fSpecularExponent, fCutoffAngle,
980 xform_color(this->color(), xformer));
981 }
982
robertphillips2f0dbc72015-08-20 05:15:06 -0700983 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000984 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
985 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000986 // Use X scale and Y scale on Z and average the result
987 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
988 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700989 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
990 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000991 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
992 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000993 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
994 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700995 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
996 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000997 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700998 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700999 return new SkSpotLight(location,
1000 target,
1001 fSpecularExponent,
1002 fCosOuterConeAngle,
1003 fCosInnerConeAngle,
1004 fConeScale,
1005 s,
1006 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001007 }
1008
Mike Reed0c182fc2017-06-16 16:55:15 -04001009 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override {
robertphillips3d32d762015-07-13 13:16:44 -07001010 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
1011 fLocation.fY - SkIntToScalar(y),
Mike Reed8be952a2017-02-13 20:44:33 -05001012 fLocation.fZ - SkIntToScalar(z) * surfaceScale);
jvanverth992c7612015-07-17 07:22:30 -07001013 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001014 return direction;
Mike Kleinfc6c37b2016-09-27 09:34:10 -04001015 }
Mike Reed0c182fc2017-06-16 16:55:15 -04001016 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const override {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001017 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -07001018 SkScalar scale = 0;
1019 if (cosAngle >= fCosOuterConeAngle) {
1020 scale = SkScalarPow(cosAngle, fSpecularExponent);
1021 if (cosAngle < fCosInnerConeAngle) {
Mike Reed8be952a2017-02-13 20:44:33 -05001022 scale *= (cosAngle - fCosOuterConeAngle) * fConeScale;
robertphillips3d32d762015-07-13 13:16:44 -07001023 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001024 }
robertphillips3d32d762015-07-13 13:16:44 -07001025 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001026 }
mtklein36352bf2015-03-25 18:17:31 -07001027 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001028#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -07001029 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001030#else
1031 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -07001032 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001033#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001034 }
mtklein36352bf2015-03-25 18:17:31 -07001035 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001036 const SkPoint3& location() const { return fLocation; }
1037 const SkPoint3& target() const { return fTarget; }
1038 SkScalar specularExponent() const { return fSpecularExponent; }
1039 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
1040 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
1041 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +00001042 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +00001043
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001044 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
Robert Phillips959ccc22018-01-23 11:56:12 -05001045 fLocation = read_point3(buffer);
1046 fTarget = read_point3(buffer);
djsollen@google.com08337772012-06-26 14:33:13 +00001047 fSpecularExponent = buffer.readScalar();
1048 fCosOuterConeAngle = buffer.readScalar();
1049 fCosInnerConeAngle = buffer.readScalar();
1050 fConeScale = buffer.readScalar();
Robert Phillips959ccc22018-01-23 11:56:12 -05001051 fS = read_point3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +00001052 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
1053 SkScalarIsFinite(fCosOuterConeAngle) &&
1054 SkScalarIsFinite(fCosInnerConeAngle) &&
1055 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +00001056 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001057protected:
senorblancod0d37ca2015-04-02 04:54:56 -07001058 SkSpotLight(const SkPoint3& location,
1059 const SkPoint3& target,
1060 SkScalar specularExponent,
1061 SkScalar cosOuterConeAngle,
1062 SkScalar cosInnerConeAngle,
1063 SkScalar coneScale,
1064 const SkPoint3& s,
1065 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001066 : INHERITED(color),
1067 fLocation(location),
1068 fTarget(target),
1069 fSpecularExponent(specularExponent),
1070 fCosOuterConeAngle(cosOuterConeAngle),
1071 fCosInnerConeAngle(cosInnerConeAngle),
1072 fConeScale(coneScale),
1073 fS(s)
1074 {
1075 }
mtklein36352bf2015-03-25 18:17:31 -07001076 void onFlattenLight(SkWriteBuffer& buffer) const override {
Robert Phillips959ccc22018-01-23 11:56:12 -05001077 write_point3(fLocation, buffer);
1078 write_point3(fTarget, buffer);
djsollen@google.com08337772012-06-26 14:33:13 +00001079 buffer.writeScalar(fSpecularExponent);
1080 buffer.writeScalar(fCosOuterConeAngle);
1081 buffer.writeScalar(fCosInnerConeAngle);
1082 buffer.writeScalar(fConeScale);
Robert Phillips959ccc22018-01-23 11:56:12 -05001083 write_point3(fS, buffer);
djsollen@google.com08337772012-06-26 14:33:13 +00001084 }
1085
robertphillips2f0dbc72015-08-20 05:15:06 -07001086 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001087 if (other.type() != kSpot_LightType) {
1088 return false;
1089 }
1090
1091 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1092 return INHERITED::isEqual(other) &&
1093 fLocation == o.fLocation &&
1094 fTarget == o.fTarget &&
1095 fSpecularExponent == o.fSpecularExponent &&
1096 fCosOuterConeAngle == o.fCosOuterConeAngle;
1097 }
1098
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001099private:
caryclark0bccd872015-10-20 10:04:03 -07001100 static const SkScalar kSpecularExponentMin;
1101 static const SkScalar kSpecularExponentMax;
1102
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001103 SkPoint3 fLocation;
1104 SkPoint3 fTarget;
1105 SkScalar fSpecularExponent;
Matt Sarett62745a82017-04-17 11:57:29 -04001106 SkScalar fCutoffAngle;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001107 SkScalar fCosOuterConeAngle;
1108 SkScalar fCosInnerConeAngle;
1109 SkScalar fConeScale;
1110 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001111
1112 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001113};
1114
caryclark0bccd872015-10-20 10:04:03 -07001115// According to the spec, the specular term should be in the range [1, 128] :
1116// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1117const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1118const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1119
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001120///////////////////////////////////////////////////////////////////////////////
1121
robertphillips2f0dbc72015-08-20 05:15:06 -07001122void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001123 // Write type first, then baseclass, then subclass.
1124 buffer.writeInt(this->type());
Robert Phillips959ccc22018-01-23 11:56:12 -05001125 write_point3(fColor, buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001126 this->onFlattenLight(buffer);
1127}
1128
robertphillips2f0dbc72015-08-20 05:15:06 -07001129/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -05001130 SkImageFilterLight::LightType type = buffer.read32LE(SkImageFilterLight::kLast_LightType);
Robert Phillips959ccc22018-01-23 11:56:12 -05001131
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001132 switch (type) {
1133 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1134 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001135 case SkImageFilterLight::kDistant_LightType:
1136 return new SkDistantLight(buffer);
1137 case SkImageFilterLight::kPoint_LightType:
1138 return new SkPointLight(buffer);
1139 case SkImageFilterLight::kSpot_LightType:
1140 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001141 default:
Robert Phillips959ccc22018-01-23 11:56:12 -05001142 // Should never get here due to prior check of SkSafeRange
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001143 SkDEBUGFAIL("Unknown LightType.");
halcanary96fcdcc2015-08-27 07:41:13 -07001144 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001145 }
1146}
1147///////////////////////////////////////////////////////////////////////////////
1148
robertphillips12fa47d2016-04-08 16:28:09 -07001149SkLightingImageFilter::SkLightingImageFilter(sk_sp<SkImageFilterLight> light,
1150 SkScalar surfaceScale,
1151 sk_sp<SkImageFilter> input, const CropRect* cropRect)
1152 : INHERITED(&input, 1, cropRect)
1153 , fLight(std::move(light))
1154 , fSurfaceScale(surfaceScale / 255) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001155}
1156
robertphillips82b043e2016-04-10 14:04:19 -07001157SkLightingImageFilter::~SkLightingImageFilter() {}
1158
robertphillips12fa47d2016-04-08 16:28:09 -07001159sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitDiffuse(const SkPoint3& direction,
1160 SkColor lightColor,
1161 SkScalar surfaceScale,
1162 SkScalar kd,
1163 sk_sp<SkImageFilter> input,
1164 const CropRect* cropRect) {
1165 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
Mike Kleinfc6c37b2016-09-27 09:34:10 -04001166 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
robertphillips12fa47d2016-04-08 16:28:09 -07001167 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001168}
1169
robertphillips12fa47d2016-04-08 16:28:09 -07001170sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitDiffuse(const SkPoint3& location,
1171 SkColor lightColor,
1172 SkScalar surfaceScale,
1173 SkScalar kd,
1174 sk_sp<SkImageFilter> input,
1175 const CropRect* cropRect) {
1176 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1177 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1178 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001179}
1180
robertphillips12fa47d2016-04-08 16:28:09 -07001181sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitDiffuse(const SkPoint3& location,
1182 const SkPoint3& target,
1183 SkScalar specularExponent,
1184 SkScalar cutoffAngle,
reed9fa60da2014-08-21 07:59:51 -07001185 SkColor lightColor,
1186 SkScalar surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -07001187 SkScalar kd,
1188 sk_sp<SkImageFilter> input,
reed9fa60da2014-08-21 07:59:51 -07001189 const CropRect* cropRect) {
robertphillips12fa47d2016-04-08 16:28:09 -07001190 sk_sp<SkImageFilterLight> light(
halcanary385fe4d2015-08-26 13:07:48 -07001191 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
robertphillips12fa47d2016-04-08 16:28:09 -07001192 return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1193 std::move(input), cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001194}
1195
robertphillips12fa47d2016-04-08 16:28:09 -07001196sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitSpecular(const SkPoint3& direction,
1197 SkColor lightColor,
1198 SkScalar surfaceScale,
1199 SkScalar ks,
1200 SkScalar shine,
1201 sk_sp<SkImageFilter> input,
1202 const CropRect* cropRect) {
1203 sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1204 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1205 std::move(input), cropRect);
1206}
1207
1208sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitSpecular(const SkPoint3& location,
1209 SkColor lightColor,
1210 SkScalar surfaceScale,
1211 SkScalar ks,
1212 SkScalar shine,
1213 sk_sp<SkImageFilter> input,
1214 const CropRect* cropRect) {
1215 sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1216 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1217 std::move(input), cropRect);
1218}
1219
1220sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitSpecular(const SkPoint3& location,
1221 const SkPoint3& target,
1222 SkScalar specularExponent,
1223 SkScalar cutoffAngle,
1224 SkColor lightColor,
1225 SkScalar surfaceScale,
1226 SkScalar ks,
1227 SkScalar shine,
1228 sk_sp<SkImageFilter> input,
1229 const CropRect* cropRect) {
1230 sk_sp<SkImageFilterLight> light(
1231 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
1232 return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shine,
1233 std::move(input), cropRect);
1234}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001235
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001236void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001237 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001238 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001239 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001240}
1241
Brian Salomon6b17ff62017-07-28 10:16:29 -04001242sk_sp<const SkImageFilterLight> SkLightingImageFilter::refLight() const { return fLight; }
1243
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001244///////////////////////////////////////////////////////////////////////////////
1245
robertphillips12fa47d2016-04-08 16:28:09 -07001246sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1247 SkScalar surfaceScale,
1248 SkScalar kd,
1249 sk_sp<SkImageFilter> input,
1250 const CropRect* cropRect) {
1251 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001252 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001253 }
1254 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001255 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001256 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001257 // According to the spec, kd can be any non-negative number :
1258 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001259 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001260 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001261 }
Mike Kleinfc6c37b2016-09-27 09:34:10 -04001262 return sk_sp<SkImageFilter>(new SkDiffuseLightingImageFilter(std::move(light), surfaceScale,
robertphillips12fa47d2016-04-08 16:28:09 -07001263 kd, std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001264}
1265
robertphillips12fa47d2016-04-08 16:28:09 -07001266SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001267 SkScalar surfaceScale,
1268 SkScalar kd,
robertphillips12fa47d2016-04-08 16:28:09 -07001269 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001270 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001271 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1272 , fKD(kd) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001273}
1274
reed60c9b582016-04-03 09:11:13 -07001275sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001276 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
Robert Phillips959ccc22018-01-23 11:56:12 -05001277
robertphillips12fa47d2016-04-08 16:28:09 -07001278 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001279 SkScalar surfaceScale = buffer.readScalar();
1280 SkScalar kd = buffer.readScalar();
Robert Phillips959ccc22018-01-23 11:56:12 -05001281
robertphillips12fa47d2016-04-08 16:28:09 -07001282 return Make(std::move(light), surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001283}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001284
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001285void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001286 this->INHERITED::flatten(buffer);
1287 buffer.writeScalar(fKD);
1288}
1289
robertphillipsad3dc0d2016-04-15 05:06:11 -07001290sk_sp<SkSpecialImage> SkDiffuseLightingImageFilter::onFilterImage(SkSpecialImage* source,
1291 const Context& ctx,
1292 SkIPoint* offset) const {
1293 SkIPoint inputOffset = SkIPoint::Make(0, 0);
1294 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
1295 if (!input) {
1296 return nullptr;
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001297 }
1298
robertphillipsad3dc0d2016-04-15 05:06:11 -07001299 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1300 input->width(), input->height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001301 SkIRect bounds;
robertphillipsad3dc0d2016-04-15 05:06:11 -07001302 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1303 return nullptr;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001304 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001305
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001306 offset->fX = bounds.left();
1307 offset->fY = bounds.top();
robertphillipsad3dc0d2016-04-15 05:06:11 -07001308 bounds.offset(-inputOffset);
1309
1310#if SK_SUPPORT_GPU
1311 if (source->isTextureBacked()) {
1312 SkMatrix matrix(ctx.ctm());
1313 matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1314
brianosman2a75e5d2016-09-22 07:15:37 -07001315 return this->filterImageGPU(source, input.get(), bounds, matrix, ctx.outputProperties());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001316 }
1317#endif
1318
1319 if (bounds.width() < 2 || bounds.height() < 2) {
1320 return nullptr;
1321 }
1322
1323 SkBitmap inputBM;
1324
1325 if (!input->getROPixels(&inputBM)) {
1326 return nullptr;
1327 }
1328
1329 if (inputBM.colorType() != kN32_SkColorType) {
1330 return nullptr;
1331 }
1332
robertphillipsad3dc0d2016-04-15 05:06:11 -07001333 if (!inputBM.getPixels()) {
1334 return nullptr;
1335 }
1336
1337 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1338
1339 SkBitmap dst;
1340 if (!dst.tryAllocPixels(info)) {
1341 return nullptr;
1342 }
1343
robertphillipsad3dc0d2016-04-15 05:06:11 -07001344 SkMatrix matrix(ctx.ctm());
1345 matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1346
1347 sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1348
1349 DiffuseLightingType lightingType(fKD);
Mike Reed0c182fc2017-06-16 16:55:15 -04001350 lightBitmap(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001351 transformedLight.get(),
1352 inputBM,
1353 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001354 surfaceScale(),
1355 bounds);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001356
robertphillips3e302272016-04-20 11:48:36 -07001357 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
robertphillipsad3dc0d2016-04-15 05:06:11 -07001358 dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001359}
1360
Matt Sarett62745a82017-04-17 11:57:29 -04001361sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer)
1362const {
1363 SkASSERT(1 == this->countInputs());
Mike Reed6d9f4292017-07-06 12:32:55 -04001364 auto input = xformer->apply(this->getInput(0));
1365 auto light = this->light()->makeColorSpace(xformer);
1366 if (input.get() != this->getInput(0) || light.get() != this->light()) {
1367 return SkDiffuseLightingImageFilter::Make(std::move(light), 255.0f * this->surfaceScale(),
1368 fKD, std::move(input), this->getCropRectIfSet());
1369 }
1370 return this->refMe();
Matt Sarett62745a82017-04-17 11:57:29 -04001371}
1372
robertphillipsf3f5bad2014-12-19 13:49:15 -08001373#ifndef SK_IGNORE_TO_STRING
1374void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1375 str->appendf("SkDiffuseLightingImageFilter: (");
1376 str->appendf("kD: %f\n", fKD);
1377 str->append(")");
1378}
1379#endif
1380
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001381#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -04001382std::unique_ptr<GrFragmentProcessor> SkDiffuseLightingImageFilter::makeFragmentProcessor(
1383 sk_sp<GrTextureProxy> proxy,
1384 const SkMatrix& matrix,
1385 const SkIRect* srcBounds,
1386 BoundaryMode boundaryMode) const {
Mike Reed8be952a2017-02-13 20:44:33 -05001387 SkScalar scale = this->surfaceScale() * 255;
Brian Salomon6b17ff62017-07-28 10:16:29 -04001388 return GrDiffuseLightingEffect::Make(std::move(proxy), this->refLight(), scale, matrix,
1389 this->kd(), boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001390}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001391#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001392
1393///////////////////////////////////////////////////////////////////////////////
1394
robertphillips12fa47d2016-04-08 16:28:09 -07001395sk_sp<SkImageFilter> SkSpecularLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1396 SkScalar surfaceScale,
1397 SkScalar ks,
1398 SkScalar shininess,
1399 sk_sp<SkImageFilter> input,
1400 const CropRect* cropRect) {
1401 if (!light) {
halcanary96fcdcc2015-08-27 07:41:13 -07001402 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001403 }
1404 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001405 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001406 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001407 // According to the spec, ks can be any non-negative number :
1408 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001409 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001410 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001411 }
robertphillips12fa47d2016-04-08 16:28:09 -07001412 return sk_sp<SkImageFilter>(new SkSpecularLightingImageFilter(std::move(light), surfaceScale,
1413 ks, shininess,
1414 std::move(input), cropRect));
reed9fa60da2014-08-21 07:59:51 -07001415}
1416
robertphillips12fa47d2016-04-08 16:28:09 -07001417SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
senorblancod0d37ca2015-04-02 04:54:56 -07001418 SkScalar surfaceScale,
1419 SkScalar ks,
1420 SkScalar shininess,
robertphillips12fa47d2016-04-08 16:28:09 -07001421 sk_sp<SkImageFilter> input,
senorblancod0d37ca2015-04-02 04:54:56 -07001422 const CropRect* cropRect)
robertphillips12fa47d2016-04-08 16:28:09 -07001423 : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1424 , fKS(ks)
1425 , fShininess(shininess) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001426}
1427
reed60c9b582016-04-03 09:11:13 -07001428sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -07001429 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips12fa47d2016-04-08 16:28:09 -07001430 sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001431 SkScalar surfaceScale = buffer.readScalar();
1432 SkScalar ks = buffer.readScalar();
1433 SkScalar shine = buffer.readScalar();
Robert Phillips959ccc22018-01-23 11:56:12 -05001434
robertphillips12fa47d2016-04-08 16:28:09 -07001435 return Make(std::move(light), surfaceScale, ks, shine, common.getInput(0),
1436 &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001437}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001438
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001439void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001440 this->INHERITED::flatten(buffer);
1441 buffer.writeScalar(fKS);
1442 buffer.writeScalar(fShininess);
1443}
1444
robertphillipsad3dc0d2016-04-15 05:06:11 -07001445sk_sp<SkSpecialImage> SkSpecularLightingImageFilter::onFilterImage(SkSpecialImage* source,
1446 const Context& ctx,
1447 SkIPoint* offset) const {
1448 SkIPoint inputOffset = SkIPoint::Make(0, 0);
1449 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
1450 if (!input) {
1451 return nullptr;
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001452 }
1453
robertphillipsad3dc0d2016-04-15 05:06:11 -07001454 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1455 input->width(), input->height());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001456 SkIRect bounds;
robertphillipsad3dc0d2016-04-15 05:06:11 -07001457 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1458 return nullptr;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001459 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001460
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001461 offset->fX = bounds.left();
1462 offset->fY = bounds.top();
robertphillipsad3dc0d2016-04-15 05:06:11 -07001463 bounds.offset(-inputOffset);
1464
1465#if SK_SUPPORT_GPU
1466 if (source->isTextureBacked()) {
1467 SkMatrix matrix(ctx.ctm());
1468 matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1469
brianosman2a75e5d2016-09-22 07:15:37 -07001470 return this->filterImageGPU(source, input.get(), bounds, matrix, ctx.outputProperties());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001471 }
1472#endif
1473
1474 if (bounds.width() < 2 || bounds.height() < 2) {
1475 return nullptr;
1476 }
1477
1478 SkBitmap inputBM;
1479
1480 if (!input->getROPixels(&inputBM)) {
1481 return nullptr;
1482 }
1483
1484 if (inputBM.colorType() != kN32_SkColorType) {
1485 return nullptr;
1486 }
1487
robertphillipsad3dc0d2016-04-15 05:06:11 -07001488 if (!inputBM.getPixels()) {
1489 return nullptr;
1490 }
1491
1492 const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1493
1494 SkBitmap dst;
1495 if (!dst.tryAllocPixels(info)) {
1496 return nullptr;
1497 }
1498
robertphillipsad3dc0d2016-04-15 05:06:11 -07001499 SpecularLightingType lightingType(fKS, fShininess);
1500
senorblanco7b7ecfc2015-08-26 14:26:40 -07001501 SkMatrix matrix(ctx.ctm());
robertphillipsad3dc0d2016-04-15 05:06:11 -07001502 matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1503
1504 sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1505
Mike Reed0c182fc2017-06-16 16:55:15 -04001506 lightBitmap(lightingType,
robertphillipsad3dc0d2016-04-15 05:06:11 -07001507 transformedLight.get(),
1508 inputBM,
1509 &dst,
senorblancod0d37ca2015-04-02 04:54:56 -07001510 surfaceScale(),
1511 bounds);
robertphillipsad3dc0d2016-04-15 05:06:11 -07001512
robertphillips3e302272016-04-20 11:48:36 -07001513 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001514}
1515
Matt Sarett62745a82017-04-17 11:57:29 -04001516sk_sp<SkImageFilter> SkSpecularLightingImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer)
1517const {
1518 SkASSERT(1 == this->countInputs());
1519
Mike Reed6d9f4292017-07-06 12:32:55 -04001520 auto input = xformer->apply(this->getInput(0));
1521 auto light = this->light()->makeColorSpace(xformer);
1522 if (input.get() != this->getInput(0) || light.get() != this->light()) {
1523 return SkSpecularLightingImageFilter::Make(std::move(light),
1524 255.0f * this->surfaceScale(), fKS, fShininess,
1525 std::move(input), this->getCropRectIfSet());
1526 }
1527 return this->refMe();
Matt Sarett62745a82017-04-17 11:57:29 -04001528}
1529
robertphillipsf3f5bad2014-12-19 13:49:15 -08001530#ifndef SK_IGNORE_TO_STRING
1531void SkSpecularLightingImageFilter::toString(SkString* str) const {
1532 str->appendf("SkSpecularLightingImageFilter: (");
1533 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1534 str->append(")");
1535}
1536#endif
1537
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001538#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -04001539std::unique_ptr<GrFragmentProcessor> SkSpecularLightingImageFilter::makeFragmentProcessor(
1540 sk_sp<GrTextureProxy> proxy,
1541 const SkMatrix& matrix,
1542 const SkIRect* srcBounds,
1543 BoundaryMode boundaryMode) const {
Mike Reed8be952a2017-02-13 20:44:33 -05001544 SkScalar scale = this->surfaceScale() * 255;
Brian Salomon6b17ff62017-07-28 10:16:29 -04001545 return GrSpecularLightingEffect::Make(std::move(proxy), this->refLight(), scale, matrix,
1546 this->ks(), this->shininess(), boundaryMode, srcBounds);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001547}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001548#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001549
1550///////////////////////////////////////////////////////////////////////////////
1551
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001552#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001553
Matt Sarett62745a82017-04-17 11:57:29 -04001554static SkString emitNormalFunc(BoundaryMode mode,
1555 const char* pointToNormalName,
1556 const char* sobelFuncName) {
senorblancod0d37ca2015-04-02 04:54:56 -07001557 SkString result;
1558 switch (mode) {
1559 case kTopLeft_BoundaryMode:
1560 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1561 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1562 "\t surfaceScale);\n",
1563 pointToNormalName, sobelFuncName, gTwoThirds,
1564 sobelFuncName, gTwoThirds);
1565 break;
1566 case kTop_BoundaryMode:
1567 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1568 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1569 "\t surfaceScale);\n",
1570 pointToNormalName, sobelFuncName, gOneThird,
1571 sobelFuncName, gOneHalf);
1572 break;
1573 case kTopRight_BoundaryMode:
1574 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1575 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1576 "\t surfaceScale);\n",
1577 pointToNormalName, sobelFuncName, gTwoThirds,
1578 sobelFuncName, gTwoThirds);
1579 break;
1580 case kLeft_BoundaryMode:
1581 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1582 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1583 "\t surfaceScale);\n",
1584 pointToNormalName, sobelFuncName, gOneHalf,
1585 sobelFuncName, gOneThird);
1586 break;
1587 case kInterior_BoundaryMode:
1588 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1589 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1590 "\t surfaceScale);\n",
1591 pointToNormalName, sobelFuncName, gOneQuarter,
1592 sobelFuncName, gOneQuarter);
1593 break;
1594 case kRight_BoundaryMode:
1595 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1596 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1597 "\t surfaceScale);\n",
1598 pointToNormalName, sobelFuncName, gOneHalf,
1599 sobelFuncName, gOneThird);
1600 break;
1601 case kBottomLeft_BoundaryMode:
1602 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1603 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1604 "\t surfaceScale);\n",
1605 pointToNormalName, sobelFuncName, gTwoThirds,
1606 sobelFuncName, gTwoThirds);
1607 break;
1608 case kBottom_BoundaryMode:
1609 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1610 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1611 "\t surfaceScale);\n",
1612 pointToNormalName, sobelFuncName, gOneThird,
1613 sobelFuncName, gOneHalf);
1614 break;
1615 case kBottomRight_BoundaryMode:
1616 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1617 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1618 "\t surfaceScale);\n",
1619 pointToNormalName, sobelFuncName, gTwoThirds,
1620 sobelFuncName, gTwoThirds);
1621 break;
1622 default:
1623 SkASSERT(false);
1624 break;
1625 }
1626 return result;
1627}
1628
Brian Salomon587e08f2017-01-27 10:59:27 -05001629class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001630public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001631 GrGLLightingEffect() : fLight(nullptr) { }
Brian Salomond3b65972017-03-22 12:05:03 -04001632 ~GrGLLightingEffect() override { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001633
wangyix7c157a92015-07-22 15:08:53 -07001634 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001635
Brian Salomon94efbf52016-11-29 13:43:05 -05001636 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001637
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001638protected:
wangyixb1daa862015-08-18 11:29:31 -07001639 /**
1640 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1641 */
Brian Salomonab015ef2017-04-04 10:15:51 -04001642 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001643
egdaniel7ea439b2015-12-03 09:20:44 -08001644 virtual void emitLightFunc(GrGLSLUniformHandler*,
cdalton85285412016-02-18 12:37:07 -08001645 GrGLSLFPFragmentBuilder*,
egdaniel7ea439b2015-12-03 09:20:44 -08001646 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001647
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001648private:
egdaniel64c47282015-11-13 06:54:19 -08001649 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001650
senorblanco9bd5f742016-02-17 10:59:47 -08001651 UniformHandle fImageIncrementUni;
1652 UniformHandle fSurfaceScaleUni;
1653 GrTextureDomain::GLDomain fDomain;
1654 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001655};
1656
1657///////////////////////////////////////////////////////////////////////////////
1658
1659class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1660public:
cdalton85285412016-02-18 12:37:07 -08001661 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001662
1663protected:
Brian Salomonab015ef2017-04-04 10:15:51 -04001664 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001665
1666private:
1667 typedef GrGLLightingEffect INHERITED;
1668
bsalomon@google.com032b2212012-07-16 13:36:18 +00001669 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001670};
1671
1672///////////////////////////////////////////////////////////////////////////////
1673
1674class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1675public:
cdalton85285412016-02-18 12:37:07 -08001676 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001677
1678protected:
Brian Salomonab015ef2017-04-04 10:15:51 -04001679 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001680
1681private:
1682 typedef GrGLLightingEffect INHERITED;
1683
bsalomon@google.com032b2212012-07-16 13:36:18 +00001684 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001685 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001686};
1687
1688///////////////////////////////////////////////////////////////////////////////
1689
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001690static GrTextureDomain create_domain(GrTextureProxy* proxy, const SkIRect* srcBounds,
Robert Phillipse98234f2017-01-09 14:23:59 -05001691 GrTextureDomain::Mode mode) {
senorblanco9bd5f742016-02-17 10:59:47 -08001692 if (srcBounds) {
Robert Phillipse98234f2017-01-09 14:23:59 -05001693 SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(*srcBounds, mode);
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001694 return GrTextureDomain(proxy, texelDomain, mode);
senorblanco9bd5f742016-02-17 10:59:47 -08001695 } else {
Robert Phillipse98234f2017-01-09 14:23:59 -05001696 return GrTextureDomain::IgnoredDomain();
senorblanco9bd5f742016-02-17 10:59:47 -08001697 }
1698}
1699
Ethan Nicholasabff9562017-10-09 10:54:08 -04001700GrLightingEffect::GrLightingEffect(ClassID classID,
1701 sk_sp<GrTextureProxy> proxy,
Brian Salomon6b17ff62017-07-28 10:16:29 -04001702 sk_sp<const SkImageFilterLight> light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001703 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001704 const SkMatrix& matrix,
senorblanco9bd5f742016-02-17 10:59:47 -08001705 BoundaryMode boundaryMode,
1706 const SkIRect* srcBounds)
Brian Salomonf3b995b2017-02-15 10:22:23 -05001707 // Perhaps this could advertise the opaque or coverage-as-alpha optimizations?
Ethan Nicholasabff9562017-10-09 10:54:08 -04001708 : INHERITED(classID, kNone_OptimizationFlags)
Brian Salomon6cd51b52017-07-26 19:07:15 -04001709 , fCoordTransform(proxy.get())
1710 , fDomain(create_domain(proxy.get(), srcBounds, GrTextureDomain::kDecal_Mode))
1711 , fTextureSampler(std::move(proxy))
Brian Salomon6b17ff62017-07-28 10:16:29 -04001712 , fLight(std::move(light))
Brian Salomon587e08f2017-01-27 10:59:27 -05001713 , fSurfaceScale(surfaceScale)
1714 , fFilterMatrix(matrix)
Brian Salomon6cd51b52017-07-26 19:07:15 -04001715 , fBoundaryMode(boundaryMode) {
Brian Salomon6cd51b52017-07-26 19:07:15 -04001716 this->addCoordTransform(&fCoordTransform);
1717 this->addTextureSampler(&fTextureSampler);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001718}
1719
Brian Salomon6b17ff62017-07-28 10:16:29 -04001720GrLightingEffect::GrLightingEffect(const GrLightingEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001721 : INHERITED(that.classID(), that.optimizationFlags())
Brian Salomon6b17ff62017-07-28 10:16:29 -04001722 , fCoordTransform(that.fCoordTransform)
1723 , fDomain(that.fDomain)
1724 , fTextureSampler(that.fTextureSampler)
1725 , fLight(that.fLight)
1726 , fSurfaceScale(that.fSurfaceScale)
1727 , fFilterMatrix(that.fFilterMatrix)
1728 , fBoundaryMode(that.fBoundaryMode) {
Brian Salomon6b17ff62017-07-28 10:16:29 -04001729 this->addCoordTransform(&fCoordTransform);
1730 this->addTextureSampler(&fTextureSampler);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001731}
1732
bsalomon0e08fc12014-10-15 08:19:04 -07001733bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001734 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001735 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001736 fSurfaceScale == s.fSurfaceScale &&
1737 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001738}
1739
1740///////////////////////////////////////////////////////////////////////////////
1741
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001742GrDiffuseLightingEffect::GrDiffuseLightingEffect(sk_sp<GrTextureProxy> proxy,
Brian Salomon6b17ff62017-07-28 10:16:29 -04001743 sk_sp<const SkImageFilterLight>light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001744 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001745 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001746 SkScalar kd,
senorblanco9bd5f742016-02-17 10:59:47 -08001747 BoundaryMode boundaryMode,
1748 const SkIRect* srcBounds)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001749 : INHERITED(kGrDiffuseLightingEffect_ClassID, std::move(proxy), std::move(light),
1750 surfaceScale, matrix, boundaryMode, srcBounds)
1751 , fKD(kd) {}
Brian Salomon6b17ff62017-07-28 10:16:29 -04001752
1753GrDiffuseLightingEffect::GrDiffuseLightingEffect(const GrDiffuseLightingEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001754 : INHERITED(that), fKD(that.fKD) {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001755
bsalomon0e08fc12014-10-15 08:19:04 -07001756bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001757 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001758 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001759}
1760
Brian Salomon94efbf52016-11-29 13:43:05 -05001761void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001762 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001763 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1764}
1765
egdaniel57d3b032015-11-13 11:57:27 -08001766GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001767 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001768}
1769
joshualittb0a8a372014-09-23 09:50:21 -07001770GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001771
Hal Canary6f6961e2017-01-31 13:50:44 -05001772#if GR_TEST_UTILS
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001773
1774static SkPoint3 random_point3(SkRandom* random) {
1775 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1776 SkScalarToFloat(random->nextSScalar1()),
1777 SkScalarToFloat(random->nextSScalar1()));
1778}
1779
1780static SkImageFilterLight* create_random_light(SkRandom* random) {
1781 int type = random->nextULessThan(3);
1782 switch (type) {
1783 case 0: {
1784 return new SkDistantLight(random_point3(random), random->nextU());
1785 }
1786 case 1: {
1787 return new SkPointLight(random_point3(random), random->nextU());
1788 }
1789 case 2: {
1790 return new SkSpotLight(random_point3(random), random_point3(random),
1791 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
1792 }
1793 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -04001794 SK_ABORT("Unexpected value.");
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001795 return nullptr;
1796 }
1797}
1798
Brian Salomonaff329b2017-08-11 09:40:37 -04001799std::unique_ptr<GrFragmentProcessor> GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001800 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
1801 : GrProcessorUnitTest::kAlphaTextureIdx;
1802 sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
joshualitt0067ff52015-07-08 14:26:19 -07001803 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1804 SkScalar kd = d->fRandom->nextUScalar1();
Hal Canary67b39de2016-11-07 11:47:44 -05001805 sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001806 SkMatrix matrix;
1807 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001808 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001809 }
Robert Phillips8e1c4e62017-02-19 12:27:01 -05001810 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()),
1811 d->fRandom->nextRangeU(0, proxy->height()),
1812 d->fRandom->nextRangeU(0, proxy->width()),
1813 d->fRandom->nextRangeU(0, proxy->height()));
joshualitt0067ff52015-07-08 14:26:19 -07001814 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
Brian Salomon6b17ff62017-07-28 10:16:29 -04001815 return GrDiffuseLightingEffect::Make(std::move(proxy), std::move(light), surfaceScale, matrix,
1816 kd, mode, &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001817}
Hal Canary6f6961e2017-01-31 13:50:44 -05001818#endif
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001819
1820
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001821///////////////////////////////////////////////////////////////////////////////
1822
wangyix7c157a92015-07-22 15:08:53 -07001823void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001824 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1825 if (!fLight) {
1826 fLight = le.light()->createGLLight();
1827 }
1828
egdaniel7ea439b2015-12-03 09:20:44 -08001829 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
cdalton5e58cee2016-02-11 12:49:47 -08001830 fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001831 kHalf2_GrSLType, "ImageIncrement");
cdalton5e58cee2016-02-11 12:49:47 -08001832 fSurfaceScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001833 kHalf_GrSLType, "SurfaceScale");
egdaniel7ea439b2015-12-03 09:20:44 -08001834 fLight->emitLightColorUniform(uniformHandler);
cdalton85285412016-02-18 12:37:07 -08001835 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001836 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001837 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
Brian Salomon99938a82016-11-21 13:41:08 -05001838 static const GrShaderVar gSobelArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001839 GrShaderVar("a", kHalf_GrSLType),
1840 GrShaderVar("b", kHalf_GrSLType),
1841 GrShaderVar("c", kHalf_GrSLType),
1842 GrShaderVar("d", kHalf_GrSLType),
1843 GrShaderVar("e", kHalf_GrSLType),
1844 GrShaderVar("f", kHalf_GrSLType),
1845 GrShaderVar("scale", kHalf_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001846 };
1847 SkString sobelFuncName;
bsalomon1a1aa932016-09-12 09:30:36 -07001848 SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
joshualitt30ba4362014-08-21 20:18:45 -07001849
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001850 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001851 "sobel",
1852 SK_ARRAY_COUNT(gSobelArgs),
1853 gSobelArgs,
1854 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1855 &sobelFuncName);
Brian Salomon99938a82016-11-21 13:41:08 -05001856 static const GrShaderVar gPointToNormalArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001857 GrShaderVar("x", kHalf_GrSLType),
1858 GrShaderVar("y", kHalf_GrSLType),
1859 GrShaderVar("scale", kHalf_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001860 };
1861 SkString pointToNormalName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001862 fragBuilder->emitFunction(kHalf3_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001863 "pointToNormal",
1864 SK_ARRAY_COUNT(gPointToNormalArgs),
1865 gPointToNormalArgs,
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001866 "\treturn normalize(half3(-x * scale, -y * scale, 1));\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001867 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001868
Brian Salomon99938a82016-11-21 13:41:08 -05001869 static const GrShaderVar gInteriorNormalArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001870 GrShaderVar("m", kHalf_GrSLType, 9),
1871 GrShaderVar("surfaceScale", kHalf_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001872 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001873 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001874 pointToNormalName.c_str(),
1875 sobelFuncName.c_str());
1876 SkString normalName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001877 fragBuilder->emitFunction(kHalf3_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001878 "normal",
1879 SK_ARRAY_COUNT(gInteriorNormalArgs),
1880 gInteriorNormalArgs,
1881 normalBody.c_str(),
1882 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001883
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001884 fragBuilder->codeAppendf("\t\tfloat2 coord = %s;\n", coords2D.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001885 fragBuilder->codeAppend("\t\thalf m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001886
egdaniel7ea439b2015-12-03 09:20:44 -08001887 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1888 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001889
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001890 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001891 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001892 for (int dx = -1; dx <= 1; dx++) {
1893 SkString texCoords;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001894 texCoords.appendf("coord + half2(%d, %d) * %s", dx, dy, imgInc);
senorblanco9bd5f742016-02-17 10:59:47 -08001895 SkString temp;
1896 temp.appendf("temp%d", index);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001897 fragBuilder->codeAppendf("half4 %s;", temp.c_str());
senorblanco9bd5f742016-02-17 10:59:47 -08001898 fDomain.sampleTexture(fragBuilder,
1899 args.fUniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -05001900 args.fShaderCaps,
senorblanco9bd5f742016-02-17 10:59:47 -08001901 le.domain(),
1902 temp.c_str(),
1903 texCoords,
cdalton3f6f76f2016-04-11 12:18:09 -07001904 args.fTexSamplers[0]);
senorblanco9bd5f742016-02-17 10:59:47 -08001905 fragBuilder->codeAppendf("m[%d] = %s.a;", index, temp.c_str());
1906 index++;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001907 }
1908 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001909 fragBuilder->codeAppend("\t\thalf3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001910 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001911 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001912 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001913 fragBuilder->codeAppend(";\n");
1914 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1915 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001916 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001917 fragBuilder->codeAppend(");\n");
Ethan Nicholas2983f402017-05-08 09:36:08 -04001918 fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001919}
1920
joshualittb0a8a372014-09-23 09:50:21 -07001921void GrGLLightingEffect::GenKey(const GrProcessor& proc,
Brian Salomon94efbf52016-11-29 13:43:05 -05001922 const GrShaderCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001923 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1924 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco9bd5f742016-02-17 10:59:47 -08001925 b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain()));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001926}
1927
egdaniel018fb622015-10-28 07:26:40 -07001928void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001929 const GrFragmentProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001930 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001931 if (!fLight) {
1932 fLight = lighting.light()->createGLLight();
1933 }
1934
Robert Phillipsc686ce32017-07-21 14:12:29 -04001935 GrTextureProxy* proxy = lighting.textureSampler(0).proxy();
1936 GrTexture* texture = proxy->priv().peekTexture();
Robert Phillips9bee2e52017-05-29 12:37:20 -04001937
Robert Phillipsc686ce32017-07-21 14:12:29 -04001938 float ySign = proxy->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001939 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1940 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
Hal Canary67b39de2016-11-07 11:47:44 -05001941 sk_sp<SkImageFilterLight> transformedLight(
1942 lighting.light()->transform(lighting.filterMatrix()));
Robert Phillipsc686ce32017-07-21 14:12:29 -04001943 fDomain.setData(pdman, lighting.domain(), proxy);
Hal Canary67b39de2016-11-07 11:47:44 -05001944 fLight->setData(pdman, transformedLight.get());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001945}
1946
1947///////////////////////////////////////////////////////////////////////////////
1948
1949///////////////////////////////////////////////////////////////////////////////
1950
egdaniel7ea439b2015-12-03 09:20:44 -08001951void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08001952 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08001953 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001954 const char* kd;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001955 fKDUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001956
Brian Salomon99938a82016-11-21 13:41:08 -05001957 static const GrShaderVar gLightArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001958 GrShaderVar("normal", kHalf3_GrSLType),
1959 GrShaderVar("surfaceToLight", kHalf3_GrSLType),
1960 GrShaderVar("lightColor", kHalf3_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001961 };
1962 SkString lightBody;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001963 lightBody.appendf("\thalf colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1964 lightBody.appendf("\treturn half4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1965 fragBuilder->emitFunction(kHalf4_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001966 "light",
1967 SK_ARRAY_COUNT(gLightArgs),
1968 gLightArgs,
1969 lightBody.c_str(),
1970 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001971}
1972
egdaniel018fb622015-10-28 07:26:40 -07001973void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001974 const GrFragmentProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001975 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001976 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001977 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001978}
1979
1980///////////////////////////////////////////////////////////////////////////////
1981
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001982GrSpecularLightingEffect::GrSpecularLightingEffect(sk_sp<GrTextureProxy> proxy,
Brian Salomon6b17ff62017-07-28 10:16:29 -04001983 sk_sp<const SkImageFilterLight> light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001984 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001985 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001986 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001987 SkScalar shininess,
senorblanco9bd5f742016-02-17 10:59:47 -08001988 BoundaryMode boundaryMode,
1989 const SkIRect* srcBounds)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001990 : INHERITED(kGrSpecularLightingEffect_ClassID, std::move(proxy), std::move(light),
1991 surfaceScale, matrix, boundaryMode, srcBounds)
Brian Salomon6b17ff62017-07-28 10:16:29 -04001992 , fKS(ks)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001993 , fShininess(shininess) {}
Brian Salomon6b17ff62017-07-28 10:16:29 -04001994
1995GrSpecularLightingEffect::GrSpecularLightingEffect(const GrSpecularLightingEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001996 : INHERITED(that), fKS(that.fKS), fShininess(that.fShininess) {}
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001997
bsalomon0e08fc12014-10-15 08:19:04 -07001998bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001999 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00002000 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002001 this->ks() == s.ks() &&
2002 this->shininess() == s.shininess();
2003}
2004
Brian Salomon94efbf52016-11-29 13:43:05 -05002005void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08002006 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08002007 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
2008}
2009
egdaniel57d3b032015-11-13 11:57:27 -08002010GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08002011 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08002012}
2013
joshualittb0a8a372014-09-23 09:50:21 -07002014GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002015
Hal Canary6f6961e2017-01-31 13:50:44 -05002016#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04002017std::unique_ptr<GrFragmentProcessor> GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
Robert Phillips8e1c4e62017-02-19 12:27:01 -05002018 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
2019 : GrProcessorUnitTest::kAlphaTextureIdx;
2020 sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
joshualitt0067ff52015-07-08 14:26:19 -07002021 SkScalar surfaceScale = d->fRandom->nextSScalar1();
2022 SkScalar ks = d->fRandom->nextUScalar1();
2023 SkScalar shininess = d->fRandom->nextUScalar1();
Hal Canary67b39de2016-11-07 11:47:44 -05002024 sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00002025 SkMatrix matrix;
2026 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07002027 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00002028 }
joshualitt0067ff52015-07-08 14:26:19 -07002029 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
Robert Phillips8e1c4e62017-02-19 12:27:01 -05002030 SkIRect srcBounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()),
2031 d->fRandom->nextRangeU(0, proxy->height()),
2032 d->fRandom->nextRangeU(0, proxy->width()),
2033 d->fRandom->nextRangeU(0, proxy->height()));
Brian Salomon6b17ff62017-07-28 10:16:29 -04002034 return GrSpecularLightingEffect::Make(std::move(proxy), std::move(light), surfaceScale, matrix,
2035 ks, shininess, mode, &srcBounds);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002036}
Hal Canary6f6961e2017-01-31 13:50:44 -05002037#endif
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002038
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002039///////////////////////////////////////////////////////////////////////////////
2040
egdaniel7ea439b2015-12-03 09:20:44 -08002041void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002042 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002043 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002044 const char* ks;
2045 const char* shininess;
2046
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002047 fKSUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "KS", &ks);
cdalton5e58cee2016-02-11 12:49:47 -08002048 fShininessUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002049 kHalf_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002050 "Shininess",
2051 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002052
Brian Salomon99938a82016-11-21 13:41:08 -05002053 static const GrShaderVar gLightArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002054 GrShaderVar("normal", kHalf3_GrSLType),
2055 GrShaderVar("surfaceToLight", kHalf3_GrSLType),
2056 GrShaderVar("lightColor", kHalf3_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002057 };
2058 SkString lightBody;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002059 lightBody.appendf("\thalf3 halfDir = half3(normalize(surfaceToLight + half3(0, 0, 1)));\n");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04002060 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n",
Brian Osman9bc39bb2017-03-17 09:36:31 -04002061 ks, shininess);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002062 lightBody.appendf("\thalf3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
2063 lightBody.appendf("\treturn half4(color, max(max(color.r, color.g), color.b));\n");
2064 fragBuilder->emitFunction(kHalf4_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08002065 "light",
2066 SK_ARRAY_COUNT(gLightArgs),
2067 gLightArgs,
2068 lightBody.c_str(),
2069 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002070}
2071
egdaniel018fb622015-10-28 07:26:40 -07002072void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04002073 const GrFragmentProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07002074 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07002075 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07002076 pdman.set1f(fKSUni, spec.ks());
2077 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002078}
2079
2080///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08002081void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002082 fColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType, "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002083}
2084
egdaniel7ea439b2015-12-03 09:20:44 -08002085void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002086 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002087 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08002088 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002089}
2090
egdaniel018fb622015-10-28 07:26:40 -07002091void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002092 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07002093 setUniformPoint3(pdman, fColorUni,
2094 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002095}
2096
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002097///////////////////////////////////////////////////////////////////////////////
2098
egdaniel018fb622015-10-28 07:26:40 -07002099void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002100 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002101 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002102 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002103 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002104 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002105}
2106
egdaniel7ea439b2015-12-03 09:20:44 -08002107void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002108 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002109 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002110 const char* dir;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002111 fDirectionUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002112 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08002113 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002114}
2115
2116///////////////////////////////////////////////////////////////////////////////
2117
egdaniel018fb622015-10-28 07:26:40 -07002118void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002119 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002120 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002121 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002122 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002123 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002124}
2125
egdaniel7ea439b2015-12-03 09:20:44 -08002126void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002127 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002128 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002129 const char* loc;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002130 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002131 "LightLocation", &loc);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002132 fragBuilder->codeAppendf("normalize(%s - half3(sk_FragCoord.xy, %s))",
Ethan Nicholas38657112017-02-09 17:01:22 -05002133 loc, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002134}
2135
2136///////////////////////////////////////////////////////////////////////////////
2137
egdaniel018fb622015-10-28 07:26:40 -07002138void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07002139 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07002140 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07002141 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002142 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07002143 setUniformPoint3(pdman, fLocationUni, spotLight->location());
2144 pdman.set1f(fExponentUni, spotLight->specularExponent());
2145 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
2146 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
2147 pdman.set1f(fConeScaleUni, spotLight->coneScale());
2148 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002149}
2150
egdaniel7ea439b2015-12-03 09:20:44 -08002151void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002152 GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel4ca2e602015-11-18 08:01:26 -08002153 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002154 const char* location;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002155 fLocationUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002156 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07002157
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002158 fragBuilder->codeAppendf("normalize(%s - half3(sk_FragCoord.xy, %s))",
Ethan Nicholas38657112017-02-09 17:01:22 -05002159 location, z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002160}
2161
egdaniel7ea439b2015-12-03 09:20:44 -08002162void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
cdalton85285412016-02-18 12:37:07 -08002163 GrGLSLFPFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002164 const char *surfaceToLight) {
2165
egdaniel7ea439b2015-12-03 09:20:44 -08002166 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002167
2168 const char* exponent;
2169 const char* cosInner;
2170 const char* cosOuter;
2171 const char* coneScale;
2172 const char* s;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002173 fExponentUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002174 "Exponent", &exponent);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002175 fCosInnerConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002176 "CosInnerConeAngle", &cosInner);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002177 fCosOuterConeAngleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002178 "CosOuterConeAngle", &cosOuter);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002179 fConeScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -08002180 "ConeScale", &coneScale);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002181 fSUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002182
Brian Salomon99938a82016-11-21 13:41:08 -05002183 static const GrShaderVar gLightColorArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002184 GrShaderVar("surfaceToLight", kHalf3_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002185 };
2186 SkString lightColorBody;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002187 lightColorBody.appendf("\thalf cosAngle = -dot(surfaceToLight, %s);\n", s);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002188 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002189 lightColorBody.appendf("\t\treturn half3(0);\n");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002190 lightColorBody.appendf("\t}\n");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002191 lightColorBody.appendf("\thalf scale = pow(cosAngle, %s);\n", exponent);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002192 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2193 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2194 color, cosOuter, coneScale);
2195 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002196 lightColorBody.appendf("\treturn %s;\n", color);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002197 fragBuilder->emitFunction(kHalf3_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08002198 "lightColor",
2199 SK_ARRAY_COUNT(gLightColorArgs),
2200 gLightColorArgs,
2201 lightColorBody.c_str(),
2202 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002203
egdaniel4ca2e602015-11-18 08:01:26 -08002204 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002205}
2206
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002207#endif
2208
djsollen@google.com08337772012-06-26 14:33:13 +00002209SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2210 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2211 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002212SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END