blob: 9b6a20f0efb05061ca547dfde5df1c0b919e89f4 [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();
egdanielc4b72722015-11-23 13:20:41 -0800357 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800358 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700359}
360
361bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
362 const SkBitmap& src,
363 const Context& ctx,
364 SkBitmap* result,
365 SkIPoint* offset) const {
366 SkBitmap input = src;
367 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700368 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700369 return false;
370 }
371 SkIRect bounds;
372 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
373 return false;
374 }
375 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
376 SkIntToScalar(bounds.height()));
377 GrTexture* srcTexture = input.getTexture();
378 GrContext* context = srcTexture->getContext();
379
380 GrSurfaceDesc desc;
381 desc.fFlags = kRenderTarget_GrSurfaceFlag,
382 desc.fWidth = bounds.width();
383 desc.fHeight = bounds.height();
384 desc.fConfig = kRGBA_8888_GrPixelConfig;
385
senorblanco51eedb62015-10-23 09:56:48 -0700386 auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint());
387 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, constraint));
senorblancod0d37ca2015-04-02 04:54:56 -0700388 if (!dst) {
389 return false;
390 }
391
392 // setup new clip
393 GrClip clip(dstRect);
394
395 offset->fX = bounds.left();
396 offset->fY = bounds.top();
397 SkMatrix matrix(ctx.ctm());
398 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
399 bounds.offset(-srcOffset);
400 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
401 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
402 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
403 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
404 SkRect interior = dstRect.makeInset(1, 1);
405 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
406 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
407 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
408 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700409
robertphillips2e1e51f2015-10-15 08:01:48 -0700410 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700411 if (!drawContext) {
412 return false;
413 }
414
robertphillips2e1e51f2015-10-15 08:01:48 -0700415 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
416 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
417 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700418 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700419 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
420 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700421 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700422 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
423 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700424 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700425 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
426 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700427 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700428 WrapTexture(dst, bounds.width(), bounds.height(), result);
429 return true;
430}
431#endif
432
433class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000434public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700435 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
436 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700437 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700438
robertphillipsf3f5bad2014-12-19 13:49:15 -0800439 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000440 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000441 SkScalar kd() const { return fKD; }
442
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000443protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700444 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700445 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700446 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700447 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
448 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000449#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700450 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
451 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000452#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000453
454private:
reed9fa60da2014-08-21 07:59:51 -0700455 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700456 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000457 SkScalar fKD;
458};
459
senorblancod0d37ca2015-04-02 04:54:56 -0700460class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700462 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700463 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700464
robertphillipsf3f5bad2014-12-19 13:49:15 -0800465 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000466 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
467
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000468 SkScalar ks() const { return fKS; }
469 SkScalar shininess() const { return fShininess; }
470
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700472 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700473 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700474 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700475 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
476 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000477#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700478 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
479 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000480#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481
482private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483 SkScalar fKS;
484 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700485 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700486 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000487};
488
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000489#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000491class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492public:
bsalomon4a339522015-10-06 08:40:50 -0700493 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
494 const SkMatrix& matrix, BoundaryMode boundaryMode);
robertphillipse004bfc2015-11-16 09:06:59 -0800495 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496
robertphillips2f0dbc72015-08-20 05:15:06 -0700497 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000498 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000499 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700500 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000501
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000502protected:
mtklein36352bf2015-03-25 18:17:31 -0700503 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000504
mtklein36352bf2015-03-25 18:17:31 -0700505 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700506 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800507 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700508 }
509
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700511 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000512 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000513 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700514 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700515
516 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000517};
518
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000519class GrDiffuseLightingEffect : public GrLightingEffect {
520public:
bsalomon4a339522015-10-06 08:40:50 -0700521 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700522 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700523 SkScalar surfaceScale,
524 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700525 SkScalar kd,
526 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700527 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000528 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529
mtklein36352bf2015-03-25 18:17:31 -0700530 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000531
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000532 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534private:
egdaniel57d3b032015-11-13 11:57:27 -0800535 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700536
egdaniel57d3b032015-11-13 11:57:27 -0800537 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700538
mtklein36352bf2015-03-25 18:17:31 -0700539 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000540
bsalomon4a339522015-10-06 08:40:50 -0700541 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700542 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000543 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000544 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700545 SkScalar kd,
546 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000547
joshualittb0a8a372014-09-23 09:50:21 -0700548 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000549 typedef GrLightingEffect INHERITED;
550 SkScalar fKD;
551};
552
553class GrSpecularLightingEffect : public GrLightingEffect {
554public:
bsalomon4a339522015-10-06 08:40:50 -0700555 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700556 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700557 SkScalar surfaceScale,
558 const SkMatrix& matrix,
559 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700560 SkScalar shininess,
561 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700562 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
563 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000564 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565
mtklein36352bf2015-03-25 18:17:31 -0700566 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567
egdaniel57d3b032015-11-13 11:57:27 -0800568 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800569
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000570 SkScalar ks() const { return fKS; }
571 SkScalar shininess() const { return fShininess; }
572
573private:
egdaniel57d3b032015-11-13 11:57:27 -0800574 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700575
mtklein36352bf2015-03-25 18:17:31 -0700576 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000577
bsalomon4a339522015-10-06 08:40:50 -0700578 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700579 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000580 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000581 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000582 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700583 SkScalar shininess,
584 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000585
joshualittb0a8a372014-09-23 09:50:21 -0700586 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000587 typedef GrLightingEffect INHERITED;
588 SkScalar fKS;
589 SkScalar fShininess;
590};
591
592///////////////////////////////////////////////////////////////////////////////
593
594class GrGLLight {
595public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000596 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000597
598 /**
599 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
600 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
601 */
egdaniel8dcdedc2015-11-11 06:27:20 -0800602 void emitLightColorUniform(GrGLSLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000603
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000604 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000605 * These two functions are called from GrGLLightingEffect's emitCode() function.
606 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
607 * the light. The expression will be used in the FS. emitLightColor writes an expression into
608 * the FS that is the color of the light. Either function may add functions and/or uniforms to
609 * the FS. The default of emitLightColor appends the name of the constant light color uniform
610 * and so this function only needs to be overridden if the light color varies spatially.
611 */
egdaniel4ca2e602015-11-18 08:01:26 -0800612 virtual void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) = 0;
613 virtual void emitLightColor(GrGLSLFPBuilder*,
614 GrGLSLFragmentBuilder*,
615 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000616
617 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
618 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700619 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000620
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000621protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000622 /**
623 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
624 * function.
625 */
626 UniformHandle lightColorUni() const { return fColorUni; }
627
628private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000629 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000630
631 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632};
633
634///////////////////////////////////////////////////////////////////////////////
635
636class GrGLDistantLight : public GrGLLight {
637public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000638 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700639 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel4ca2e602015-11-18 08:01:26 -0800640 void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000641
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000642private:
643 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000644 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000645};
646
647///////////////////////////////////////////////////////////////////////////////
648
649class GrGLPointLight : public GrGLLight {
650public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000651 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700652 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel4ca2e602015-11-18 08:01:26 -0800653 void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000654
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000655private:
656 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000657 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000658};
659
660///////////////////////////////////////////////////////////////////////////////
661
662class GrGLSpotLight : public GrGLLight {
663public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000664 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700665 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel4ca2e602015-11-18 08:01:26 -0800666 void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) override;
667 void emitLightColor(GrGLSLFPBuilder*,
668 GrGLSLFragmentBuilder*,
669 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000670
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000671private:
672 typedef GrGLLight INHERITED;
673
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000674 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000675 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000676 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000677 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000678 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000679 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000680 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000681};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000682#else
683
684class GrGLLight;
685
686#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000687
688};
689
690///////////////////////////////////////////////////////////////////////////////
691
robertphillips2f0dbc72015-08-20 05:15:06 -0700692class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000693public:
caryclark0bccd872015-10-20 10:04:03 -0700694
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000695
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696 enum LightType {
697 kDistant_LightType,
698 kPoint_LightType,
699 kSpot_LightType,
700 };
701 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000702 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000703 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700704 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000705 return fColor == other.fColor;
706 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000707 // Called to know whether the generated GrGLLight will require access to the fragment position.
708 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700709 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000710
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000711 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000712 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700713 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000714
djsollen@google.com08337772012-06-26 14:33:13 +0000715protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700716 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700717 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
718 SkIntToScalar(SkColorGetG(color)),
719 SkIntToScalar(SkColorGetB(color)));
720 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700721 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000722 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700723 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000724 fColor = readPoint3(buffer);
725 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000726
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000727 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000728
djsollen@google.com08337772012-06-26 14:33:13 +0000729
730private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000731 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000732 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733};
734
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000735///////////////////////////////////////////////////////////////////////////////
736
robertphillips2f0dbc72015-08-20 05:15:06 -0700737class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000738public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000739 SkDistantLight(const SkPoint3& direction, SkColor color)
740 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000741 }
djsollen@google.com08337772012-06-26 14:33:13 +0000742
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
744 return fDirection;
745 };
robertphillips3d32d762015-07-13 13:16:44 -0700746 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700747 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000748 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700749 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000750#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700751 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000752#else
753 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700754 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000755#endif
756 }
mtklein36352bf2015-03-25 18:17:31 -0700757 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000758
robertphillips2f0dbc72015-08-20 05:15:06 -0700759 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000760 if (other.type() != kDistant_LightType) {
761 return false;
762 }
763
764 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
765 return INHERITED::isEqual(other) &&
766 fDirection == o.fDirection;
767 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000768
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000769 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000770 fDirection = readPoint3(buffer);
771 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000772
djsollen@google.com08337772012-06-26 14:33:13 +0000773protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000774 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
775 : INHERITED(color), fDirection(direction) {
776 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700777 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000778 return new SkDistantLight(direction(), color());
779 }
mtklein36352bf2015-03-25 18:17:31 -0700780 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000781 writePoint3(fDirection, buffer);
782 }
783
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784private:
785 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700786
787 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000788};
789
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000790///////////////////////////////////////////////////////////////////////////////
791
robertphillips2f0dbc72015-08-20 05:15:06 -0700792class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000793public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000794 SkPointLight(const SkPoint3& location, SkColor color)
795 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000796
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000797 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700798 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
799 fLocation.fY - SkIntToScalar(y),
800 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
801 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700802 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000803 return direction;
804 };
robertphillips3d32d762015-07-13 13:16:44 -0700805 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700806 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000807 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700808 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000809#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700810 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000811#else
812 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700813 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000814#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000815 }
mtklein36352bf2015-03-25 18:17:31 -0700816 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700817 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000818 if (other.type() != kPoint_LightType) {
819 return false;
820 }
821 const SkPointLight& o = static_cast<const SkPointLight&>(other);
822 return INHERITED::isEqual(other) &&
823 fLocation == o.fLocation;
824 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700825 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000826 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
827 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000828 // Use X scale and Y scale on Z and average the result
829 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
830 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700831 SkPoint3 location = SkPoint3::Make(location2.fX,
832 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700833 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000834 return new SkPointLight(location, color());
835 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000836
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000837 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000838 fLocation = readPoint3(buffer);
839 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000840
841protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000842 SkPointLight(const SkPoint3& location, const SkPoint3& color)
843 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700844 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000845 writePoint3(fLocation, buffer);
846 }
847
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848private:
849 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700850
851 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000852};
853
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000854///////////////////////////////////////////////////////////////////////////////
855
robertphillips2f0dbc72015-08-20 05:15:06 -0700856class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000857public:
senorblancod0d37ca2015-04-02 04:54:56 -0700858 SkSpotLight(const SkPoint3& location,
859 const SkPoint3& target,
860 SkScalar specularExponent,
861 SkScalar cutoffAngle,
862 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000863 : INHERITED(color),
864 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000865 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700866 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867 {
868 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700869 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000870 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000871 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000872 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
873 fConeScale = SkScalarInvert(antiAliasThreshold);
874 }
djsollen@google.com08337772012-06-26 14:33:13 +0000875
robertphillips2f0dbc72015-08-20 05:15:06 -0700876 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000877 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
878 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000879 // Use X scale and Y scale on Z and average the result
880 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
881 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700882 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
883 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000884 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
885 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000886 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
887 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700888 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
889 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000890 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700891 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700892 return new SkSpotLight(location,
893 target,
894 fSpecularExponent,
895 fCosOuterConeAngle,
896 fCosInnerConeAngle,
897 fConeScale,
898 s,
899 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000900 }
901
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700903 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
904 fLocation.fY - SkIntToScalar(y),
905 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
906 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700907 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000908 return direction;
909 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000910 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700912 SkScalar scale = 0;
913 if (cosAngle >= fCosOuterConeAngle) {
914 scale = SkScalarPow(cosAngle, fSpecularExponent);
915 if (cosAngle < fCosInnerConeAngle) {
916 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
917 scale *= fConeScale;
918 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000919 }
robertphillips3d32d762015-07-13 13:16:44 -0700920 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000921 }
mtklein36352bf2015-03-25 18:17:31 -0700922 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000923#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700924 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000925#else
926 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700927 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000928#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000929 }
mtklein36352bf2015-03-25 18:17:31 -0700930 bool requiresFragmentPosition() const override { return true; }
931 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000932 const SkPoint3& location() const { return fLocation; }
933 const SkPoint3& target() const { return fTarget; }
934 SkScalar specularExponent() const { return fSpecularExponent; }
935 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
936 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
937 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000938 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000939
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000940 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000941 fLocation = readPoint3(buffer);
942 fTarget = readPoint3(buffer);
943 fSpecularExponent = buffer.readScalar();
944 fCosOuterConeAngle = buffer.readScalar();
945 fCosInnerConeAngle = buffer.readScalar();
946 fConeScale = buffer.readScalar();
947 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000948 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
949 SkScalarIsFinite(fCosOuterConeAngle) &&
950 SkScalarIsFinite(fCosInnerConeAngle) &&
951 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000952 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000953protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700954 SkSpotLight(const SkPoint3& location,
955 const SkPoint3& target,
956 SkScalar specularExponent,
957 SkScalar cosOuterConeAngle,
958 SkScalar cosInnerConeAngle,
959 SkScalar coneScale,
960 const SkPoint3& s,
961 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000962 : INHERITED(color),
963 fLocation(location),
964 fTarget(target),
965 fSpecularExponent(specularExponent),
966 fCosOuterConeAngle(cosOuterConeAngle),
967 fCosInnerConeAngle(cosInnerConeAngle),
968 fConeScale(coneScale),
969 fS(s)
970 {
971 }
mtklein36352bf2015-03-25 18:17:31 -0700972 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000973 writePoint3(fLocation, buffer);
974 writePoint3(fTarget, buffer);
975 buffer.writeScalar(fSpecularExponent);
976 buffer.writeScalar(fCosOuterConeAngle);
977 buffer.writeScalar(fCosInnerConeAngle);
978 buffer.writeScalar(fConeScale);
979 writePoint3(fS, buffer);
980 }
981
robertphillips2f0dbc72015-08-20 05:15:06 -0700982 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000983 if (other.type() != kSpot_LightType) {
984 return false;
985 }
986
987 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
988 return INHERITED::isEqual(other) &&
989 fLocation == o.fLocation &&
990 fTarget == o.fTarget &&
991 fSpecularExponent == o.fSpecularExponent &&
992 fCosOuterConeAngle == o.fCosOuterConeAngle;
993 }
994
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000995private:
caryclark0bccd872015-10-20 10:04:03 -0700996 static const SkScalar kSpecularExponentMin;
997 static const SkScalar kSpecularExponentMax;
998
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000999 SkPoint3 fLocation;
1000 SkPoint3 fTarget;
1001 SkScalar fSpecularExponent;
1002 SkScalar fCosOuterConeAngle;
1003 SkScalar fCosInnerConeAngle;
1004 SkScalar fConeScale;
1005 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001006
1007 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001008};
1009
caryclark0bccd872015-10-20 10:04:03 -07001010// According to the spec, the specular term should be in the range [1, 128] :
1011// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1012const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1013const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1014
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001015///////////////////////////////////////////////////////////////////////////////
1016
robertphillips2f0dbc72015-08-20 05:15:06 -07001017void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001018 // Write type first, then baseclass, then subclass.
1019 buffer.writeInt(this->type());
1020 writePoint3(fColor, buffer);
1021 this->onFlattenLight(buffer);
1022}
1023
robertphillips2f0dbc72015-08-20 05:15:06 -07001024/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001025 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001026 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001027 switch (type) {
1028 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1029 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001030 case SkImageFilterLight::kDistant_LightType:
1031 return new SkDistantLight(buffer);
1032 case SkImageFilterLight::kPoint_LightType:
1033 return new SkPointLight(buffer);
1034 case SkImageFilterLight::kSpot_LightType:
1035 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001036 default:
1037 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001038 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001039 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001040 }
1041}
1042///////////////////////////////////////////////////////////////////////////////
1043
robertphillips2f0dbc72015-08-20 05:15:06 -07001044SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001045 SkImageFilter* input, const CropRect* cropRect)
1046 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001047 , fLight(SkRef(light))
1048 , fSurfaceScale(surfaceScale / 255)
1049{}
1050
1051SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1052 SkColor lightColor,
1053 SkScalar surfaceScale,
1054 SkScalar kd,
1055 SkImageFilter* input,
1056 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001057 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001058 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001059}
1060
reed9fa60da2014-08-21 07:59:51 -07001061SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1062 SkColor lightColor,
1063 SkScalar surfaceScale,
1064 SkScalar kd,
1065 SkImageFilter* input,
1066 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001067 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001068 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001069}
1070
reed9fa60da2014-08-21 07:59:51 -07001071SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1072 const SkPoint3& target,
1073 SkScalar specularExponent,
1074 SkScalar cutoffAngle,
1075 SkColor lightColor,
1076 SkScalar surfaceScale,
1077 SkScalar kd,
1078 SkImageFilter* input,
1079 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001080 SkAutoTUnref<SkImageFilterLight> light(
1081 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001082 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001083}
1084
reed9fa60da2014-08-21 07:59:51 -07001085SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1086 SkColor lightColor,
1087 SkScalar surfaceScale,
1088 SkScalar ks,
1089 SkScalar shine,
1090 SkImageFilter* input,
1091 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001092 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001093 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001094}
1095
reed9fa60da2014-08-21 07:59:51 -07001096SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1097 SkColor lightColor,
1098 SkScalar surfaceScale,
1099 SkScalar ks,
1100 SkScalar shine,
1101 SkImageFilter* input,
1102 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001103 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001104 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001105}
1106
reed9fa60da2014-08-21 07:59:51 -07001107SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1108 const SkPoint3& target,
1109 SkScalar specularExponent,
1110 SkScalar cutoffAngle,
1111 SkColor lightColor,
1112 SkScalar surfaceScale,
1113 SkScalar ks,
1114 SkScalar shine,
1115 SkImageFilter* input,
1116 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001117 SkAutoTUnref<SkImageFilterLight> light(
1118 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001119 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001120}
1121
reed9fa60da2014-08-21 07:59:51 -07001122SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001123
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001124void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001125 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001126 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001127 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001128}
1129
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001130///////////////////////////////////////////////////////////////////////////////
1131
robertphillips2f0dbc72015-08-20 05:15:06 -07001132SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1133 SkScalar surfaceScale,
1134 SkScalar kd,
1135 SkImageFilter* input,
1136 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001137 if (nullptr == light) {
1138 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001139 }
1140 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001141 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001142 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001143 // According to the spec, kd can be any non-negative number :
1144 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001145 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001146 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001147 }
halcanary385fe4d2015-08-26 13:07:48 -07001148 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001149}
1150
robertphillips2f0dbc72015-08-20 05:15:06 -07001151SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001152 SkScalar surfaceScale,
1153 SkScalar kd,
1154 SkImageFilter* input,
1155 const CropRect* cropRect)
1156 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001157 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001158{
1159}
1160
reed9fa60da2014-08-21 07:59:51 -07001161SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1162 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001163 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001164 SkScalar surfaceScale = buffer.readScalar();
1165 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001166 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001167}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001168
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001169void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170 this->INHERITED::flatten(buffer);
1171 buffer.writeScalar(fKD);
1172}
1173
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001174bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1175 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001176 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001177 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001178 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001179 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001180 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001181 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001182 return false;
1183 }
1184
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001185 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001186 return false;
1187 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001188 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001189 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001190 return false;
1191 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001192
1193 if (bounds.width() < 2 || bounds.height() < 2) {
1194 return false;
1195 }
1196
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001197 SkAutoLockPixels alp(src);
1198 if (!src.getPixels()) {
1199 return false;
1200 }
1201
senorblanco1d3ff432015-10-20 10:17:34 -07001202 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1203 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001204 return false;
1205 }
senorblanco1d3ff432015-10-20 10:17:34 -07001206 *dst = device->accessBitmap(false);
1207 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001208
senorblanco7b7ecfc2015-08-26 14:26:40 -07001209 SkMatrix matrix(ctx.ctm());
1210 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1211 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001212
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001213 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001214 offset->fX = bounds.left();
1215 offset->fY = bounds.top();
1216 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001217 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001218 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001219 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1220 transformedLight,
1221 src,
1222 dst,
1223 surfaceScale(),
1224 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001225 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001226 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001227 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1228 transformedLight,
1229 src,
1230 dst,
1231 surfaceScale(),
1232 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001233 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001234 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001235 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1236 transformedLight,
1237 src,
1238 dst,
1239 surfaceScale(),
1240 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001241 break;
1242 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001243
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001244 return true;
1245}
1246
robertphillipsf3f5bad2014-12-19 13:49:15 -08001247#ifndef SK_IGNORE_TO_STRING
1248void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1249 str->appendf("SkDiffuseLightingImageFilter: (");
1250 str->appendf("kD: %f\n", fKD);
1251 str->append(")");
1252}
1253#endif
1254
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001255#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001256GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001257 GrTexture* texture,
1258 const SkMatrix& matrix,
1259 const SkIRect&,
1260 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001261) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001262 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001263 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1264 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001265}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001266#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001267
1268///////////////////////////////////////////////////////////////////////////////
1269
robertphillips2f0dbc72015-08-20 05:15:06 -07001270SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1271 SkScalar surfaceScale,
1272 SkScalar ks,
1273 SkScalar shininess,
1274 SkImageFilter* input,
1275 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001276 if (nullptr == light) {
1277 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001278 }
1279 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001280 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001281 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001282 // According to the spec, ks can be any non-negative number :
1283 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001284 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001285 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001286 }
halcanary385fe4d2015-08-26 13:07:48 -07001287 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001288}
1289
robertphillips2f0dbc72015-08-20 05:15:06 -07001290SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001291 SkScalar surfaceScale,
1292 SkScalar ks,
1293 SkScalar shininess,
1294 SkImageFilter* input,
1295 const CropRect* cropRect)
1296 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001297 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001298 fShininess(shininess)
1299{
1300}
1301
reed9fa60da2014-08-21 07:59:51 -07001302SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1303 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001304 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001305 SkScalar surfaceScale = buffer.readScalar();
1306 SkScalar ks = buffer.readScalar();
1307 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001308 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001309}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001310
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001311void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001312 this->INHERITED::flatten(buffer);
1313 buffer.writeScalar(fKS);
1314 buffer.writeScalar(fShininess);
1315}
1316
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001317bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1318 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001319 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001320 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001321 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001322 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001323 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001324 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001325 return false;
1326 }
1327
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001328 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001329 return false;
1330 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001331
1332 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001333 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001334 return false;
1335 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001336
1337 if (bounds.width() < 2 || bounds.height() < 2) {
1338 return false;
1339 }
1340
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001341 SkAutoLockPixels alp(src);
1342 if (!src.getPixels()) {
1343 return false;
1344 }
1345
senorblanco1d3ff432015-10-20 10:17:34 -07001346 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1347 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001348 return false;
1349 }
senorblanco1d3ff432015-10-20 10:17:34 -07001350 *dst = device->accessBitmap(false);
1351 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001352
1353 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001354 offset->fX = bounds.left();
1355 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001356 SkMatrix matrix(ctx.ctm());
1357 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1358 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001359 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001360 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001361 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001362 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1363 transformedLight,
1364 src,
1365 dst,
1366 surfaceScale(),
1367 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001368 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001369 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001370 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1371 transformedLight,
1372 src,
1373 dst,
1374 surfaceScale(),
1375 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001376 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001377 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001378 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1379 transformedLight,
1380 src,
1381 dst,
1382 surfaceScale(),
1383 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001384 break;
1385 }
1386 return true;
1387}
1388
robertphillipsf3f5bad2014-12-19 13:49:15 -08001389#ifndef SK_IGNORE_TO_STRING
1390void SkSpecularLightingImageFilter::toString(SkString* str) const {
1391 str->appendf("SkSpecularLightingImageFilter: (");
1392 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1393 str->append(")");
1394}
1395#endif
1396
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001397#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001398GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001399 GrTexture* texture,
1400 const SkMatrix& matrix,
1401 const SkIRect&,
1402 BoundaryMode boundaryMode) const {
1403 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001404 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1405 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001406}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001407#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001408
1409///////////////////////////////////////////////////////////////////////////////
1410
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001411#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001412
1413namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001414SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001415 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1416 SkScalarToFloat(random->nextSScalar1()),
1417 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001418}
1419
robertphillips2f0dbc72015-08-20 05:15:06 -07001420SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001421 int type = random->nextULessThan(3);
1422 switch (type) {
1423 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001424 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001425 }
1426 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001427 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001428 }
1429 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001430 return new SkSpotLight(random_point3(random), random_point3(random),
1431 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001432 }
1433 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001434 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001435 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001436 }
1437}
1438
senorblancod0d37ca2015-04-02 04:54:56 -07001439SkString emitNormalFunc(BoundaryMode mode,
1440 const char* pointToNormalName,
1441 const char* sobelFuncName) {
1442 SkString result;
1443 switch (mode) {
1444 case kTopLeft_BoundaryMode:
1445 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1446 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1447 "\t surfaceScale);\n",
1448 pointToNormalName, sobelFuncName, gTwoThirds,
1449 sobelFuncName, gTwoThirds);
1450 break;
1451 case kTop_BoundaryMode:
1452 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1453 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1454 "\t surfaceScale);\n",
1455 pointToNormalName, sobelFuncName, gOneThird,
1456 sobelFuncName, gOneHalf);
1457 break;
1458 case kTopRight_BoundaryMode:
1459 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1460 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1461 "\t surfaceScale);\n",
1462 pointToNormalName, sobelFuncName, gTwoThirds,
1463 sobelFuncName, gTwoThirds);
1464 break;
1465 case kLeft_BoundaryMode:
1466 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1467 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1468 "\t surfaceScale);\n",
1469 pointToNormalName, sobelFuncName, gOneHalf,
1470 sobelFuncName, gOneThird);
1471 break;
1472 case kInterior_BoundaryMode:
1473 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1474 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1475 "\t surfaceScale);\n",
1476 pointToNormalName, sobelFuncName, gOneQuarter,
1477 sobelFuncName, gOneQuarter);
1478 break;
1479 case kRight_BoundaryMode:
1480 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1481 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1482 "\t surfaceScale);\n",
1483 pointToNormalName, sobelFuncName, gOneHalf,
1484 sobelFuncName, gOneThird);
1485 break;
1486 case kBottomLeft_BoundaryMode:
1487 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1488 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1489 "\t surfaceScale);\n",
1490 pointToNormalName, sobelFuncName, gTwoThirds,
1491 sobelFuncName, gTwoThirds);
1492 break;
1493 case kBottom_BoundaryMode:
1494 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1495 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1496 "\t surfaceScale);\n",
1497 pointToNormalName, sobelFuncName, gOneThird,
1498 sobelFuncName, gOneHalf);
1499 break;
1500 case kBottomRight_BoundaryMode:
1501 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1502 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1503 "\t surfaceScale);\n",
1504 pointToNormalName, sobelFuncName, gTwoThirds,
1505 sobelFuncName, gTwoThirds);
1506 break;
1507 default:
1508 SkASSERT(false);
1509 break;
1510 }
1511 return result;
1512}
1513
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001514}
1515
egdaniel64c47282015-11-13 06:54:19 -08001516class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001517public:
joshualitteb2a6762014-12-04 11:35:33 -08001518 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001519 virtual ~GrGLLightingEffect();
1520
wangyix7c157a92015-07-22 15:08:53 -07001521 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001522
jvanverthcfc18862015-04-28 08:48:20 -07001523 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001524
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001525protected:
wangyixb1daa862015-08-18 11:29:31 -07001526 /**
1527 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1528 */
egdaniel018fb622015-10-28 07:26:40 -07001529 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001530
egdaniel4ca2e602015-11-18 08:01:26 -08001531 virtual void emitLightFunc(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001532
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001533private:
egdaniel64c47282015-11-13 06:54:19 -08001534 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001535
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001536 UniformHandle fImageIncrementUni;
1537 UniformHandle fSurfaceScaleUni;
1538 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001539 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001540};
1541
1542///////////////////////////////////////////////////////////////////////////////
1543
1544class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1545public:
joshualitteb2a6762014-12-04 11:35:33 -08001546 GrGLDiffuseLightingEffect(const GrProcessor&);
egdaniel4ca2e602015-11-18 08:01:26 -08001547 void emitLightFunc(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001548
1549protected:
egdaniel018fb622015-10-28 07:26:40 -07001550 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001551
1552private:
1553 typedef GrGLLightingEffect INHERITED;
1554
bsalomon@google.com032b2212012-07-16 13:36:18 +00001555 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001556};
1557
1558///////////////////////////////////////////////////////////////////////////////
1559
1560class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1561public:
joshualitteb2a6762014-12-04 11:35:33 -08001562 GrGLSpecularLightingEffect(const GrProcessor&);
egdaniel4ca2e602015-11-18 08:01:26 -08001563 void emitLightFunc(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001564
1565protected:
egdaniel018fb622015-10-28 07:26:40 -07001566 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001567
1568private:
1569 typedef GrGLLightingEffect INHERITED;
1570
bsalomon@google.com032b2212012-07-16 13:36:18 +00001571 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001572 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001573};
1574
1575///////////////////////////////////////////////////////////////////////////////
1576
bsalomon4a339522015-10-06 08:40:50 -07001577GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001578 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001579 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001580 const SkMatrix& matrix,
1581 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001582 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001583 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001584 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001585 , fFilterMatrix(matrix)
1586 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001587 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001588 if (light->requiresFragmentPosition()) {
1589 this->setWillReadFragmentPosition();
1590 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001591}
1592
1593GrLightingEffect::~GrLightingEffect() {
1594 fLight->unref();
1595}
1596
bsalomon0e08fc12014-10-15 08:19:04 -07001597bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001598 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001599 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001600 fSurfaceScale == s.fSurfaceScale &&
1601 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001602}
1603
1604///////////////////////////////////////////////////////////////////////////////
1605
bsalomon4a339522015-10-06 08:40:50 -07001606GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001607 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001608 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001609 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001610 SkScalar kd,
1611 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001612 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001613 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001614}
1615
bsalomon0e08fc12014-10-15 08:19:04 -07001616bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001617 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001618 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001619 this->kd() == s.kd();
1620}
1621
egdaniel57d3b032015-11-13 11:57:27 -08001622void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1623 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001624 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1625}
1626
egdaniel57d3b032015-11-13 11:57:27 -08001627GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001628 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001629}
1630
joshualittb0a8a372014-09-23 09:50:21 -07001631GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001632
bsalomonc21b09e2015-08-28 18:46:56 -07001633const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001634 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1635 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001636 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001637 SkMatrix matrix;
1638 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001639 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001640 }
joshualitt0067ff52015-07-08 14:26:19 -07001641 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001642 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001643 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001644}
1645
1646
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001647///////////////////////////////////////////////////////////////////////////////
1648
joshualitteb2a6762014-12-04 11:35:33 -08001649GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001650 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001651 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001652 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001653}
1654
1655GrGLLightingEffect::~GrGLLightingEffect() {
1656 delete fLight;
1657}
1658
wangyix7c157a92015-07-22 15:08:53 -07001659void GrGLLightingEffect::emitCode(EmitArgs& args) {
egdaniel2d721d32015-11-11 13:06:05 -08001660 fImageIncrementUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001661 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001662 "ImageIncrement");
egdaniel2d721d32015-11-11 13:06:05 -08001663 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001664 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001665 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001666 fLight->emitLightColorUniform(args.fBuilder);
egdaniel4ca2e602015-11-18 08:01:26 -08001667 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001668 SkString lightFunc;
egdaniel4ca2e602015-11-18 08:01:26 -08001669 this->emitLightFunc(args.fBuilder, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001670 static const GrGLSLShaderVar gSobelArgs[] = {
1671 GrGLSLShaderVar("a", kFloat_GrSLType),
1672 GrGLSLShaderVar("b", kFloat_GrSLType),
1673 GrGLSLShaderVar("c", kFloat_GrSLType),
1674 GrGLSLShaderVar("d", kFloat_GrSLType),
1675 GrGLSLShaderVar("e", kFloat_GrSLType),
1676 GrGLSLShaderVar("f", kFloat_GrSLType),
1677 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001678 };
1679 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001680 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001681
egdaniel4ca2e602015-11-18 08:01:26 -08001682 fragBuilder->emitFunction(kFloat_GrSLType,
1683 "sobel",
1684 SK_ARRAY_COUNT(gSobelArgs),
1685 gSobelArgs,
1686 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1687 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001688 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1689 GrGLSLShaderVar("x", kFloat_GrSLType),
1690 GrGLSLShaderVar("y", kFloat_GrSLType),
1691 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001692 };
1693 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001694 fragBuilder->emitFunction(kVec3f_GrSLType,
1695 "pointToNormal",
1696 SK_ARRAY_COUNT(gPointToNormalArgs),
1697 gPointToNormalArgs,
1698 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1699 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001700
egdaniel0d3f0612015-10-21 10:45:48 -07001701 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1702 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1703 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001704 };
senorblancod0d37ca2015-04-02 04:54:56 -07001705 SkString normalBody = emitNormalFunc(fBoundaryMode,
1706 pointToNormalName.c_str(),
1707 sobelFuncName.c_str());
1708 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001709 fragBuilder->emitFunction(kVec3f_GrSLType,
1710 "normal",
1711 SK_ARRAY_COUNT(gInteriorNormalArgs),
1712 gInteriorNormalArgs,
1713 normalBody.c_str(),
1714 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001715
egdaniel4ca2e602015-11-18 08:01:26 -08001716 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1717 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001718
wangyix7c157a92015-07-22 15:08:53 -07001719 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1720 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001721
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001722 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001723 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001724 for (int dx = -1; dx <= 1; dx++) {
1725 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001726 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
egdaniel4ca2e602015-11-18 08:01:26 -08001727 fragBuilder->codeAppendf("\t\tm[%d] = ", index++);
1728 fragBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
1729 fragBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001730 }
1731 }
egdaniel4ca2e602015-11-18 08:01:26 -08001732 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001733 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001734 arg.appendf("%s * m[4]", surfScale);
egdaniel4ca2e602015-11-18 08:01:26 -08001735 fLight->emitSurfaceToLight(args.fBuilder, fragBuilder, arg.c_str());
1736 fragBuilder->codeAppend(";\n");
1737 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1738 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1739 fLight->emitLightColor(args.fBuilder, fragBuilder, "surfaceToLight");
1740 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001741 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001742 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001743 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001744}
1745
joshualittb0a8a372014-09-23 09:50:21 -07001746void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001747 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001748 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1749 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001750}
1751
egdaniel018fb622015-10-28 07:26:40 -07001752void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1753 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001754 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001755 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001756 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001757 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1758 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001759 SkAutoTUnref<SkImageFilterLight> transformedLight(
1760 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001761 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001762}
1763
1764///////////////////////////////////////////////////////////////////////////////
1765
1766///////////////////////////////////////////////////////////////////////////////
1767
joshualitteb2a6762014-12-04 11:35:33 -08001768GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1769 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001770}
1771
egdaniel4ca2e602015-11-18 08:01:26 -08001772void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLFPBuilder* builder,
1773 GrGLSLFragmentBuilder* fragBuilder,
1774 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001775 const char* kd;
egdaniel2d721d32015-11-11 13:06:05 -08001776 fKDUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001777 kFloat_GrSLType, kDefault_GrSLPrecision,
1778 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001779
egdaniel0d3f0612015-10-21 10:45:48 -07001780 static const GrGLSLShaderVar gLightArgs[] = {
1781 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1782 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1783 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001784 };
1785 SkString lightBody;
1786 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1787 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001788 fragBuilder->emitFunction(kVec4f_GrSLType,
1789 "light",
1790 SK_ARRAY_COUNT(gLightArgs),
1791 gLightArgs,
1792 lightBody.c_str(),
1793 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001794}
1795
egdaniel018fb622015-10-28 07:26:40 -07001796void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1797 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001798 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001799 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001800 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001801}
1802
1803///////////////////////////////////////////////////////////////////////////////
1804
bsalomon4a339522015-10-06 08:40:50 -07001805GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001806 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001807 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001808 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001809 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001810 SkScalar shininess,
1811 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001812 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001813 , fKS(ks)
1814 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001815 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001816}
1817
bsalomon0e08fc12014-10-15 08:19:04 -07001818bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001819 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001820 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001821 this->ks() == s.ks() &&
1822 this->shininess() == s.shininess();
1823}
1824
egdaniel57d3b032015-11-13 11:57:27 -08001825void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1826 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001827 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1828}
1829
egdaniel57d3b032015-11-13 11:57:27 -08001830GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001831 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001832}
1833
joshualittb0a8a372014-09-23 09:50:21 -07001834GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001835
bsalomonc21b09e2015-08-28 18:46:56 -07001836const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001837 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1838 SkScalar ks = d->fRandom->nextUScalar1();
1839 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001840 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001841 SkMatrix matrix;
1842 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001843 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001844 }
joshualitt0067ff52015-07-08 14:26:19 -07001845 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001846 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001847 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001848}
1849
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001850///////////////////////////////////////////////////////////////////////////////
1851
joshualitteb2a6762014-12-04 11:35:33 -08001852GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1853 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001854}
1855
egdaniel4ca2e602015-11-18 08:01:26 -08001856void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLFPBuilder* builder,
1857 GrGLSLFragmentBuilder* fragBuilder,
1858 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001859 const char* ks;
1860 const char* shininess;
1861
egdaniel2d721d32015-11-11 13:06:05 -08001862 fKSUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001863 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
egdaniel2d721d32015-11-11 13:06:05 -08001864 fShininessUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001865 kFloat_GrSLType,
1866 kDefault_GrSLPrecision,
1867 "Shininess",
1868 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001869
egdaniel0d3f0612015-10-21 10:45:48 -07001870 static const GrGLSLShaderVar gLightArgs[] = {
1871 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1872 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1873 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001874 };
1875 SkString lightBody;
1876 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1877 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001878 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1879 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001880 fragBuilder->emitFunction(kVec4f_GrSLType,
1881 "light",
1882 SK_ARRAY_COUNT(gLightArgs),
1883 gLightArgs,
1884 lightBody.c_str(),
1885 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001886}
1887
egdaniel018fb622015-10-28 07:26:40 -07001888void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1889 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001890 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001891 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001892 pdman.set1f(fKSUni, spec.ks());
1893 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001894}
1895
1896///////////////////////////////////////////////////////////////////////////////
egdaniel8dcdedc2015-11-11 06:27:20 -08001897void GrGLLight::emitLightColorUniform(GrGLSLFPBuilder* builder) {
egdaniel2d721d32015-11-11 13:06:05 -08001898 fColorUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001899 kVec3f_GrSLType, kDefault_GrSLPrecision,
1900 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001901}
1902
egdaniel4ca2e602015-11-18 08:01:26 -08001903void GrGLLight::emitLightColor(GrGLSLFPBuilder* builder,
1904 GrGLSLFragmentBuilder* fragBuilder,
1905 const char *surfaceToLight) {
1906 fragBuilder->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001907}
1908
egdaniel018fb622015-10-28 07:26:40 -07001909void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001910 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001911 setUniformPoint3(pdman, fColorUni,
1912 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001913}
1914
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001915///////////////////////////////////////////////////////////////////////////////
1916
egdaniel018fb622015-10-28 07:26:40 -07001917void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001918 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001919 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001920 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001921 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001922 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001923}
1924
egdaniel4ca2e602015-11-18 08:01:26 -08001925void GrGLDistantLight::emitSurfaceToLight(GrGLSLFPBuilder* builder,
1926 GrGLSLFragmentBuilder* fragBuilder,
1927 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001928 const char* dir;
egdaniel2d721d32015-11-11 13:06:05 -08001929 fDirectionUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001930 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001931 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08001932 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001933}
1934
1935///////////////////////////////////////////////////////////////////////////////
1936
egdaniel018fb622015-10-28 07:26:40 -07001937void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001938 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001939 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001940 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001941 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001942 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001943}
1944
egdaniel4ca2e602015-11-18 08:01:26 -08001945void GrGLPointLight::emitSurfaceToLight(GrGLSLFPBuilder* builder,
1946 GrGLSLFragmentBuilder* fragBuilder,
1947 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001948 const char* loc;
egdaniel2d721d32015-11-11 13:06:05 -08001949 fLocationUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001950 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001951 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08001952 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1953 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001954}
1955
1956///////////////////////////////////////////////////////////////////////////////
1957
egdaniel018fb622015-10-28 07:26:40 -07001958void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001959 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001960 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001961 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001962 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001963 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1964 pdman.set1f(fExponentUni, spotLight->specularExponent());
1965 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1966 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1967 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1968 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001969}
1970
egdaniel4ca2e602015-11-18 08:01:26 -08001971void GrGLSpotLight::emitSurfaceToLight(GrGLSLFPBuilder* builder,
1972 GrGLSLFragmentBuilder* fragBuilder,
1973 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001974 const char* location;
egdaniel2d721d32015-11-11 13:06:05 -08001975 fLocationUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001976 kVec3f_GrSLType, kDefault_GrSLPrecision,
1977 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001978
egdaniel4ca2e602015-11-18 08:01:26 -08001979 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1980 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001981}
1982
egdaniel8dcdedc2015-11-11 06:27:20 -08001983void GrGLSpotLight::emitLightColor(GrGLSLFPBuilder* builder,
egdaniel4ca2e602015-11-18 08:01:26 -08001984 GrGLSLFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001985 const char *surfaceToLight) {
1986
1987 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1988
1989 const char* exponent;
1990 const char* cosInner;
1991 const char* cosOuter;
1992 const char* coneScale;
1993 const char* s;
egdaniel2d721d32015-11-11 13:06:05 -08001994 fExponentUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001995 kFloat_GrSLType, kDefault_GrSLPrecision,
1996 "Exponent", &exponent);
egdaniel2d721d32015-11-11 13:06:05 -08001997 fCosInnerConeAngleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001998 kFloat_GrSLType, kDefault_GrSLPrecision,
1999 "CosInnerConeAngle", &cosInner);
egdaniel2d721d32015-11-11 13:06:05 -08002000 fCosOuterConeAngleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08002001 kFloat_GrSLType, kDefault_GrSLPrecision,
2002 "CosOuterConeAngle", &cosOuter);
egdaniel2d721d32015-11-11 13:06:05 -08002003 fConeScaleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08002004 kFloat_GrSLType, kDefault_GrSLPrecision,
2005 "ConeScale", &coneScale);
egdaniel2d721d32015-11-11 13:06:05 -08002006 fSUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08002007 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002008
egdaniel0d3f0612015-10-21 10:45:48 -07002009 static const GrGLSLShaderVar gLightColorArgs[] = {
2010 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002011 };
2012 SkString lightColorBody;
2013 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2014 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2015 lightColorBody.appendf("\t\treturn vec3(0);\n");
2016 lightColorBody.appendf("\t}\n");
2017 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2018 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2019 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2020 color, cosOuter, coneScale);
2021 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002022 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002023 fragBuilder->emitFunction(kVec3f_GrSLType,
2024 "lightColor",
2025 SK_ARRAY_COUNT(gLightColorArgs),
2026 gLightColorArgs,
2027 lightColorBody.c_str(),
2028 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002029
egdaniel4ca2e602015-11-18 08:01:26 -08002030 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002031}
2032
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002033#endif
2034
djsollen@google.com08337772012-06-26 14:33:13 +00002035SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2036 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2037 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002038SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END