blob: 46daea1f4a3bcdceb080d98f5f2e5e1f7b70cf02 [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"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000023#include "effects/GrSingleTextureEffect.h"
egdaniel64c47282015-11-13 06:54:19 -080024#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080025#include "glsl/GrGLSLFragmentShaderBuilder.h"
26#include "glsl/GrGLSLProgramBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000028
29class GrGLDiffuseLightingEffect;
30class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000031
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000032// For brevity
egdaniel018fb622015-10-28 07:26:40 -070033typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000034#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000035
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000036namespace {
37
reed80ea19c2015-05-12 10:37:34 -070038const SkScalar gOneThird = SkIntToScalar(1) / 3;
39const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000040const SkScalar gOneHalf = 0.5f;
41const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000042
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000043#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070044void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070045 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070046 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070047 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000048}
49
egdaniel018fb622015-10-28 07:26:40 -070050void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070051 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070052 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000053}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000054#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000055
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000056// Shift matrix components to the left, as we advance pixels to the right.
57inline void shiftMatrixLeft(int m[9]) {
58 m[0] = m[1];
59 m[3] = m[4];
60 m[6] = m[7];
61 m[1] = m[2];
62 m[4] = m[5];
63 m[7] = m[8];
64}
65
jvanverth992c7612015-07-17 07:22:30 -070066static inline void fast_normalize(SkPoint3* vector) {
67 // add a tiny bit so we don't have to worry about divide-by-zero
68 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
69 SkScalar scale = sk_float_rsqrt(magSq);
70 vector->fX *= scale;
71 vector->fY *= scale;
72 vector->fZ *= scale;
73}
74
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000075class DiffuseLightingType {
76public:
77 DiffuseLightingType(SkScalar kd)
78 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070079 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
80 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000081 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
82 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070083 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000084 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000085 SkClampMax(SkScalarRoundToInt(color.fX), 255),
86 SkClampMax(SkScalarRoundToInt(color.fY), 255),
87 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000088 }
89private:
90 SkScalar fKD;
91};
92
robertphillips3d32d762015-07-13 13:16:44 -070093static SkScalar max_component(const SkPoint3& p) {
94 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
95}
96
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000097class SpecularLightingType {
98public:
99 SpecularLightingType(SkScalar ks, SkScalar shininess)
100 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700101 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
102 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000103 SkPoint3 halfDir(surfaceTolight);
104 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700105 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000106 SkScalar colorScale = SkScalarMul(fKS,
107 SkScalarPow(normal.dot(halfDir), fShininess));
108 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700109 SkPoint3 color = lightColor.makeScale(colorScale);
110 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000111 SkClampMax(SkScalarRoundToInt(color.fX), 255),
112 SkClampMax(SkScalarRoundToInt(color.fY), 255),
113 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000114 }
115private:
116 SkScalar fKS;
117 SkScalar fShininess;
118};
119
120inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
121 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
122}
123
124inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700125 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
126 SkScalarMul(-y, surfaceScale),
127 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700128 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000129 return vector;
130}
131
132inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
134 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
135 surfaceScale);
136}
137
138inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
139 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
140 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
141 surfaceScale);
142}
143
144inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
145 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
146 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
147 surfaceScale);
148}
149
150inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
151 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
152 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
153 surfaceScale);
154}
155
156
157inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
159 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
160 surfaceScale);
161}
162
163inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
165 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
166 surfaceScale);
167}
168
169inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
170 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
171 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
172 surfaceScale);
173}
174
175inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
176 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
177 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
178 surfaceScale);
179}
180
181inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
182 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
183 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
184 surfaceScale);
185}
186
robertphillips2f0dbc72015-08-20 05:15:06 -0700187template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType,
188 const SkImageFilterLight* light,
189 const SkBitmap& src,
190 SkBitmap* dst,
191 SkScalar surfaceScale,
192 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000193 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000194 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000195 int left = bounds.left(), right = bounds.right();
196 int bottom = bounds.bottom();
197 int y = bounds.top();
198 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000199 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000200 int x = left;
201 const SkPMColor* row1 = src.getAddr32(x, y);
202 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000203 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 m[4] = SkGetPackedA32(*row1++);
205 m[5] = SkGetPackedA32(*row1++);
206 m[7] = SkGetPackedA32(*row2++);
207 m[8] = SkGetPackedA32(*row2++);
208 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700209 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
210 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000211 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000212 {
213 shiftMatrixLeft(m);
214 m[5] = SkGetPackedA32(*row1++);
215 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000216 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700217 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
218 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000219 }
220 shiftMatrixLeft(m);
221 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700222 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
223 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000224 }
225
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000226 for (++y; y < bottom - 1; ++y) {
227 int x = left;
228 const SkPMColor* row0 = src.getAddr32(x, y - 1);
229 const SkPMColor* row1 = src.getAddr32(x, y);
230 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000231 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000232 m[1] = SkGetPackedA32(*row0++);
233 m[2] = SkGetPackedA32(*row0++);
234 m[4] = SkGetPackedA32(*row1++);
235 m[5] = SkGetPackedA32(*row1++);
236 m[7] = SkGetPackedA32(*row2++);
237 m[8] = SkGetPackedA32(*row2++);
238 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700239 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
240 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000241 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000242 shiftMatrixLeft(m);
243 m[2] = SkGetPackedA32(*row0++);
244 m[5] = SkGetPackedA32(*row1++);
245 m[8] = SkGetPackedA32(*row2++);
246 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700247 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
248 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000249 }
250 shiftMatrixLeft(m);
251 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700252 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
253 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000254 }
255
256 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000257 int x = left;
258 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
259 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000260 int m[9];
261 m[1] = SkGetPackedA32(*row0++);
262 m[2] = SkGetPackedA32(*row0++);
263 m[4] = SkGetPackedA32(*row1++);
264 m[5] = SkGetPackedA32(*row1++);
265 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700266 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
267 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000268 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000269 {
270 shiftMatrixLeft(m);
271 m[2] = SkGetPackedA32(*row0++);
272 m[5] = SkGetPackedA32(*row1++);
273 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700274 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
275 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000276 }
277 shiftMatrixLeft(m);
278 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700279 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
280 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000281 }
282}
283
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000284SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000285 SkPoint3 point;
286 point.fX = buffer.readScalar();
287 point.fY = buffer.readScalar();
288 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000289 buffer.validate(SkScalarIsFinite(point.fX) &&
290 SkScalarIsFinite(point.fY) &&
291 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000292 return point;
293};
294
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000295void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000296 buffer.writeScalar(point.fX);
297 buffer.writeScalar(point.fY);
298 buffer.writeScalar(point.fZ);
299};
300
senorblancod0d37ca2015-04-02 04:54:56 -0700301enum BoundaryMode {
302 kTopLeft_BoundaryMode,
303 kTop_BoundaryMode,
304 kTopRight_BoundaryMode,
305 kLeft_BoundaryMode,
306 kInterior_BoundaryMode,
307 kRight_BoundaryMode,
308 kBottomLeft_BoundaryMode,
309 kBottom_BoundaryMode,
310 kBottomRight_BoundaryMode,
311
312 kBoundaryModeCount,
313};
314
315class SkLightingImageFilterInternal : public SkLightingImageFilter {
316protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700317 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700318 SkScalar surfaceScale,
319 SkImageFilter* input,
320 const CropRect* cropRect)
321 : INHERITED(light, surfaceScale, input, cropRect) {}
322
323#if SK_SUPPORT_GPU
324 bool canFilterImageGPU() const override { return true; }
325 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
326 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700327 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700328 const SkMatrix&,
329 const SkIRect& bounds,
330 BoundaryMode boundaryMode) const = 0;
331#endif
332private:
333#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700334 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700335 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700336 const SkMatrix& matrix,
337 const GrClip& clip,
338 const SkRect& dstRect,
339 BoundaryMode boundaryMode,
340 const SkIRect& bounds) const;
341#endif
342 typedef SkLightingImageFilter INHERITED;
343};
344
345#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700346void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700347 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700348 const SkMatrix& matrix,
349 const GrClip& clip,
350 const SkRect& dstRect,
351 BoundaryMode boundaryMode,
352 const SkIRect& bounds) const {
353 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700354 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700355 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700356 paint.addColorFragmentProcessor(fp)->unref();
bsalomona2e69fc2015-11-05 10:41:43 -0800357 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700358}
359
360bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
361 const SkBitmap& src,
362 const Context& ctx,
363 SkBitmap* result,
364 SkIPoint* offset) const {
365 SkBitmap input = src;
366 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700367 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700368 return false;
369 }
370 SkIRect bounds;
371 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
372 return false;
373 }
374 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
375 SkIntToScalar(bounds.height()));
376 GrTexture* srcTexture = input.getTexture();
377 GrContext* context = srcTexture->getContext();
378
379 GrSurfaceDesc desc;
380 desc.fFlags = kRenderTarget_GrSurfaceFlag,
381 desc.fWidth = bounds.width();
382 desc.fHeight = bounds.height();
383 desc.fConfig = kRGBA_8888_GrPixelConfig;
384
senorblanco51eedb62015-10-23 09:56:48 -0700385 auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint());
386 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, constraint));
senorblancod0d37ca2015-04-02 04:54:56 -0700387 if (!dst) {
388 return false;
389 }
390
391 // setup new clip
392 GrClip clip(dstRect);
393
394 offset->fX = bounds.left();
395 offset->fY = bounds.top();
396 SkMatrix matrix(ctx.ctm());
397 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
398 bounds.offset(-srcOffset);
399 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
400 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
401 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
402 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
403 SkRect interior = dstRect.makeInset(1, 1);
404 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
405 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
406 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
407 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700408
robertphillips2e1e51f2015-10-15 08:01:48 -0700409 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700410 if (!drawContext) {
411 return false;
412 }
413
robertphillips2e1e51f2015-10-15 08:01:48 -0700414 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
415 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
416 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700417 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700418 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
419 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700420 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700421 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
422 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700423 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700424 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
425 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700426 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700427 WrapTexture(dst, bounds.width(), bounds.height(), result);
428 return true;
429}
430#endif
431
432class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000433public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700434 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
435 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700436 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700437
robertphillipsf3f5bad2014-12-19 13:49:15 -0800438 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000439 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000440 SkScalar kd() const { return fKD; }
441
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000442protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700443 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700444 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700445 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700446 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
447 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000448#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700449 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
450 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000451#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000452
453private:
reed9fa60da2014-08-21 07:59:51 -0700454 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700455 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456 SkScalar fKD;
457};
458
senorblancod0d37ca2015-04-02 04:54:56 -0700459class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000460public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700461 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700462 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700463
robertphillipsf3f5bad2014-12-19 13:49:15 -0800464 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000465 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
466
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000467 SkScalar ks() const { return fKS; }
468 SkScalar shininess() const { return fShininess; }
469
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000470protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700471 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700472 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700473 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700474 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
475 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000476#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700477 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
478 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000479#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000480
481private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000482 SkScalar fKS;
483 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700484 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700485 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000486};
487
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000488#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000489
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000490class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491public:
bsalomon4a339522015-10-06 08:40:50 -0700492 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
493 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494 virtual ~GrLightingEffect();
495
robertphillips2f0dbc72015-08-20 05:15:06 -0700496 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000497 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000498 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700499 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000500
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000501protected:
mtklein36352bf2015-03-25 18:17:31 -0700502 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000503
mtklein36352bf2015-03-25 18:17:31 -0700504 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700505 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800506 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700507 }
508
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000509private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700510 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000511 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000512 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700513 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700514
515 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000516};
517
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518class GrDiffuseLightingEffect : public GrLightingEffect {
519public:
bsalomon4a339522015-10-06 08:40:50 -0700520 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700521 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700522 SkScalar surfaceScale,
523 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700524 SkScalar kd,
525 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700526 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000527 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000528
mtklein36352bf2015-03-25 18:17:31 -0700529 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000530
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000531 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000532
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000533private:
egdaniel64c47282015-11-13 06:54:19 -0800534 GrGLSLFragmentProcessor* onCreateGLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700535
wangyix4b3050b2015-08-04 07:59:37 -0700536 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
537
mtklein36352bf2015-03-25 18:17:31 -0700538 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000539
bsalomon4a339522015-10-06 08:40:50 -0700540 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700541 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000542 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000543 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700544 SkScalar kd,
545 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000546
joshualittb0a8a372014-09-23 09:50:21 -0700547 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000548 typedef GrLightingEffect INHERITED;
549 SkScalar fKD;
550};
551
552class GrSpecularLightingEffect : public GrLightingEffect {
553public:
bsalomon4a339522015-10-06 08:40:50 -0700554 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700555 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700556 SkScalar surfaceScale,
557 const SkMatrix& matrix,
558 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700559 SkScalar shininess,
560 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700561 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
562 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000563 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000564
mtklein36352bf2015-03-25 18:17:31 -0700565 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566
egdaniel64c47282015-11-13 06:54:19 -0800567 GrGLSLFragmentProcessor* onCreateGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800568
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000569 SkScalar ks() const { return fKS; }
570 SkScalar shininess() const { return fShininess; }
571
572private:
wangyix4b3050b2015-08-04 07:59:37 -0700573 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
574
mtklein36352bf2015-03-25 18:17:31 -0700575 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000576
bsalomon4a339522015-10-06 08:40:50 -0700577 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700578 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000579 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000580 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000581 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700582 SkScalar shininess,
583 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000584
joshualittb0a8a372014-09-23 09:50:21 -0700585 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000586 typedef GrLightingEffect INHERITED;
587 SkScalar fKS;
588 SkScalar fShininess;
589};
590
591///////////////////////////////////////////////////////////////////////////////
592
593class GrGLLight {
594public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000595 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000596
597 /**
598 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
599 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
600 */
egdaniel8dcdedc2015-11-11 06:27:20 -0800601 void emitLightColorUniform(GrGLSLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000602
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000603 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000604 * These two functions are called from GrGLLightingEffect's emitCode() function.
605 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
606 * the light. The expression will be used in the FS. emitLightColor writes an expression into
607 * the FS that is the color of the light. Either function may add functions and/or uniforms to
608 * the FS. The default of emitLightColor appends the name of the constant light color uniform
609 * and so this function only needs to be overridden if the light color varies spatially.
610 */
egdaniel8dcdedc2015-11-11 06:27:20 -0800611 virtual void emitSurfaceToLight(GrGLSLFPBuilder*, const char* z) = 0;
612 virtual void emitLightColor(GrGLSLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000613
614 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
615 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700616 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000617
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000618protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000619 /**
620 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
621 * function.
622 */
623 UniformHandle lightColorUni() const { return fColorUni; }
624
625private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000626 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000627
628 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000629};
630
631///////////////////////////////////////////////////////////////////////////////
632
633class GrGLDistantLight : public GrGLLight {
634public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000635 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700636 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel8dcdedc2015-11-11 06:27:20 -0800637 void emitSurfaceToLight(GrGLSLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000638
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000639private:
640 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000641 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000642};
643
644///////////////////////////////////////////////////////////////////////////////
645
646class GrGLPointLight : public GrGLLight {
647public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000648 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700649 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel8dcdedc2015-11-11 06:27:20 -0800650 void emitSurfaceToLight(GrGLSLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000651
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000652private:
653 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000654 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000655};
656
657///////////////////////////////////////////////////////////////////////////////
658
659class GrGLSpotLight : public GrGLLight {
660public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000661 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700662 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel8dcdedc2015-11-11 06:27:20 -0800663 void emitSurfaceToLight(GrGLSLFPBuilder*, const char* z) override;
664 void emitLightColor(GrGLSLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000665
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000666private:
667 typedef GrGLLight INHERITED;
668
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000669 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000670 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000671 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000672 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000673 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000674 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000675 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000676};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000677#else
678
679class GrGLLight;
680
681#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000682
683};
684
685///////////////////////////////////////////////////////////////////////////////
686
robertphillips2f0dbc72015-08-20 05:15:06 -0700687class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000688public:
caryclark0bccd872015-10-20 10:04:03 -0700689
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000690
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691 enum LightType {
692 kDistant_LightType,
693 kPoint_LightType,
694 kSpot_LightType,
695 };
696 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000697 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000698 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700699 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000700 return fColor == other.fColor;
701 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000702 // Called to know whether the generated GrGLLight will require access to the fragment position.
703 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700704 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000705
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000706 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000707 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700708 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000709
djsollen@google.com08337772012-06-26 14:33:13 +0000710protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700711 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700712 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
713 SkIntToScalar(SkColorGetG(color)),
714 SkIntToScalar(SkColorGetB(color)));
715 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700716 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000717 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700718 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000719 fColor = readPoint3(buffer);
720 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000721
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000722 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000723
djsollen@google.com08337772012-06-26 14:33:13 +0000724
725private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000726 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000727 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000728};
729
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000730///////////////////////////////////////////////////////////////////////////////
731
robertphillips2f0dbc72015-08-20 05:15:06 -0700732class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 SkDistantLight(const SkPoint3& direction, SkColor color)
735 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000736 }
djsollen@google.com08337772012-06-26 14:33:13 +0000737
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
739 return fDirection;
740 };
robertphillips3d32d762015-07-13 13:16:44 -0700741 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700742 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000743 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700744 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000745#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700746 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000747#else
748 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700749 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000750#endif
751 }
mtklein36352bf2015-03-25 18:17:31 -0700752 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000753
robertphillips2f0dbc72015-08-20 05:15:06 -0700754 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000755 if (other.type() != kDistant_LightType) {
756 return false;
757 }
758
759 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
760 return INHERITED::isEqual(other) &&
761 fDirection == o.fDirection;
762 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000763
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000764 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000765 fDirection = readPoint3(buffer);
766 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000767
djsollen@google.com08337772012-06-26 14:33:13 +0000768protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000769 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
770 : INHERITED(color), fDirection(direction) {
771 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700772 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000773 return new SkDistantLight(direction(), color());
774 }
mtklein36352bf2015-03-25 18:17:31 -0700775 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000776 writePoint3(fDirection, buffer);
777 }
778
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779private:
780 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700781
782 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000783};
784
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000785///////////////////////////////////////////////////////////////////////////////
786
robertphillips2f0dbc72015-08-20 05:15:06 -0700787class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000788public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000789 SkPointLight(const SkPoint3& location, SkColor color)
790 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000791
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000792 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700793 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
794 fLocation.fY - SkIntToScalar(y),
795 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
796 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700797 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000798 return direction;
799 };
robertphillips3d32d762015-07-13 13:16:44 -0700800 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700801 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000802 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700803 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000804#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700805 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000806#else
807 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700808 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000809#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000810 }
mtklein36352bf2015-03-25 18:17:31 -0700811 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700812 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000813 if (other.type() != kPoint_LightType) {
814 return false;
815 }
816 const SkPointLight& o = static_cast<const SkPointLight&>(other);
817 return INHERITED::isEqual(other) &&
818 fLocation == o.fLocation;
819 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700820 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000821 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
822 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000823 // Use X scale and Y scale on Z and average the result
824 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
825 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700826 SkPoint3 location = SkPoint3::Make(location2.fX,
827 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700828 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000829 return new SkPointLight(location, color());
830 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000831
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000832 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000833 fLocation = readPoint3(buffer);
834 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000835
836protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000837 SkPointLight(const SkPoint3& location, const SkPoint3& color)
838 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700839 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000840 writePoint3(fLocation, buffer);
841 }
842
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000843private:
844 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700845
846 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000847};
848
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000849///////////////////////////////////////////////////////////////////////////////
850
robertphillips2f0dbc72015-08-20 05:15:06 -0700851class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000852public:
senorblancod0d37ca2015-04-02 04:54:56 -0700853 SkSpotLight(const SkPoint3& location,
854 const SkPoint3& target,
855 SkScalar specularExponent,
856 SkScalar cutoffAngle,
857 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000858 : INHERITED(color),
859 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000860 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700861 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000862 {
863 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700864 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000865 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000866 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
868 fConeScale = SkScalarInvert(antiAliasThreshold);
869 }
djsollen@google.com08337772012-06-26 14:33:13 +0000870
robertphillips2f0dbc72015-08-20 05:15:06 -0700871 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000872 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
873 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000874 // Use X scale and Y scale on Z and average the result
875 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
876 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700877 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
878 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000879 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
880 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000881 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
882 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700883 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
884 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000885 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700886 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700887 return new SkSpotLight(location,
888 target,
889 fSpecularExponent,
890 fCosOuterConeAngle,
891 fCosInnerConeAngle,
892 fConeScale,
893 s,
894 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000895 }
896
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000897 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700898 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
899 fLocation.fY - SkIntToScalar(y),
900 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
901 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700902 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000903 return direction;
904 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000905 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000906 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700907 SkScalar scale = 0;
908 if (cosAngle >= fCosOuterConeAngle) {
909 scale = SkScalarPow(cosAngle, fSpecularExponent);
910 if (cosAngle < fCosInnerConeAngle) {
911 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
912 scale *= fConeScale;
913 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000914 }
robertphillips3d32d762015-07-13 13:16:44 -0700915 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000916 }
mtklein36352bf2015-03-25 18:17:31 -0700917 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000918#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700919 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000920#else
921 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700922 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000923#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000924 }
mtklein36352bf2015-03-25 18:17:31 -0700925 bool requiresFragmentPosition() const override { return true; }
926 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000927 const SkPoint3& location() const { return fLocation; }
928 const SkPoint3& target() const { return fTarget; }
929 SkScalar specularExponent() const { return fSpecularExponent; }
930 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
931 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
932 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000933 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000934
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000935 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000936 fLocation = readPoint3(buffer);
937 fTarget = readPoint3(buffer);
938 fSpecularExponent = buffer.readScalar();
939 fCosOuterConeAngle = buffer.readScalar();
940 fCosInnerConeAngle = buffer.readScalar();
941 fConeScale = buffer.readScalar();
942 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000943 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
944 SkScalarIsFinite(fCosOuterConeAngle) &&
945 SkScalarIsFinite(fCosInnerConeAngle) &&
946 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000947 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000948protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700949 SkSpotLight(const SkPoint3& location,
950 const SkPoint3& target,
951 SkScalar specularExponent,
952 SkScalar cosOuterConeAngle,
953 SkScalar cosInnerConeAngle,
954 SkScalar coneScale,
955 const SkPoint3& s,
956 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000957 : INHERITED(color),
958 fLocation(location),
959 fTarget(target),
960 fSpecularExponent(specularExponent),
961 fCosOuterConeAngle(cosOuterConeAngle),
962 fCosInnerConeAngle(cosInnerConeAngle),
963 fConeScale(coneScale),
964 fS(s)
965 {
966 }
mtklein36352bf2015-03-25 18:17:31 -0700967 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000968 writePoint3(fLocation, buffer);
969 writePoint3(fTarget, buffer);
970 buffer.writeScalar(fSpecularExponent);
971 buffer.writeScalar(fCosOuterConeAngle);
972 buffer.writeScalar(fCosInnerConeAngle);
973 buffer.writeScalar(fConeScale);
974 writePoint3(fS, buffer);
975 }
976
robertphillips2f0dbc72015-08-20 05:15:06 -0700977 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000978 if (other.type() != kSpot_LightType) {
979 return false;
980 }
981
982 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
983 return INHERITED::isEqual(other) &&
984 fLocation == o.fLocation &&
985 fTarget == o.fTarget &&
986 fSpecularExponent == o.fSpecularExponent &&
987 fCosOuterConeAngle == o.fCosOuterConeAngle;
988 }
989
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000990private:
caryclark0bccd872015-10-20 10:04:03 -0700991 static const SkScalar kSpecularExponentMin;
992 static const SkScalar kSpecularExponentMax;
993
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000994 SkPoint3 fLocation;
995 SkPoint3 fTarget;
996 SkScalar fSpecularExponent;
997 SkScalar fCosOuterConeAngle;
998 SkScalar fCosInnerConeAngle;
999 SkScalar fConeScale;
1000 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001001
1002 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001003};
1004
caryclark0bccd872015-10-20 10:04:03 -07001005// According to the spec, the specular term should be in the range [1, 128] :
1006// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1007const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1008const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1009
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001010///////////////////////////////////////////////////////////////////////////////
1011
robertphillips2f0dbc72015-08-20 05:15:06 -07001012void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001013 // Write type first, then baseclass, then subclass.
1014 buffer.writeInt(this->type());
1015 writePoint3(fColor, buffer);
1016 this->onFlattenLight(buffer);
1017}
1018
robertphillips2f0dbc72015-08-20 05:15:06 -07001019/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001020 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001021 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001022 switch (type) {
1023 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1024 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001025 case SkImageFilterLight::kDistant_LightType:
1026 return new SkDistantLight(buffer);
1027 case SkImageFilterLight::kPoint_LightType:
1028 return new SkPointLight(buffer);
1029 case SkImageFilterLight::kSpot_LightType:
1030 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001031 default:
1032 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001033 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001034 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001035 }
1036}
1037///////////////////////////////////////////////////////////////////////////////
1038
robertphillips2f0dbc72015-08-20 05:15:06 -07001039SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001040 SkImageFilter* input, const CropRect* cropRect)
1041 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001042 , fLight(SkRef(light))
1043 , fSurfaceScale(surfaceScale / 255)
1044{}
1045
1046SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1047 SkColor lightColor,
1048 SkScalar surfaceScale,
1049 SkScalar kd,
1050 SkImageFilter* input,
1051 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001052 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001053 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001054}
1055
reed9fa60da2014-08-21 07:59:51 -07001056SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1057 SkColor lightColor,
1058 SkScalar surfaceScale,
1059 SkScalar kd,
1060 SkImageFilter* input,
1061 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001062 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001063 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001064}
1065
reed9fa60da2014-08-21 07:59:51 -07001066SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1067 const SkPoint3& target,
1068 SkScalar specularExponent,
1069 SkScalar cutoffAngle,
1070 SkColor lightColor,
1071 SkScalar surfaceScale,
1072 SkScalar kd,
1073 SkImageFilter* input,
1074 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001075 SkAutoTUnref<SkImageFilterLight> light(
1076 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001077 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001078}
1079
reed9fa60da2014-08-21 07:59:51 -07001080SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1081 SkColor lightColor,
1082 SkScalar surfaceScale,
1083 SkScalar ks,
1084 SkScalar shine,
1085 SkImageFilter* input,
1086 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001087 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001088 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001089}
1090
reed9fa60da2014-08-21 07:59:51 -07001091SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1092 SkColor lightColor,
1093 SkScalar surfaceScale,
1094 SkScalar ks,
1095 SkScalar shine,
1096 SkImageFilter* input,
1097 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001098 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001099 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001100}
1101
reed9fa60da2014-08-21 07:59:51 -07001102SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1103 const SkPoint3& target,
1104 SkScalar specularExponent,
1105 SkScalar cutoffAngle,
1106 SkColor lightColor,
1107 SkScalar surfaceScale,
1108 SkScalar ks,
1109 SkScalar shine,
1110 SkImageFilter* input,
1111 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001112 SkAutoTUnref<SkImageFilterLight> light(
1113 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001114 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001115}
1116
reed9fa60da2014-08-21 07:59:51 -07001117SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001118
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001119void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001120 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001121 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001122 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001123}
1124
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001125///////////////////////////////////////////////////////////////////////////////
1126
robertphillips2f0dbc72015-08-20 05:15:06 -07001127SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1128 SkScalar surfaceScale,
1129 SkScalar kd,
1130 SkImageFilter* input,
1131 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001132 if (nullptr == light) {
1133 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001134 }
1135 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001136 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001137 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001138 // According to the spec, kd can be any non-negative number :
1139 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001140 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001141 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001142 }
halcanary385fe4d2015-08-26 13:07:48 -07001143 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001144}
1145
robertphillips2f0dbc72015-08-20 05:15:06 -07001146SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001147 SkScalar surfaceScale,
1148 SkScalar kd,
1149 SkImageFilter* input,
1150 const CropRect* cropRect)
1151 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001152 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001153{
1154}
1155
reed9fa60da2014-08-21 07:59:51 -07001156SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1157 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001158 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001159 SkScalar surfaceScale = buffer.readScalar();
1160 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001161 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001162}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001163
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001164void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001165 this->INHERITED::flatten(buffer);
1166 buffer.writeScalar(fKD);
1167}
1168
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001169bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1170 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001171 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001172 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001173 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001174 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001175 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001176 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001177 return false;
1178 }
1179
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001180 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001181 return false;
1182 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001183 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001184 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001185 return false;
1186 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001187
1188 if (bounds.width() < 2 || bounds.height() < 2) {
1189 return false;
1190 }
1191
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001192 SkAutoLockPixels alp(src);
1193 if (!src.getPixels()) {
1194 return false;
1195 }
1196
senorblanco1d3ff432015-10-20 10:17:34 -07001197 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1198 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001199 return false;
1200 }
senorblanco1d3ff432015-10-20 10:17:34 -07001201 *dst = device->accessBitmap(false);
1202 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001203
senorblanco7b7ecfc2015-08-26 14:26:40 -07001204 SkMatrix matrix(ctx.ctm());
1205 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1206 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001207
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001208 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001209 offset->fX = bounds.left();
1210 offset->fY = bounds.top();
1211 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001212 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001213 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001214 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1215 transformedLight,
1216 src,
1217 dst,
1218 surfaceScale(),
1219 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001220 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001221 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001222 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1223 transformedLight,
1224 src,
1225 dst,
1226 surfaceScale(),
1227 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001228 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001229 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001230 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1231 transformedLight,
1232 src,
1233 dst,
1234 surfaceScale(),
1235 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001236 break;
1237 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001238
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001239 return true;
1240}
1241
robertphillipsf3f5bad2014-12-19 13:49:15 -08001242#ifndef SK_IGNORE_TO_STRING
1243void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1244 str->appendf("SkDiffuseLightingImageFilter: (");
1245 str->appendf("kD: %f\n", fKD);
1246 str->append(")");
1247}
1248#endif
1249
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001250#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001251GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001252 GrTexture* texture,
1253 const SkMatrix& matrix,
1254 const SkIRect&,
1255 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001256) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001257 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001258 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1259 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001260}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001261#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001262
1263///////////////////////////////////////////////////////////////////////////////
1264
robertphillips2f0dbc72015-08-20 05:15:06 -07001265SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1266 SkScalar surfaceScale,
1267 SkScalar ks,
1268 SkScalar shininess,
1269 SkImageFilter* input,
1270 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001271 if (nullptr == light) {
1272 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001273 }
1274 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001275 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001276 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001277 // According to the spec, ks can be any non-negative number :
1278 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001279 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001280 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001281 }
halcanary385fe4d2015-08-26 13:07:48 -07001282 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001283}
1284
robertphillips2f0dbc72015-08-20 05:15:06 -07001285SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001286 SkScalar surfaceScale,
1287 SkScalar ks,
1288 SkScalar shininess,
1289 SkImageFilter* input,
1290 const CropRect* cropRect)
1291 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001292 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001293 fShininess(shininess)
1294{
1295}
1296
reed9fa60da2014-08-21 07:59:51 -07001297SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1298 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001299 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001300 SkScalar surfaceScale = buffer.readScalar();
1301 SkScalar ks = buffer.readScalar();
1302 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001303 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001304}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001305
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001306void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001307 this->INHERITED::flatten(buffer);
1308 buffer.writeScalar(fKS);
1309 buffer.writeScalar(fShininess);
1310}
1311
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001312bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1313 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001314 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001315 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001316 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001317 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001318 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001319 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001320 return false;
1321 }
1322
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001323 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001324 return false;
1325 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001326
1327 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001328 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001329 return false;
1330 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001331
1332 if (bounds.width() < 2 || bounds.height() < 2) {
1333 return false;
1334 }
1335
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001336 SkAutoLockPixels alp(src);
1337 if (!src.getPixels()) {
1338 return false;
1339 }
1340
senorblanco1d3ff432015-10-20 10:17:34 -07001341 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1342 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001343 return false;
1344 }
senorblanco1d3ff432015-10-20 10:17:34 -07001345 *dst = device->accessBitmap(false);
1346 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001347
1348 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001349 offset->fX = bounds.left();
1350 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001351 SkMatrix matrix(ctx.ctm());
1352 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1353 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001354 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001355 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001356 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001357 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1358 transformedLight,
1359 src,
1360 dst,
1361 surfaceScale(),
1362 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001363 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001364 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001365 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1366 transformedLight,
1367 src,
1368 dst,
1369 surfaceScale(),
1370 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001371 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001372 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001373 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1374 transformedLight,
1375 src,
1376 dst,
1377 surfaceScale(),
1378 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001379 break;
1380 }
1381 return true;
1382}
1383
robertphillipsf3f5bad2014-12-19 13:49:15 -08001384#ifndef SK_IGNORE_TO_STRING
1385void SkSpecularLightingImageFilter::toString(SkString* str) const {
1386 str->appendf("SkSpecularLightingImageFilter: (");
1387 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1388 str->append(")");
1389}
1390#endif
1391
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001392#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001393GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001394 GrTexture* texture,
1395 const SkMatrix& matrix,
1396 const SkIRect&,
1397 BoundaryMode boundaryMode) const {
1398 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001399 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1400 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001401}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001402#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001403
1404///////////////////////////////////////////////////////////////////////////////
1405
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001406#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001407
1408namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001409SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001410 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1411 SkScalarToFloat(random->nextSScalar1()),
1412 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001413}
1414
robertphillips2f0dbc72015-08-20 05:15:06 -07001415SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001416 int type = random->nextULessThan(3);
1417 switch (type) {
1418 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001419 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001420 }
1421 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001422 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001423 }
1424 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001425 return new SkSpotLight(random_point3(random), random_point3(random),
1426 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001427 }
1428 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001429 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001430 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001431 }
1432}
1433
senorblancod0d37ca2015-04-02 04:54:56 -07001434SkString emitNormalFunc(BoundaryMode mode,
1435 const char* pointToNormalName,
1436 const char* sobelFuncName) {
1437 SkString result;
1438 switch (mode) {
1439 case kTopLeft_BoundaryMode:
1440 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1441 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1442 "\t surfaceScale);\n",
1443 pointToNormalName, sobelFuncName, gTwoThirds,
1444 sobelFuncName, gTwoThirds);
1445 break;
1446 case kTop_BoundaryMode:
1447 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], 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, gOneThird,
1451 sobelFuncName, gOneHalf);
1452 break;
1453 case kTopRight_BoundaryMode:
1454 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1455 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1456 "\t surfaceScale);\n",
1457 pointToNormalName, sobelFuncName, gTwoThirds,
1458 sobelFuncName, gTwoThirds);
1459 break;
1460 case kLeft_BoundaryMode:
1461 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1462 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1463 "\t surfaceScale);\n",
1464 pointToNormalName, sobelFuncName, gOneHalf,
1465 sobelFuncName, gOneThird);
1466 break;
1467 case kInterior_BoundaryMode:
1468 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1469 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1470 "\t surfaceScale);\n",
1471 pointToNormalName, sobelFuncName, gOneQuarter,
1472 sobelFuncName, gOneQuarter);
1473 break;
1474 case kRight_BoundaryMode:
1475 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1476 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1477 "\t surfaceScale);\n",
1478 pointToNormalName, sobelFuncName, gOneHalf,
1479 sobelFuncName, gOneThird);
1480 break;
1481 case kBottomLeft_BoundaryMode:
1482 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1483 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1484 "\t surfaceScale);\n",
1485 pointToNormalName, sobelFuncName, gTwoThirds,
1486 sobelFuncName, gTwoThirds);
1487 break;
1488 case kBottom_BoundaryMode:
1489 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1490 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1491 "\t surfaceScale);\n",
1492 pointToNormalName, sobelFuncName, gOneThird,
1493 sobelFuncName, gOneHalf);
1494 break;
1495 case kBottomRight_BoundaryMode:
1496 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1497 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1498 "\t surfaceScale);\n",
1499 pointToNormalName, sobelFuncName, gTwoThirds,
1500 sobelFuncName, gTwoThirds);
1501 break;
1502 default:
1503 SkASSERT(false);
1504 break;
1505 }
1506 return result;
1507}
1508
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001509}
1510
egdaniel64c47282015-11-13 06:54:19 -08001511class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001512public:
joshualitteb2a6762014-12-04 11:35:33 -08001513 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001514 virtual ~GrGLLightingEffect();
1515
wangyix7c157a92015-07-22 15:08:53 -07001516 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001517
jvanverthcfc18862015-04-28 08:48:20 -07001518 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001519
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001520protected:
wangyixb1daa862015-08-18 11:29:31 -07001521 /**
1522 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1523 */
egdaniel018fb622015-10-28 07:26:40 -07001524 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001525
egdaniel8dcdedc2015-11-11 06:27:20 -08001526 virtual void emitLightFunc(GrGLSLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001527
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001528private:
egdaniel64c47282015-11-13 06:54:19 -08001529 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001530
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001531 UniformHandle fImageIncrementUni;
1532 UniformHandle fSurfaceScaleUni;
1533 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001534 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001535};
1536
1537///////////////////////////////////////////////////////////////////////////////
1538
1539class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1540public:
joshualitteb2a6762014-12-04 11:35:33 -08001541 GrGLDiffuseLightingEffect(const GrProcessor&);
egdaniel8dcdedc2015-11-11 06:27:20 -08001542 void emitLightFunc(GrGLSLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001543
1544protected:
egdaniel018fb622015-10-28 07:26:40 -07001545 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001546
1547private:
1548 typedef GrGLLightingEffect INHERITED;
1549
bsalomon@google.com032b2212012-07-16 13:36:18 +00001550 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001551};
1552
1553///////////////////////////////////////////////////////////////////////////////
1554
1555class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1556public:
joshualitteb2a6762014-12-04 11:35:33 -08001557 GrGLSpecularLightingEffect(const GrProcessor&);
egdaniel8dcdedc2015-11-11 06:27:20 -08001558 void emitLightFunc(GrGLSLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001559
1560protected:
egdaniel018fb622015-10-28 07:26:40 -07001561 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001562
1563private:
1564 typedef GrGLLightingEffect INHERITED;
1565
bsalomon@google.com032b2212012-07-16 13:36:18 +00001566 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001567 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001568};
1569
1570///////////////////////////////////////////////////////////////////////////////
1571
bsalomon4a339522015-10-06 08:40:50 -07001572GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001573 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001574 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001575 const SkMatrix& matrix,
1576 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001577 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001578 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001579 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001580 , fFilterMatrix(matrix)
1581 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001582 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001583 if (light->requiresFragmentPosition()) {
1584 this->setWillReadFragmentPosition();
1585 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001586}
1587
1588GrLightingEffect::~GrLightingEffect() {
1589 fLight->unref();
1590}
1591
bsalomon0e08fc12014-10-15 08:19:04 -07001592bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001593 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001594 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001595 fSurfaceScale == s.fSurfaceScale &&
1596 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001597}
1598
1599///////////////////////////////////////////////////////////////////////////////
1600
bsalomon4a339522015-10-06 08:40:50 -07001601GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001602 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001603 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001604 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001605 SkScalar kd,
1606 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001607 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001608 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001609}
1610
bsalomon0e08fc12014-10-15 08:19:04 -07001611bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001612 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001613 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001614 this->kd() == s.kd();
1615}
1616
wangyix4b3050b2015-08-04 07:59:37 -07001617void GrDiffuseLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel2d721d32015-11-11 13:06:05 -08001618 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001619 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1620}
1621
egdaniel64c47282015-11-13 06:54:19 -08001622GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001623 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001624}
1625
joshualittb0a8a372014-09-23 09:50:21 -07001626GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001627
bsalomonc21b09e2015-08-28 18:46:56 -07001628const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001629 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1630 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001631 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001632 SkMatrix matrix;
1633 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001634 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001635 }
joshualitt0067ff52015-07-08 14:26:19 -07001636 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001637 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001638 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001639}
1640
1641
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001642///////////////////////////////////////////////////////////////////////////////
1643
joshualitteb2a6762014-12-04 11:35:33 -08001644GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001645 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001646 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001647 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001648}
1649
1650GrGLLightingEffect::~GrGLLightingEffect() {
1651 delete fLight;
1652}
1653
wangyix7c157a92015-07-22 15:08:53 -07001654void GrGLLightingEffect::emitCode(EmitArgs& args) {
egdaniel2d721d32015-11-11 13:06:05 -08001655 fImageIncrementUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001656 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001657 "ImageIncrement");
egdaniel2d721d32015-11-11 13:06:05 -08001658 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001659 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001660 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001661 fLight->emitLightColorUniform(args.fBuilder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001662 SkString lightFunc;
wangyix7c157a92015-07-22 15:08:53 -07001663 this->emitLightFunc(args.fBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001664 static const GrGLSLShaderVar gSobelArgs[] = {
1665 GrGLSLShaderVar("a", kFloat_GrSLType),
1666 GrGLSLShaderVar("b", kFloat_GrSLType),
1667 GrGLSLShaderVar("c", kFloat_GrSLType),
1668 GrGLSLShaderVar("d", kFloat_GrSLType),
1669 GrGLSLShaderVar("e", kFloat_GrSLType),
1670 GrGLSLShaderVar("f", kFloat_GrSLType),
1671 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001672 };
1673 SkString sobelFuncName;
egdaniel2d721d32015-11-11 13:06:05 -08001674 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
wangyix7c157a92015-07-22 15:08:53 -07001675 SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001676
1677 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001678 "sobel",
1679 SK_ARRAY_COUNT(gSobelArgs),
1680 gSobelArgs,
1681 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1682 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001683 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1684 GrGLSLShaderVar("x", kFloat_GrSLType),
1685 GrGLSLShaderVar("y", kFloat_GrSLType),
1686 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001687 };
1688 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001689 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001690 "pointToNormal",
1691 SK_ARRAY_COUNT(gPointToNormalArgs),
1692 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001693 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001694 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001695
egdaniel0d3f0612015-10-21 10:45:48 -07001696 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1697 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1698 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001699 };
senorblancod0d37ca2015-04-02 04:54:56 -07001700 SkString normalBody = emitNormalFunc(fBoundaryMode,
1701 pointToNormalName.c_str(),
1702 sobelFuncName.c_str());
1703 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001704 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001705 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001706 SK_ARRAY_COUNT(gInteriorNormalArgs),
1707 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001708 normalBody.c_str(),
1709 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001710
joshualitt30ba4362014-08-21 20:18:45 -07001711 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1712 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001713
wangyix7c157a92015-07-22 15:08:53 -07001714 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1715 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001716
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001717 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001718 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001719 for (int dx = -1; dx <= 1; dx++) {
1720 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001721 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001722 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
wangyix7c157a92015-07-22 15:08:53 -07001723 fsBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001724 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001725 }
1726 }
joshualitt30ba4362014-08-21 20:18:45 -07001727 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001728 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001729 arg.appendf("%s * m[4]", surfScale);
wangyix7c157a92015-07-22 15:08:53 -07001730 fLight->emitSurfaceToLight(args.fBuilder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001731 fsBuilder->codeAppend(";\n");
1732 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
wangyix7c157a92015-07-22 15:08:53 -07001733 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1734 fLight->emitLightColor(args.fBuilder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001735 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001736 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001737 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001738 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001739}
1740
joshualittb0a8a372014-09-23 09:50:21 -07001741void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001742 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001743 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1744 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001745}
1746
egdaniel018fb622015-10-28 07:26:40 -07001747void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1748 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001749 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001750 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001751 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001752 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1753 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001754 SkAutoTUnref<SkImageFilterLight> transformedLight(
1755 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001756 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001757}
1758
1759///////////////////////////////////////////////////////////////////////////////
1760
1761///////////////////////////////////////////////////////////////////////////////
1762
joshualitteb2a6762014-12-04 11:35:33 -08001763GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1764 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001765}
1766
egdaniel8dcdedc2015-11-11 06:27:20 -08001767void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001768 const char* kd;
egdaniel2d721d32015-11-11 13:06:05 -08001769 fKDUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001770 kFloat_GrSLType, kDefault_GrSLPrecision,
1771 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001772
egdaniel0d3f0612015-10-21 10:45:48 -07001773 static const GrGLSLShaderVar gLightArgs[] = {
1774 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1775 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1776 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001777 };
1778 SkString lightBody;
1779 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1780 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001781 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1782 "light",
1783 SK_ARRAY_COUNT(gLightArgs),
1784 gLightArgs,
1785 lightBody.c_str(),
1786 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001787}
1788
egdaniel018fb622015-10-28 07:26:40 -07001789void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1790 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001791 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001792 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001793 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001794}
1795
1796///////////////////////////////////////////////////////////////////////////////
1797
bsalomon4a339522015-10-06 08:40:50 -07001798GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001799 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001800 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001801 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001802 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001803 SkScalar shininess,
1804 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001805 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001806 , fKS(ks)
1807 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001808 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001809}
1810
bsalomon0e08fc12014-10-15 08:19:04 -07001811bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001812 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001813 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001814 this->ks() == s.ks() &&
1815 this->shininess() == s.shininess();
1816}
1817
wangyix4b3050b2015-08-04 07:59:37 -07001818void GrSpecularLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel2d721d32015-11-11 13:06:05 -08001819 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001820 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1821}
1822
egdaniel64c47282015-11-13 06:54:19 -08001823GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001824 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001825}
1826
joshualittb0a8a372014-09-23 09:50:21 -07001827GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001828
bsalomonc21b09e2015-08-28 18:46:56 -07001829const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001830 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1831 SkScalar ks = d->fRandom->nextUScalar1();
1832 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001833 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001834 SkMatrix matrix;
1835 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001836 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001837 }
joshualitt0067ff52015-07-08 14:26:19 -07001838 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001839 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001840 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001841}
1842
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001843///////////////////////////////////////////////////////////////////////////////
1844
joshualitteb2a6762014-12-04 11:35:33 -08001845GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1846 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001847}
1848
egdaniel8dcdedc2015-11-11 06:27:20 -08001849void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001850 const char* ks;
1851 const char* shininess;
1852
egdaniel2d721d32015-11-11 13:06:05 -08001853 fKSUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001854 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
egdaniel2d721d32015-11-11 13:06:05 -08001855 fShininessUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001856 kFloat_GrSLType,
1857 kDefault_GrSLPrecision,
1858 "Shininess",
1859 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001860
egdaniel0d3f0612015-10-21 10:45:48 -07001861 static const GrGLSLShaderVar gLightArgs[] = {
1862 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1863 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1864 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001865 };
1866 SkString lightBody;
1867 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1868 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001869 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1870 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001871 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1872 "light",
1873 SK_ARRAY_COUNT(gLightArgs),
1874 gLightArgs,
1875 lightBody.c_str(),
1876 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001877}
1878
egdaniel018fb622015-10-28 07:26:40 -07001879void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1880 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001881 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001882 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001883 pdman.set1f(fKSUni, spec.ks());
1884 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001885}
1886
1887///////////////////////////////////////////////////////////////////////////////
egdaniel8dcdedc2015-11-11 06:27:20 -08001888void GrGLLight::emitLightColorUniform(GrGLSLFPBuilder* builder) {
egdaniel2d721d32015-11-11 13:06:05 -08001889 fColorUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001890 kVec3f_GrSLType, kDefault_GrSLPrecision,
1891 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001892}
1893
egdaniel8dcdedc2015-11-11 06:27:20 -08001894void GrGLLight::emitLightColor(GrGLSLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001895 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001896}
1897
egdaniel018fb622015-10-28 07:26:40 -07001898void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001899 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001900 setUniformPoint3(pdman, fColorUni,
1901 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001902}
1903
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001904///////////////////////////////////////////////////////////////////////////////
1905
egdaniel018fb622015-10-28 07:26:40 -07001906void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001907 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001908 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001909 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001910 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001911 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001912}
1913
egdaniel8dcdedc2015-11-11 06:27:20 -08001914void GrGLDistantLight::emitSurfaceToLight(GrGLSLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001915 const char* dir;
egdaniel2d721d32015-11-11 13:06:05 -08001916 fDirectionUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001917 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001918 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001919 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001920}
1921
1922///////////////////////////////////////////////////////////////////////////////
1923
egdaniel018fb622015-10-28 07:26:40 -07001924void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001925 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001926 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001927 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001928 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001929 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001930}
1931
egdaniel8dcdedc2015-11-11 06:27:20 -08001932void GrGLPointLight::emitSurfaceToLight(GrGLSLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001933 const char* loc;
egdaniel2d721d32015-11-11 13:06:05 -08001934 fLocationUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001935 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001936 "LightLocation", &loc);
egdaniel2d721d32015-11-11 13:06:05 -08001937 GrGLSLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001938 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1939 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001940}
1941
1942///////////////////////////////////////////////////////////////////////////////
1943
egdaniel018fb622015-10-28 07:26:40 -07001944void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001945 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001946 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001947 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001948 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001949 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1950 pdman.set1f(fExponentUni, spotLight->specularExponent());
1951 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1952 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1953 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1954 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001955}
1956
egdaniel8dcdedc2015-11-11 06:27:20 -08001957void GrGLSpotLight::emitSurfaceToLight(GrGLSLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001958 const char* location;
egdaniel2d721d32015-11-11 13:06:05 -08001959 fLocationUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001960 kVec3f_GrSLType, kDefault_GrSLPrecision,
1961 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001962
egdaniel2d721d32015-11-11 13:06:05 -08001963 GrGLSLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001964 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1965 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001966}
1967
egdaniel8dcdedc2015-11-11 06:27:20 -08001968void GrGLSpotLight::emitLightColor(GrGLSLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001969 const char *surfaceToLight) {
1970
1971 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1972
1973 const char* exponent;
1974 const char* cosInner;
1975 const char* cosOuter;
1976 const char* coneScale;
1977 const char* s;
egdaniel2d721d32015-11-11 13:06:05 -08001978 fExponentUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001979 kFloat_GrSLType, kDefault_GrSLPrecision,
1980 "Exponent", &exponent);
egdaniel2d721d32015-11-11 13:06:05 -08001981 fCosInnerConeAngleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001982 kFloat_GrSLType, kDefault_GrSLPrecision,
1983 "CosInnerConeAngle", &cosInner);
egdaniel2d721d32015-11-11 13:06:05 -08001984 fCosOuterConeAngleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001985 kFloat_GrSLType, kDefault_GrSLPrecision,
1986 "CosOuterConeAngle", &cosOuter);
egdaniel2d721d32015-11-11 13:06:05 -08001987 fConeScaleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001988 kFloat_GrSLType, kDefault_GrSLPrecision,
1989 "ConeScale", &coneScale);
egdaniel2d721d32015-11-11 13:06:05 -08001990 fSUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001991 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001992
egdaniel0d3f0612015-10-21 10:45:48 -07001993 static const GrGLSLShaderVar gLightColorArgs[] = {
1994 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001995 };
1996 SkString lightColorBody;
1997 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1998 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1999 lightColorBody.appendf("\t\treturn vec3(0);\n");
2000 lightColorBody.appendf("\t}\n");
2001 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2002 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2003 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2004 color, cosOuter, coneScale);
2005 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002006 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel2d721d32015-11-11 13:06:05 -08002007 GrGLSLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002008 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002009 "lightColor",
2010 SK_ARRAY_COUNT(gLightColorArgs),
2011 gLightColorArgs,
2012 lightColorBody.c_str(),
2013 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002014
joshualitt30ba4362014-08-21 20:18:45 -07002015 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002016}
2017
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002018#endif
2019
djsollen@google.com08337772012-06-26 14:33:13 +00002020SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2021 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2022 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002023SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END