blob: a891fe135c5fa06fe54e0abf3f7b47258f454efe [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
senorblanco1d3ff432015-10-20 10:17:34 -070011#include "SkDevice.h"
robertphillips3d32d762015-07-13 13:16:44 -070012#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070015#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070018#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070019#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
21#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070022#include "GrPaint.h"
robertphillips1de87df2016-01-14 06:03:29 -080023#include "SkGr.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000024#include "effects/GrSingleTextureEffect.h"
egdaniel64c47282015-11-13 06:54:19 -080025#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080026#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080028#include "glsl/GrGLSLUniformHandler.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000029
30class GrGLDiffuseLightingEffect;
31class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000032
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000033// For brevity
egdaniel018fb622015-10-28 07:26:40 -070034typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000035#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000036
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037namespace {
38
reed80ea19c2015-05-12 10:37:34 -070039const SkScalar gOneThird = SkIntToScalar(1) / 3;
40const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000041const SkScalar gOneHalf = 0.5f;
42const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000043
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000044#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070045void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070046 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070047 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070048 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000049}
50
egdaniel018fb622015-10-28 07:26:40 -070051void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070052 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070053 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000054}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000055#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000056
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000057// Shift matrix components to the left, as we advance pixels to the right.
58inline void shiftMatrixLeft(int m[9]) {
59 m[0] = m[1];
60 m[3] = m[4];
61 m[6] = m[7];
62 m[1] = m[2];
63 m[4] = m[5];
64 m[7] = m[8];
65}
66
jvanverth992c7612015-07-17 07:22:30 -070067static inline void fast_normalize(SkPoint3* vector) {
68 // add a tiny bit so we don't have to worry about divide-by-zero
69 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
70 SkScalar scale = sk_float_rsqrt(magSq);
71 vector->fX *= scale;
72 vector->fY *= scale;
73 vector->fZ *= scale;
74}
75
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000076class DiffuseLightingType {
77public:
78 DiffuseLightingType(SkScalar kd)
79 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070080 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
81 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000082 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
83 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070084 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000086 SkClampMax(SkScalarRoundToInt(color.fX), 255),
87 SkClampMax(SkScalarRoundToInt(color.fY), 255),
88 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000089 }
90private:
91 SkScalar fKD;
92};
93
robertphillips3d32d762015-07-13 13:16:44 -070094static SkScalar max_component(const SkPoint3& p) {
95 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
96}
97
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000098class SpecularLightingType {
99public:
100 SpecularLightingType(SkScalar ks, SkScalar shininess)
101 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700102 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
103 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000104 SkPoint3 halfDir(surfaceTolight);
105 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700106 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000107 SkScalar colorScale = SkScalarMul(fKS,
108 SkScalarPow(normal.dot(halfDir), fShininess));
109 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700110 SkPoint3 color = lightColor.makeScale(colorScale);
111 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000112 SkClampMax(SkScalarRoundToInt(color.fX), 255),
113 SkClampMax(SkScalarRoundToInt(color.fY), 255),
114 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000115 }
116private:
117 SkScalar fKS;
118 SkScalar fShininess;
119};
120
121inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
122 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
123}
124
125inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700126 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
127 SkScalarMul(-y, surfaceScale),
128 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700129 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000130 return vector;
131}
132
133inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
134 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
135 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
136 surfaceScale);
137}
138
139inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
141 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
142 surfaceScale);
143}
144
145inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
147 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
148 surfaceScale);
149}
150
151inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
153 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
154 surfaceScale);
155}
156
157
158inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
160 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
161 surfaceScale);
162}
163
164inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
165 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
166 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
167 surfaceScale);
168}
169
170inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
171 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
172 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
173 surfaceScale);
174}
175
176inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
177 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
178 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
179 surfaceScale);
180}
181
182inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
183 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
184 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
185 surfaceScale);
186}
187
robertphillips2f0dbc72015-08-20 05:15:06 -0700188template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType,
189 const SkImageFilterLight* light,
190 const SkBitmap& src,
191 SkBitmap* dst,
192 SkScalar surfaceScale,
193 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000194 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000195 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000196 int left = bounds.left(), right = bounds.right();
197 int bottom = bounds.bottom();
198 int y = bounds.top();
199 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000200 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000201 int x = left;
202 const SkPMColor* row1 = src.getAddr32(x, y);
203 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000205 m[4] = SkGetPackedA32(*row1++);
206 m[5] = SkGetPackedA32(*row1++);
207 m[7] = SkGetPackedA32(*row2++);
208 m[8] = SkGetPackedA32(*row2++);
209 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700210 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
211 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000212 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000213 {
214 shiftMatrixLeft(m);
215 m[5] = SkGetPackedA32(*row1++);
216 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700218 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
219 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000220 }
221 shiftMatrixLeft(m);
222 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700223 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
224 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000225 }
226
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000227 for (++y; y < bottom - 1; ++y) {
228 int x = left;
229 const SkPMColor* row0 = src.getAddr32(x, y - 1);
230 const SkPMColor* row1 = src.getAddr32(x, y);
231 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000232 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 m[1] = SkGetPackedA32(*row0++);
234 m[2] = SkGetPackedA32(*row0++);
235 m[4] = SkGetPackedA32(*row1++);
236 m[5] = SkGetPackedA32(*row1++);
237 m[7] = SkGetPackedA32(*row2++);
238 m[8] = SkGetPackedA32(*row2++);
239 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700240 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
241 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000242 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000243 shiftMatrixLeft(m);
244 m[2] = SkGetPackedA32(*row0++);
245 m[5] = SkGetPackedA32(*row1++);
246 m[8] = SkGetPackedA32(*row2++);
247 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700248 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
249 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000250 }
251 shiftMatrixLeft(m);
252 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700253 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
254 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000255 }
256
257 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000258 int x = left;
259 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
260 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000261 int m[9];
262 m[1] = SkGetPackedA32(*row0++);
263 m[2] = SkGetPackedA32(*row0++);
264 m[4] = SkGetPackedA32(*row1++);
265 m[5] = SkGetPackedA32(*row1++);
266 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700267 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
268 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000269 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270 {
271 shiftMatrixLeft(m);
272 m[2] = SkGetPackedA32(*row0++);
273 m[5] = SkGetPackedA32(*row1++);
274 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700275 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
276 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000277 }
278 shiftMatrixLeft(m);
279 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700280 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
281 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000282 }
283}
284
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000285SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 SkPoint3 point;
287 point.fX = buffer.readScalar();
288 point.fY = buffer.readScalar();
289 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000290 buffer.validate(SkScalarIsFinite(point.fX) &&
291 SkScalarIsFinite(point.fY) &&
292 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000293 return point;
294};
295
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000296void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297 buffer.writeScalar(point.fX);
298 buffer.writeScalar(point.fY);
299 buffer.writeScalar(point.fZ);
300};
301
senorblancod0d37ca2015-04-02 04:54:56 -0700302enum BoundaryMode {
303 kTopLeft_BoundaryMode,
304 kTop_BoundaryMode,
305 kTopRight_BoundaryMode,
306 kLeft_BoundaryMode,
307 kInterior_BoundaryMode,
308 kRight_BoundaryMode,
309 kBottomLeft_BoundaryMode,
310 kBottom_BoundaryMode,
311 kBottomRight_BoundaryMode,
312
313 kBoundaryModeCount,
314};
315
316class SkLightingImageFilterInternal : public SkLightingImageFilter {
317protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700318 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700319 SkScalar surfaceScale,
320 SkImageFilter* input,
321 const CropRect* cropRect)
322 : INHERITED(light, surfaceScale, input, cropRect) {}
323
324#if SK_SUPPORT_GPU
325 bool canFilterImageGPU() const override { return true; }
326 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
327 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700328 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700329 const SkMatrix&,
330 const SkIRect& bounds,
331 BoundaryMode boundaryMode) const = 0;
332#endif
333private:
334#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700335 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700336 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700337 const SkMatrix& matrix,
338 const GrClip& clip,
339 const SkRect& dstRect,
340 BoundaryMode boundaryMode,
341 const SkIRect& bounds) const;
342#endif
343 typedef SkLightingImageFilter INHERITED;
344};
345
346#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700347void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700348 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700349 const SkMatrix& matrix,
350 const GrClip& clip,
351 const SkRect& dstRect,
352 BoundaryMode boundaryMode,
353 const SkIRect& bounds) const {
354 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700355 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700356 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700357 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800358 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800359 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700360}
361
362bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
363 const SkBitmap& src,
364 const Context& ctx,
365 SkBitmap* result,
366 SkIPoint* offset) const {
367 SkBitmap input = src;
368 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700369 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700370 return false;
371 }
372 SkIRect bounds;
373 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
374 return false;
375 }
376 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
377 SkIntToScalar(bounds.height()));
378 GrTexture* srcTexture = input.getTexture();
379 GrContext* context = srcTexture->getContext();
380
381 GrSurfaceDesc desc;
382 desc.fFlags = kRenderTarget_GrSurfaceFlag,
383 desc.fWidth = bounds.width();
384 desc.fHeight = bounds.height();
385 desc.fConfig = kRGBA_8888_GrPixelConfig;
386
reed4e23cda2016-01-11 10:56:59 -0800387 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700388 if (!dst) {
389 return false;
390 }
391
392 // setup new clip
393 GrClip clip(dstRect);
394
395 offset->fX = bounds.left();
396 offset->fY = bounds.top();
397 SkMatrix matrix(ctx.ctm());
398 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
399 bounds.offset(-srcOffset);
400 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
401 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
402 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
403 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
404 SkRect interior = dstRect.makeInset(1, 1);
405 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
406 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
407 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
408 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700409
robertphillips2e1e51f2015-10-15 08:01:48 -0700410 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700411 if (!drawContext) {
412 return false;
413 }
414
robertphillips2e1e51f2015-10-15 08:01:48 -0700415 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
416 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
417 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700418 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700419 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
420 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700421 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700422 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
423 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700424 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700425 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
426 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700427 kBottomRight_BoundaryMode, bounds);
robertphillips1de87df2016-01-14 06:03:29 -0800428 GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
senorblancod0d37ca2015-04-02 04:54:56 -0700429 return true;
430}
431#endif
432
433class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000434public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700435 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
436 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700437 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700438
robertphillipsf3f5bad2014-12-19 13:49:15 -0800439 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000440 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000441 SkScalar kd() const { return fKD; }
442
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000443protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700444 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700445 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700446 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700447 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
448 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000449#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700450 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
451 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000452#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000453
454private:
reed9fa60da2014-08-21 07:59:51 -0700455 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700456 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000457 SkScalar fKD;
458};
459
senorblancod0d37ca2015-04-02 04:54:56 -0700460class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700462 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700463 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700464
robertphillipsf3f5bad2014-12-19 13:49:15 -0800465 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000466 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
467
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000468 SkScalar ks() const { return fKS; }
469 SkScalar shininess() const { return fShininess; }
470
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700472 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700473 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700474 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700475 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
476 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000477#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700478 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
479 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000480#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481
482private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483 SkScalar fKS;
484 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700485 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700486 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000487};
488
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000489#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000491class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492public:
bsalomon4a339522015-10-06 08:40:50 -0700493 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
494 const SkMatrix& matrix, BoundaryMode boundaryMode);
robertphillipse004bfc2015-11-16 09:06:59 -0800495 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496
robertphillips2f0dbc72015-08-20 05:15:06 -0700497 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000498 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000499 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700500 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000501
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000502protected:
mtklein36352bf2015-03-25 18:17:31 -0700503 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000504
mtklein36352bf2015-03-25 18:17:31 -0700505 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700506 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800507 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700508 }
509
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700511 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000512 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000513 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700514 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700515
516 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000517};
518
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000519class GrDiffuseLightingEffect : public GrLightingEffect {
520public:
bsalomon4a339522015-10-06 08:40:50 -0700521 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700522 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700523 SkScalar surfaceScale,
524 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700525 SkScalar kd,
526 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700527 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000528 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529
mtklein36352bf2015-03-25 18:17:31 -0700530 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000531
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000532 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534private:
egdaniel57d3b032015-11-13 11:57:27 -0800535 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700536
egdaniel57d3b032015-11-13 11:57:27 -0800537 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700538
mtklein36352bf2015-03-25 18:17:31 -0700539 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000540
bsalomon4a339522015-10-06 08:40:50 -0700541 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700542 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000543 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000544 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700545 SkScalar kd,
546 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000547
joshualittb0a8a372014-09-23 09:50:21 -0700548 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000549 typedef GrLightingEffect INHERITED;
550 SkScalar fKD;
551};
552
553class GrSpecularLightingEffect : public GrLightingEffect {
554public:
bsalomon4a339522015-10-06 08:40:50 -0700555 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700556 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700557 SkScalar surfaceScale,
558 const SkMatrix& matrix,
559 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700560 SkScalar shininess,
561 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700562 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
563 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000564 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565
mtklein36352bf2015-03-25 18:17:31 -0700566 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567
egdaniel57d3b032015-11-13 11:57:27 -0800568 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800569
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000570 SkScalar ks() const { return fKS; }
571 SkScalar shininess() const { return fShininess; }
572
573private:
egdaniel57d3b032015-11-13 11:57:27 -0800574 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700575
mtklein36352bf2015-03-25 18:17:31 -0700576 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000577
bsalomon4a339522015-10-06 08:40:50 -0700578 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700579 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000580 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000581 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000582 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700583 SkScalar shininess,
584 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000585
joshualittb0a8a372014-09-23 09:50:21 -0700586 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000587 typedef GrLightingEffect INHERITED;
588 SkScalar fKS;
589 SkScalar fShininess;
590};
591
592///////////////////////////////////////////////////////////////////////////////
593
594class GrGLLight {
595public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000596 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000597
598 /**
599 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
600 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
601 */
egdaniel7ea439b2015-12-03 09:20:44 -0800602 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000603
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000604 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000605 * These two functions are called from GrGLLightingEffect's emitCode() function.
606 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
607 * the light. The expression will be used in the FS. emitLightColor writes an expression into
608 * the FS that is the color of the light. Either function may add functions and/or uniforms to
609 * the FS. The default of emitLightColor appends the name of the constant light color uniform
610 * and so this function only needs to be overridden if the light color varies spatially.
611 */
egdaniel7ea439b2015-12-03 09:20:44 -0800612 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
613 GrGLSLFragmentBuilder*,
614 const char* z) = 0;
615 virtual void emitLightColor(GrGLSLUniformHandler*,
egdaniel4ca2e602015-11-18 08:01:26 -0800616 GrGLSLFragmentBuilder*,
617 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000618
619 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
620 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700621 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000622
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000623protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000624 /**
625 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
626 * function.
627 */
628 UniformHandle lightColorUni() const { return fColorUni; }
629
630private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000631 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000632
633 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000634};
635
636///////////////////////////////////////////////////////////////////////////////
637
638class GrGLDistantLight : public GrGLLight {
639public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000640 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700641 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800642 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000643
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000644private:
645 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000646 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000647};
648
649///////////////////////////////////////////////////////////////////////////////
650
651class GrGLPointLight : public GrGLLight {
652public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000653 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700654 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800655 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000656
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000657private:
658 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000659 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000660};
661
662///////////////////////////////////////////////////////////////////////////////
663
664class GrGLSpotLight : public GrGLLight {
665public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000666 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700667 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800668 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
669 void emitLightColor(GrGLSLUniformHandler*,
egdaniel4ca2e602015-11-18 08:01:26 -0800670 GrGLSLFragmentBuilder*,
671 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000672
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000673private:
674 typedef GrGLLight INHERITED;
675
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000676 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000677 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000678 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000679 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000680 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000681 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000682 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000683};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000684#else
685
686class GrGLLight;
687
688#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000689
690};
691
692///////////////////////////////////////////////////////////////////////////////
693
robertphillips2f0dbc72015-08-20 05:15:06 -0700694class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695public:
caryclark0bccd872015-10-20 10:04:03 -0700696
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000697
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698 enum LightType {
699 kDistant_LightType,
700 kPoint_LightType,
701 kSpot_LightType,
702 };
703 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000704 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000705 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700706 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000707 return fColor == other.fColor;
708 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000709 // Called to know whether the generated GrGLLight will require access to the fragment position.
710 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700711 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000713 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000714 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700715 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000716
djsollen@google.com08337772012-06-26 14:33:13 +0000717protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700718 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700719 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
720 SkIntToScalar(SkColorGetG(color)),
721 SkIntToScalar(SkColorGetB(color)));
722 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700723 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000724 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700725 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000726 fColor = readPoint3(buffer);
727 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000728
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000729 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000730
djsollen@google.com08337772012-06-26 14:33:13 +0000731
732private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000733 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000735};
736
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000737///////////////////////////////////////////////////////////////////////////////
738
robertphillips2f0dbc72015-08-20 05:15:06 -0700739class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000740public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 SkDistantLight(const SkPoint3& direction, SkColor color)
742 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743 }
djsollen@google.com08337772012-06-26 14:33:13 +0000744
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000745 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
746 return fDirection;
747 };
robertphillips3d32d762015-07-13 13:16:44 -0700748 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700749 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000750 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700751 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000752#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700753 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000754#else
755 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700756 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000757#endif
758 }
mtklein36352bf2015-03-25 18:17:31 -0700759 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000760
robertphillips2f0dbc72015-08-20 05:15:06 -0700761 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000762 if (other.type() != kDistant_LightType) {
763 return false;
764 }
765
766 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
767 return INHERITED::isEqual(other) &&
768 fDirection == o.fDirection;
769 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000770
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000771 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000772 fDirection = readPoint3(buffer);
773 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774
djsollen@google.com08337772012-06-26 14:33:13 +0000775protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000776 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
777 : INHERITED(color), fDirection(direction) {
778 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700779 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000780 return new SkDistantLight(direction(), color());
781 }
mtklein36352bf2015-03-25 18:17:31 -0700782 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000783 writePoint3(fDirection, buffer);
784 }
785
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786private:
787 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700788
789 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000790};
791
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000792///////////////////////////////////////////////////////////////////////////////
793
robertphillips2f0dbc72015-08-20 05:15:06 -0700794class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000795public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000796 SkPointLight(const SkPoint3& location, SkColor color)
797 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000798
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000799 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700800 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
801 fLocation.fY - SkIntToScalar(y),
802 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
803 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700804 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000805 return direction;
806 };
robertphillips3d32d762015-07-13 13:16:44 -0700807 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700808 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000809 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700810 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000811#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700812 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000813#else
814 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700815 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000816#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000817 }
mtklein36352bf2015-03-25 18:17:31 -0700818 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700819 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000820 if (other.type() != kPoint_LightType) {
821 return false;
822 }
823 const SkPointLight& o = static_cast<const SkPointLight&>(other);
824 return INHERITED::isEqual(other) &&
825 fLocation == o.fLocation;
826 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700827 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000828 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
829 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000830 // Use X scale and Y scale on Z and average the result
831 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
832 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700833 SkPoint3 location = SkPoint3::Make(location2.fX,
834 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700835 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000836 return new SkPointLight(location, color());
837 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000838
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000839 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000840 fLocation = readPoint3(buffer);
841 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000842
843protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000844 SkPointLight(const SkPoint3& location, const SkPoint3& color)
845 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700846 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000847 writePoint3(fLocation, buffer);
848 }
849
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850private:
851 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700852
853 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000854};
855
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000856///////////////////////////////////////////////////////////////////////////////
857
robertphillips2f0dbc72015-08-20 05:15:06 -0700858class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000859public:
senorblancod0d37ca2015-04-02 04:54:56 -0700860 SkSpotLight(const SkPoint3& location,
861 const SkPoint3& target,
862 SkScalar specularExponent,
863 SkScalar cutoffAngle,
864 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000865 : INHERITED(color),
866 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700868 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000869 {
870 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700871 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000872 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000873 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000874 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
875 fConeScale = SkScalarInvert(antiAliasThreshold);
876 }
djsollen@google.com08337772012-06-26 14:33:13 +0000877
robertphillips2f0dbc72015-08-20 05:15:06 -0700878 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000879 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
880 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000881 // Use X scale and Y scale on Z and average the result
882 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
883 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700884 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
885 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000886 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
887 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000888 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
889 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700890 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
891 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000892 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700893 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700894 return new SkSpotLight(location,
895 target,
896 fSpecularExponent,
897 fCosOuterConeAngle,
898 fCosInnerConeAngle,
899 fConeScale,
900 s,
901 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000902 }
903
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700905 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
906 fLocation.fY - SkIntToScalar(y),
907 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
908 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700909 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910 return direction;
911 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000912 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000913 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700914 SkScalar scale = 0;
915 if (cosAngle >= fCosOuterConeAngle) {
916 scale = SkScalarPow(cosAngle, fSpecularExponent);
917 if (cosAngle < fCosInnerConeAngle) {
918 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
919 scale *= fConeScale;
920 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000921 }
robertphillips3d32d762015-07-13 13:16:44 -0700922 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 }
mtklein36352bf2015-03-25 18:17:31 -0700924 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000925#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700926 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000927#else
928 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700929 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000930#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000931 }
mtklein36352bf2015-03-25 18:17:31 -0700932 bool requiresFragmentPosition() const override { return true; }
933 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000934 const SkPoint3& location() const { return fLocation; }
935 const SkPoint3& target() const { return fTarget; }
936 SkScalar specularExponent() const { return fSpecularExponent; }
937 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
938 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
939 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000940 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000941
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000942 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000943 fLocation = readPoint3(buffer);
944 fTarget = readPoint3(buffer);
945 fSpecularExponent = buffer.readScalar();
946 fCosOuterConeAngle = buffer.readScalar();
947 fCosInnerConeAngle = buffer.readScalar();
948 fConeScale = buffer.readScalar();
949 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000950 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
951 SkScalarIsFinite(fCosOuterConeAngle) &&
952 SkScalarIsFinite(fCosInnerConeAngle) &&
953 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000954 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000955protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700956 SkSpotLight(const SkPoint3& location,
957 const SkPoint3& target,
958 SkScalar specularExponent,
959 SkScalar cosOuterConeAngle,
960 SkScalar cosInnerConeAngle,
961 SkScalar coneScale,
962 const SkPoint3& s,
963 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000964 : INHERITED(color),
965 fLocation(location),
966 fTarget(target),
967 fSpecularExponent(specularExponent),
968 fCosOuterConeAngle(cosOuterConeAngle),
969 fCosInnerConeAngle(cosInnerConeAngle),
970 fConeScale(coneScale),
971 fS(s)
972 {
973 }
mtklein36352bf2015-03-25 18:17:31 -0700974 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000975 writePoint3(fLocation, buffer);
976 writePoint3(fTarget, buffer);
977 buffer.writeScalar(fSpecularExponent);
978 buffer.writeScalar(fCosOuterConeAngle);
979 buffer.writeScalar(fCosInnerConeAngle);
980 buffer.writeScalar(fConeScale);
981 writePoint3(fS, buffer);
982 }
983
robertphillips2f0dbc72015-08-20 05:15:06 -0700984 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000985 if (other.type() != kSpot_LightType) {
986 return false;
987 }
988
989 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
990 return INHERITED::isEqual(other) &&
991 fLocation == o.fLocation &&
992 fTarget == o.fTarget &&
993 fSpecularExponent == o.fSpecularExponent &&
994 fCosOuterConeAngle == o.fCosOuterConeAngle;
995 }
996
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000997private:
caryclark0bccd872015-10-20 10:04:03 -0700998 static const SkScalar kSpecularExponentMin;
999 static const SkScalar kSpecularExponentMax;
1000
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001001 SkPoint3 fLocation;
1002 SkPoint3 fTarget;
1003 SkScalar fSpecularExponent;
1004 SkScalar fCosOuterConeAngle;
1005 SkScalar fCosInnerConeAngle;
1006 SkScalar fConeScale;
1007 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001008
1009 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001010};
1011
caryclark0bccd872015-10-20 10:04:03 -07001012// According to the spec, the specular term should be in the range [1, 128] :
1013// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1014const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1015const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1016
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001017///////////////////////////////////////////////////////////////////////////////
1018
robertphillips2f0dbc72015-08-20 05:15:06 -07001019void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001020 // Write type first, then baseclass, then subclass.
1021 buffer.writeInt(this->type());
1022 writePoint3(fColor, buffer);
1023 this->onFlattenLight(buffer);
1024}
1025
robertphillips2f0dbc72015-08-20 05:15:06 -07001026/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001027 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001028 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001029 switch (type) {
1030 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1031 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001032 case SkImageFilterLight::kDistant_LightType:
1033 return new SkDistantLight(buffer);
1034 case SkImageFilterLight::kPoint_LightType:
1035 return new SkPointLight(buffer);
1036 case SkImageFilterLight::kSpot_LightType:
1037 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001038 default:
1039 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001040 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001041 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001042 }
1043}
1044///////////////////////////////////////////////////////////////////////////////
1045
robertphillips2f0dbc72015-08-20 05:15:06 -07001046SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001047 SkImageFilter* input, const CropRect* cropRect)
1048 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001049 , fLight(SkRef(light))
1050 , fSurfaceScale(surfaceScale / 255)
1051{}
1052
1053SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1054 SkColor lightColor,
1055 SkScalar surfaceScale,
1056 SkScalar kd,
1057 SkImageFilter* input,
1058 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001059 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001060 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001061}
1062
reed9fa60da2014-08-21 07:59:51 -07001063SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1064 SkColor lightColor,
1065 SkScalar surfaceScale,
1066 SkScalar kd,
1067 SkImageFilter* input,
1068 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001069 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001070 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001071}
1072
reed9fa60da2014-08-21 07:59:51 -07001073SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1074 const SkPoint3& target,
1075 SkScalar specularExponent,
1076 SkScalar cutoffAngle,
1077 SkColor lightColor,
1078 SkScalar surfaceScale,
1079 SkScalar kd,
1080 SkImageFilter* input,
1081 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001082 SkAutoTUnref<SkImageFilterLight> light(
1083 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001084 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001085}
1086
reed9fa60da2014-08-21 07:59:51 -07001087SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1088 SkColor lightColor,
1089 SkScalar surfaceScale,
1090 SkScalar ks,
1091 SkScalar shine,
1092 SkImageFilter* input,
1093 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001094 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001095 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001096}
1097
reed9fa60da2014-08-21 07:59:51 -07001098SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1099 SkColor lightColor,
1100 SkScalar surfaceScale,
1101 SkScalar ks,
1102 SkScalar shine,
1103 SkImageFilter* input,
1104 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001105 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001106 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001107}
1108
reed9fa60da2014-08-21 07:59:51 -07001109SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1110 const SkPoint3& target,
1111 SkScalar specularExponent,
1112 SkScalar cutoffAngle,
1113 SkColor lightColor,
1114 SkScalar surfaceScale,
1115 SkScalar ks,
1116 SkScalar shine,
1117 SkImageFilter* input,
1118 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001119 SkAutoTUnref<SkImageFilterLight> light(
1120 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001121 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001122}
1123
reed9fa60da2014-08-21 07:59:51 -07001124SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001125
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001126void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001127 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001128 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001129 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001130}
1131
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001132///////////////////////////////////////////////////////////////////////////////
1133
robertphillips2f0dbc72015-08-20 05:15:06 -07001134SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1135 SkScalar surfaceScale,
1136 SkScalar kd,
1137 SkImageFilter* input,
1138 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001139 if (nullptr == light) {
1140 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001141 }
1142 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001143 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001144 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001145 // According to the spec, kd can be any non-negative number :
1146 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001147 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001148 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001149 }
halcanary385fe4d2015-08-26 13:07:48 -07001150 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001151}
1152
robertphillips2f0dbc72015-08-20 05:15:06 -07001153SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001154 SkScalar surfaceScale,
1155 SkScalar kd,
1156 SkImageFilter* input,
1157 const CropRect* cropRect)
1158 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001159 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001160{
1161}
1162
reed9fa60da2014-08-21 07:59:51 -07001163SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1164 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001165 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001166 SkScalar surfaceScale = buffer.readScalar();
1167 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001168 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001169}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001171void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001172 this->INHERITED::flatten(buffer);
1173 buffer.writeScalar(fKD);
1174}
1175
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001176bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1177 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001178 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001179 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001180 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001181 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001182 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001183 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001184 return false;
1185 }
1186
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001187 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001188 return false;
1189 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001190 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001191 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001192 return false;
1193 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001194
1195 if (bounds.width() < 2 || bounds.height() < 2) {
1196 return false;
1197 }
1198
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001199 SkAutoLockPixels alp(src);
1200 if (!src.getPixels()) {
1201 return false;
1202 }
1203
senorblanco1d3ff432015-10-20 10:17:34 -07001204 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1205 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001206 return false;
1207 }
senorblanco1d3ff432015-10-20 10:17:34 -07001208 *dst = device->accessBitmap(false);
1209 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001210
senorblanco7b7ecfc2015-08-26 14:26:40 -07001211 SkMatrix matrix(ctx.ctm());
1212 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1213 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001214
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001215 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001216 offset->fX = bounds.left();
1217 offset->fY = bounds.top();
1218 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001219 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001220 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001221 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1222 transformedLight,
1223 src,
1224 dst,
1225 surfaceScale(),
1226 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001227 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001228 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001229 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1230 transformedLight,
1231 src,
1232 dst,
1233 surfaceScale(),
1234 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001235 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001236 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001237 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1238 transformedLight,
1239 src,
1240 dst,
1241 surfaceScale(),
1242 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001243 break;
1244 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001245
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001246 return true;
1247}
1248
robertphillipsf3f5bad2014-12-19 13:49:15 -08001249#ifndef SK_IGNORE_TO_STRING
1250void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1251 str->appendf("SkDiffuseLightingImageFilter: (");
1252 str->appendf("kD: %f\n", fKD);
1253 str->append(")");
1254}
1255#endif
1256
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001257#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001258GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001259 GrTexture* texture,
1260 const SkMatrix& matrix,
1261 const SkIRect&,
1262 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001263) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001264 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001265 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1266 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001267}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001268#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001269
1270///////////////////////////////////////////////////////////////////////////////
1271
robertphillips2f0dbc72015-08-20 05:15:06 -07001272SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1273 SkScalar surfaceScale,
1274 SkScalar ks,
1275 SkScalar shininess,
1276 SkImageFilter* input,
1277 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001278 if (nullptr == light) {
1279 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001280 }
1281 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001282 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001283 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001284 // According to the spec, ks can be any non-negative number :
1285 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001286 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001287 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001288 }
halcanary385fe4d2015-08-26 13:07:48 -07001289 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001290}
1291
robertphillips2f0dbc72015-08-20 05:15:06 -07001292SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001293 SkScalar surfaceScale,
1294 SkScalar ks,
1295 SkScalar shininess,
1296 SkImageFilter* input,
1297 const CropRect* cropRect)
1298 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001299 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001300 fShininess(shininess)
1301{
1302}
1303
reed9fa60da2014-08-21 07:59:51 -07001304SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1305 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001306 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001307 SkScalar surfaceScale = buffer.readScalar();
1308 SkScalar ks = buffer.readScalar();
1309 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001310 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001311}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001312
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001313void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001314 this->INHERITED::flatten(buffer);
1315 buffer.writeScalar(fKS);
1316 buffer.writeScalar(fShininess);
1317}
1318
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001319bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1320 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001321 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001322 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001323 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001324 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001325 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001326 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001327 return false;
1328 }
1329
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001330 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001331 return false;
1332 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001333
1334 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001335 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001336 return false;
1337 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001338
1339 if (bounds.width() < 2 || bounds.height() < 2) {
1340 return false;
1341 }
1342
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001343 SkAutoLockPixels alp(src);
1344 if (!src.getPixels()) {
1345 return false;
1346 }
1347
senorblanco1d3ff432015-10-20 10:17:34 -07001348 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1349 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001350 return false;
1351 }
senorblanco1d3ff432015-10-20 10:17:34 -07001352 *dst = device->accessBitmap(false);
1353 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001354
1355 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001356 offset->fX = bounds.left();
1357 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001358 SkMatrix matrix(ctx.ctm());
1359 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1360 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001361 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001362 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001363 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001364 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1365 transformedLight,
1366 src,
1367 dst,
1368 surfaceScale(),
1369 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001370 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001371 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001372 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1373 transformedLight,
1374 src,
1375 dst,
1376 surfaceScale(),
1377 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001378 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001379 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001380 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1381 transformedLight,
1382 src,
1383 dst,
1384 surfaceScale(),
1385 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001386 break;
1387 }
1388 return true;
1389}
1390
robertphillipsf3f5bad2014-12-19 13:49:15 -08001391#ifndef SK_IGNORE_TO_STRING
1392void SkSpecularLightingImageFilter::toString(SkString* str) const {
1393 str->appendf("SkSpecularLightingImageFilter: (");
1394 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1395 str->append(")");
1396}
1397#endif
1398
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001399#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001400GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001401 GrTexture* texture,
1402 const SkMatrix& matrix,
1403 const SkIRect&,
1404 BoundaryMode boundaryMode) const {
1405 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001406 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1407 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001408}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001409#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001410
1411///////////////////////////////////////////////////////////////////////////////
1412
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001413#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001414
1415namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001416SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001417 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1418 SkScalarToFloat(random->nextSScalar1()),
1419 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001420}
1421
robertphillips2f0dbc72015-08-20 05:15:06 -07001422SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001423 int type = random->nextULessThan(3);
1424 switch (type) {
1425 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001426 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001427 }
1428 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001429 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001430 }
1431 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001432 return new SkSpotLight(random_point3(random), random_point3(random),
1433 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001434 }
1435 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001436 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001437 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001438 }
1439}
1440
senorblancod0d37ca2015-04-02 04:54:56 -07001441SkString emitNormalFunc(BoundaryMode mode,
1442 const char* pointToNormalName,
1443 const char* sobelFuncName) {
1444 SkString result;
1445 switch (mode) {
1446 case kTopLeft_BoundaryMode:
1447 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1448 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1449 "\t surfaceScale);\n",
1450 pointToNormalName, sobelFuncName, gTwoThirds,
1451 sobelFuncName, gTwoThirds);
1452 break;
1453 case kTop_BoundaryMode:
1454 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1455 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1456 "\t surfaceScale);\n",
1457 pointToNormalName, sobelFuncName, gOneThird,
1458 sobelFuncName, gOneHalf);
1459 break;
1460 case kTopRight_BoundaryMode:
1461 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1462 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1463 "\t surfaceScale);\n",
1464 pointToNormalName, sobelFuncName, gTwoThirds,
1465 sobelFuncName, gTwoThirds);
1466 break;
1467 case kLeft_BoundaryMode:
1468 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1469 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1470 "\t surfaceScale);\n",
1471 pointToNormalName, sobelFuncName, gOneHalf,
1472 sobelFuncName, gOneThird);
1473 break;
1474 case kInterior_BoundaryMode:
1475 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1476 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1477 "\t surfaceScale);\n",
1478 pointToNormalName, sobelFuncName, gOneQuarter,
1479 sobelFuncName, gOneQuarter);
1480 break;
1481 case kRight_BoundaryMode:
1482 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1483 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1484 "\t surfaceScale);\n",
1485 pointToNormalName, sobelFuncName, gOneHalf,
1486 sobelFuncName, gOneThird);
1487 break;
1488 case kBottomLeft_BoundaryMode:
1489 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1490 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1491 "\t surfaceScale);\n",
1492 pointToNormalName, sobelFuncName, gTwoThirds,
1493 sobelFuncName, gTwoThirds);
1494 break;
1495 case kBottom_BoundaryMode:
1496 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1497 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1498 "\t surfaceScale);\n",
1499 pointToNormalName, sobelFuncName, gOneThird,
1500 sobelFuncName, gOneHalf);
1501 break;
1502 case kBottomRight_BoundaryMode:
1503 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1504 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1505 "\t surfaceScale);\n",
1506 pointToNormalName, sobelFuncName, gTwoThirds,
1507 sobelFuncName, gTwoThirds);
1508 break;
1509 default:
1510 SkASSERT(false);
1511 break;
1512 }
1513 return result;
1514}
1515
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001516}
1517
egdaniel64c47282015-11-13 06:54:19 -08001518class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001519public:
robertphillipsd3b32bf2016-02-05 07:15:39 -08001520 GrGLLightingEffect() : fLight(nullptr) { }
1521 virtual ~GrGLLightingEffect() { delete fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001522
wangyix7c157a92015-07-22 15:08:53 -07001523 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001524
jvanverthcfc18862015-04-28 08:48:20 -07001525 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001526
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001527protected:
wangyixb1daa862015-08-18 11:29:31 -07001528 /**
1529 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1530 */
egdaniel018fb622015-10-28 07:26:40 -07001531 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001532
egdaniel7ea439b2015-12-03 09:20:44 -08001533 virtual void emitLightFunc(GrGLSLUniformHandler*,
1534 GrGLSLFragmentBuilder*,
1535 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001536
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001537private:
egdaniel64c47282015-11-13 06:54:19 -08001538 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001539
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001540 UniformHandle fImageIncrementUni;
1541 UniformHandle fSurfaceScaleUni;
1542 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001543};
1544
1545///////////////////////////////////////////////////////////////////////////////
1546
1547class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1548public:
egdaniel7ea439b2015-12-03 09:20:44 -08001549 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001550
1551protected:
egdaniel018fb622015-10-28 07:26:40 -07001552 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001553
1554private:
1555 typedef GrGLLightingEffect INHERITED;
1556
bsalomon@google.com032b2212012-07-16 13:36:18 +00001557 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001558};
1559
1560///////////////////////////////////////////////////////////////////////////////
1561
1562class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1563public:
egdaniel7ea439b2015-12-03 09:20:44 -08001564 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001565
1566protected:
egdaniel018fb622015-10-28 07:26:40 -07001567 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001568
1569private:
1570 typedef GrGLLightingEffect INHERITED;
1571
bsalomon@google.com032b2212012-07-16 13:36:18 +00001572 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001573 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001574};
1575
1576///////////////////////////////////////////////////////////////////////////////
1577
bsalomon4a339522015-10-06 08:40:50 -07001578GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001579 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001580 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001581 const SkMatrix& matrix,
1582 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001583 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001584 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001585 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001586 , fFilterMatrix(matrix)
1587 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001588 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001589 if (light->requiresFragmentPosition()) {
1590 this->setWillReadFragmentPosition();
1591 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001592}
1593
1594GrLightingEffect::~GrLightingEffect() {
1595 fLight->unref();
1596}
1597
bsalomon0e08fc12014-10-15 08:19:04 -07001598bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001599 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001600 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001601 fSurfaceScale == s.fSurfaceScale &&
1602 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001603}
1604
1605///////////////////////////////////////////////////////////////////////////////
1606
bsalomon4a339522015-10-06 08:40:50 -07001607GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001608 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001609 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001610 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001611 SkScalar kd,
1612 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001613 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001614 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001615}
1616
bsalomon0e08fc12014-10-15 08:19:04 -07001617bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001618 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001619 return INHERITED::onIsEqual(sBase) && this->kd() == s.kd();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001620}
1621
egdaniel57d3b032015-11-13 11:57:27 -08001622void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1623 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001624 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1625}
1626
egdaniel57d3b032015-11-13 11:57:27 -08001627GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001628 return new GrGLDiffuseLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001629}
1630
joshualittb0a8a372014-09-23 09:50:21 -07001631GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001632
bsalomonc21b09e2015-08-28 18:46:56 -07001633const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001634 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1635 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001636 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001637 SkMatrix matrix;
1638 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001639 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001640 }
joshualitt0067ff52015-07-08 14:26:19 -07001641 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001642 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001643 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001644}
1645
1646
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001647///////////////////////////////////////////////////////////////////////////////
1648
wangyix7c157a92015-07-22 15:08:53 -07001649void GrGLLightingEffect::emitCode(EmitArgs& args) {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001650 const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>();
1651 if (!fLight) {
1652 fLight = le.light()->createGLLight();
1653 }
1654
egdaniel7ea439b2015-12-03 09:20:44 -08001655 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1656 fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1657 kVec2f_GrSLType, kDefault_GrSLPrecision,
1658 "ImageIncrement");
1659 fSurfaceScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1660 kFloat_GrSLType, kDefault_GrSLPrecision,
1661 "SurfaceScale");
1662 fLight->emitLightColorUniform(uniformHandler);
egdaniel4ca2e602015-11-18 08:01:26 -08001663 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001664 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001665 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001666 static const GrGLSLShaderVar gSobelArgs[] = {
1667 GrGLSLShaderVar("a", kFloat_GrSLType),
1668 GrGLSLShaderVar("b", kFloat_GrSLType),
1669 GrGLSLShaderVar("c", kFloat_GrSLType),
1670 GrGLSLShaderVar("d", kFloat_GrSLType),
1671 GrGLSLShaderVar("e", kFloat_GrSLType),
1672 GrGLSLShaderVar("f", kFloat_GrSLType),
1673 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001674 };
1675 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001676 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001677
egdaniel4ca2e602015-11-18 08:01:26 -08001678 fragBuilder->emitFunction(kFloat_GrSLType,
1679 "sobel",
1680 SK_ARRAY_COUNT(gSobelArgs),
1681 gSobelArgs,
1682 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1683 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001684 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1685 GrGLSLShaderVar("x", kFloat_GrSLType),
1686 GrGLSLShaderVar("y", kFloat_GrSLType),
1687 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001688 };
1689 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001690 fragBuilder->emitFunction(kVec3f_GrSLType,
1691 "pointToNormal",
1692 SK_ARRAY_COUNT(gPointToNormalArgs),
1693 gPointToNormalArgs,
1694 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1695 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001696
egdaniel0d3f0612015-10-21 10:45:48 -07001697 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1698 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1699 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001700 };
robertphillipsd3b32bf2016-02-05 07:15:39 -08001701 SkString normalBody = emitNormalFunc(le.boundaryMode(),
senorblancod0d37ca2015-04-02 04:54:56 -07001702 pointToNormalName.c_str(),
1703 sobelFuncName.c_str());
1704 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001705 fragBuilder->emitFunction(kVec3f_GrSLType,
1706 "normal",
1707 SK_ARRAY_COUNT(gInteriorNormalArgs),
1708 gInteriorNormalArgs,
1709 normalBody.c_str(),
1710 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001711
egdaniel4ca2e602015-11-18 08:01:26 -08001712 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1713 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001714
egdaniel7ea439b2015-12-03 09:20:44 -08001715 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1716 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001717
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001718 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001719 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001720 for (int dx = -1; dx <= 1; dx++) {
1721 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001722 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
egdaniel4ca2e602015-11-18 08:01:26 -08001723 fragBuilder->codeAppendf("\t\tm[%d] = ", index++);
1724 fragBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
1725 fragBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001726 }
1727 }
egdaniel4ca2e602015-11-18 08:01:26 -08001728 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001729 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001730 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001731 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001732 fragBuilder->codeAppend(";\n");
1733 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1734 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001735 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001736 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001737 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001738 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001739 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001740}
1741
joshualittb0a8a372014-09-23 09:50:21 -07001742void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001743 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001744 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1745 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001746}
1747
egdaniel018fb622015-10-28 07:26:40 -07001748void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1749 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001750 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
robertphillipsd3b32bf2016-02-05 07:15:39 -08001751 if (!fLight) {
1752 fLight = lighting.light()->createGLLight();
1753 }
1754
bsalomon@google.comc7818882013-03-20 19:19:53 +00001755 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001756 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001757 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1758 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001759 SkAutoTUnref<SkImageFilterLight> transformedLight(
1760 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001761 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001762}
1763
1764///////////////////////////////////////////////////////////////////////////////
1765
1766///////////////////////////////////////////////////////////////////////////////
1767
egdaniel7ea439b2015-12-03 09:20:44 -08001768void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001769 GrGLSLFragmentBuilder* fragBuilder,
1770 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001771 const char* kd;
egdaniel7ea439b2015-12-03 09:20:44 -08001772 fKDUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001773 kFloat_GrSLType, kDefault_GrSLPrecision,
1774 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001775
egdaniel0d3f0612015-10-21 10:45:48 -07001776 static const GrGLSLShaderVar gLightArgs[] = {
1777 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1778 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1779 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001780 };
1781 SkString lightBody;
1782 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1783 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001784 fragBuilder->emitFunction(kVec4f_GrSLType,
1785 "light",
1786 SK_ARRAY_COUNT(gLightArgs),
1787 gLightArgs,
1788 lightBody.c_str(),
1789 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001790}
1791
egdaniel018fb622015-10-28 07:26:40 -07001792void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1793 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001794 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001795 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001796 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001797}
1798
1799///////////////////////////////////////////////////////////////////////////////
1800
bsalomon4a339522015-10-06 08:40:50 -07001801GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001802 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001803 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001804 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001805 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001806 SkScalar shininess,
1807 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001808 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001809 , fKS(ks)
1810 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001811 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001812}
1813
bsalomon0e08fc12014-10-15 08:19:04 -07001814bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001815 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001816 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001817 this->ks() == s.ks() &&
1818 this->shininess() == s.shininess();
1819}
1820
egdaniel57d3b032015-11-13 11:57:27 -08001821void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1822 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001823 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1824}
1825
egdaniel57d3b032015-11-13 11:57:27 -08001826GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
robertphillipsd3b32bf2016-02-05 07:15:39 -08001827 return new GrGLSpecularLightingEffect;
joshualitteb2a6762014-12-04 11:35:33 -08001828}
1829
joshualittb0a8a372014-09-23 09:50:21 -07001830GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001831
bsalomonc21b09e2015-08-28 18:46:56 -07001832const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001833 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1834 SkScalar ks = d->fRandom->nextUScalar1();
1835 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001836 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001837 SkMatrix matrix;
1838 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001839 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001840 }
joshualitt0067ff52015-07-08 14:26:19 -07001841 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001842 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001843 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001844}
1845
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001846///////////////////////////////////////////////////////////////////////////////
1847
egdaniel7ea439b2015-12-03 09:20:44 -08001848void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001849 GrGLSLFragmentBuilder* fragBuilder,
1850 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001851 const char* ks;
1852 const char* shininess;
1853
egdaniel7ea439b2015-12-03 09:20:44 -08001854 fKSUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1855 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
1856 fShininessUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1857 kFloat_GrSLType,
1858 kDefault_GrSLPrecision,
1859 "Shininess",
1860 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001861
egdaniel0d3f0612015-10-21 10:45:48 -07001862 static const GrGLSLShaderVar gLightArgs[] = {
1863 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1864 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1865 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001866 };
1867 SkString lightBody;
1868 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1869 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001870 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1871 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001872 fragBuilder->emitFunction(kVec4f_GrSLType,
1873 "light",
1874 SK_ARRAY_COUNT(gLightArgs),
1875 gLightArgs,
1876 lightBody.c_str(),
1877 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001878}
1879
egdaniel018fb622015-10-28 07:26:40 -07001880void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1881 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001882 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001883 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001884 pdman.set1f(fKSUni, spec.ks());
1885 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001886}
1887
1888///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08001889void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
1890 fColorUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1891 kVec3f_GrSLType, kDefault_GrSLPrecision,
1892 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001893}
1894
egdaniel7ea439b2015-12-03 09:20:44 -08001895void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001896 GrGLSLFragmentBuilder* fragBuilder,
1897 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08001898 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001899}
1900
egdaniel018fb622015-10-28 07:26:40 -07001901void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001902 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001903 setUniformPoint3(pdman, fColorUni,
1904 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001905}
1906
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001907///////////////////////////////////////////////////////////////////////////////
1908
egdaniel018fb622015-10-28 07:26:40 -07001909void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001910 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001911 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001912 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001913 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001914 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001915}
1916
egdaniel7ea439b2015-12-03 09:20:44 -08001917void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001918 GrGLSLFragmentBuilder* fragBuilder,
1919 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001920 const char* dir;
egdaniel7ea439b2015-12-03 09:20:44 -08001921 fDirectionUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1922 kVec3f_GrSLType, kDefault_GrSLPrecision,
1923 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08001924 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001925}
1926
1927///////////////////////////////////////////////////////////////////////////////
1928
egdaniel018fb622015-10-28 07:26:40 -07001929void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001930 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001931 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001932 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001933 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001934 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001935}
1936
egdaniel7ea439b2015-12-03 09:20:44 -08001937void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001938 GrGLSLFragmentBuilder* fragBuilder,
1939 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001940 const char* loc;
egdaniel7ea439b2015-12-03 09:20:44 -08001941 fLocationUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1942 kVec3f_GrSLType, kDefault_GrSLPrecision,
1943 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08001944 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1945 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001946}
1947
1948///////////////////////////////////////////////////////////////////////////////
1949
egdaniel018fb622015-10-28 07:26:40 -07001950void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001951 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001952 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001953 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001954 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001955 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1956 pdman.set1f(fExponentUni, spotLight->specularExponent());
1957 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1958 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1959 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1960 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001961}
1962
egdaniel7ea439b2015-12-03 09:20:44 -08001963void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001964 GrGLSLFragmentBuilder* fragBuilder,
1965 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001966 const char* location;
egdaniel7ea439b2015-12-03 09:20:44 -08001967 fLocationUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1968 kVec3f_GrSLType, kDefault_GrSLPrecision,
1969 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001970
egdaniel4ca2e602015-11-18 08:01:26 -08001971 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1972 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001973}
1974
egdaniel7ea439b2015-12-03 09:20:44 -08001975void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001976 GrGLSLFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001977 const char *surfaceToLight) {
1978
egdaniel7ea439b2015-12-03 09:20:44 -08001979 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001980
1981 const char* exponent;
1982 const char* cosInner;
1983 const char* cosOuter;
1984 const char* coneScale;
1985 const char* s;
egdaniel7ea439b2015-12-03 09:20:44 -08001986 fExponentUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1987 kFloat_GrSLType, kDefault_GrSLPrecision,
1988 "Exponent", &exponent);
1989 fCosInnerConeAngleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1990 kFloat_GrSLType, kDefault_GrSLPrecision,
1991 "CosInnerConeAngle", &cosInner);
1992 fCosOuterConeAngleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1993 kFloat_GrSLType, kDefault_GrSLPrecision,
1994 "CosOuterConeAngle", &cosOuter);
1995 fConeScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1996 kFloat_GrSLType, kDefault_GrSLPrecision,
1997 "ConeScale", &coneScale);
1998 fSUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1999 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002000
egdaniel0d3f0612015-10-21 10:45:48 -07002001 static const GrGLSLShaderVar gLightColorArgs[] = {
2002 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002003 };
2004 SkString lightColorBody;
2005 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2006 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2007 lightColorBody.appendf("\t\treturn vec3(0);\n");
2008 lightColorBody.appendf("\t}\n");
2009 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2010 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2011 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2012 color, cosOuter, coneScale);
2013 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002014 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002015 fragBuilder->emitFunction(kVec3f_GrSLType,
2016 "lightColor",
2017 SK_ARRAY_COUNT(gLightColorArgs),
2018 gLightColorArgs,
2019 lightColorBody.c_str(),
2020 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002021
egdaniel4ca2e602015-11-18 08:01:26 -08002022 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002023}
2024
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002025#endif
2026
djsollen@google.com08337772012-06-26 14:33:13 +00002027SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2028 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2029 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002030SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END