blob: ecb4111158f05a8d7ca305f5b6796b9cfc9b1a08 [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"
wangyix6af0c932015-07-22 10:21:17 -070024#include "gl/GrGLFragmentProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070025#include "gl/builders/GrGLProgramBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070026#include "glsl/GrGLSLProgramDataManager.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000027
28class GrGLDiffuseLightingEffect;
29class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000030
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000031// For brevity
egdaniel018fb622015-10-28 07:26:40 -070032typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000033#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000034
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000035namespace {
36
reed80ea19c2015-05-12 10:37:34 -070037const SkScalar gOneThird = SkIntToScalar(1) / 3;
38const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000039const SkScalar gOneHalf = 0.5f;
40const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000041
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000042#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070043void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070044 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070045 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070046 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000047}
48
egdaniel018fb622015-10-28 07:26:40 -070049void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070050 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070051 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000052}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000053#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000054
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000055// Shift matrix components to the left, as we advance pixels to the right.
56inline void shiftMatrixLeft(int m[9]) {
57 m[0] = m[1];
58 m[3] = m[4];
59 m[6] = m[7];
60 m[1] = m[2];
61 m[4] = m[5];
62 m[7] = m[8];
63}
64
jvanverth992c7612015-07-17 07:22:30 -070065static inline void fast_normalize(SkPoint3* vector) {
66 // add a tiny bit so we don't have to worry about divide-by-zero
67 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
68 SkScalar scale = sk_float_rsqrt(magSq);
69 vector->fX *= scale;
70 vector->fY *= scale;
71 vector->fZ *= scale;
72}
73
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000074class DiffuseLightingType {
75public:
76 DiffuseLightingType(SkScalar kd)
77 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070078 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
79 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000080 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
81 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070082 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000083 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000084 SkClampMax(SkScalarRoundToInt(color.fX), 255),
85 SkClampMax(SkScalarRoundToInt(color.fY), 255),
86 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000087 }
88private:
89 SkScalar fKD;
90};
91
robertphillips3d32d762015-07-13 13:16:44 -070092static SkScalar max_component(const SkPoint3& p) {
93 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
94}
95
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000096class SpecularLightingType {
97public:
98 SpecularLightingType(SkScalar ks, SkScalar shininess)
99 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700100 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
101 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000102 SkPoint3 halfDir(surfaceTolight);
103 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700104 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000105 SkScalar colorScale = SkScalarMul(fKS,
106 SkScalarPow(normal.dot(halfDir), fShininess));
107 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700108 SkPoint3 color = lightColor.makeScale(colorScale);
109 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000110 SkClampMax(SkScalarRoundToInt(color.fX), 255),
111 SkClampMax(SkScalarRoundToInt(color.fY), 255),
112 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000113 }
114private:
115 SkScalar fKS;
116 SkScalar fShininess;
117};
118
119inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
120 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
121}
122
123inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700124 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
125 SkScalarMul(-y, surfaceScale),
126 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700127 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000128 return vector;
129}
130
131inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
132 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
133 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
134 surfaceScale);
135}
136
137inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
138 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
139 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
140 surfaceScale);
141}
142
143inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
144 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
145 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
146 surfaceScale);
147}
148
149inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
150 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
151 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
152 surfaceScale);
153}
154
155
156inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
157 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
158 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
159 surfaceScale);
160}
161
162inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
163 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
164 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
165 surfaceScale);
166}
167
168inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
169 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
170 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
171 surfaceScale);
172}
173
174inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
175 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
176 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
177 surfaceScale);
178}
179
180inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
181 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
182 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
183 surfaceScale);
184}
185
robertphillips2f0dbc72015-08-20 05:15:06 -0700186template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType,
187 const SkImageFilterLight* light,
188 const SkBitmap& src,
189 SkBitmap* dst,
190 SkScalar surfaceScale,
191 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000192 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000193 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000194 int left = bounds.left(), right = bounds.right();
195 int bottom = bounds.bottom();
196 int y = bounds.top();
197 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000198 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000199 int x = left;
200 const SkPMColor* row1 = src.getAddr32(x, y);
201 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000202 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000203 m[4] = SkGetPackedA32(*row1++);
204 m[5] = SkGetPackedA32(*row1++);
205 m[7] = SkGetPackedA32(*row2++);
206 m[8] = SkGetPackedA32(*row2++);
207 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700208 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
209 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000210 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000211 {
212 shiftMatrixLeft(m);
213 m[5] = SkGetPackedA32(*row1++);
214 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700216 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
217 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000218 }
219 shiftMatrixLeft(m);
220 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700221 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
222 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000223 }
224
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000225 for (++y; y < bottom - 1; ++y) {
226 int x = left;
227 const SkPMColor* row0 = src.getAddr32(x, y - 1);
228 const SkPMColor* row1 = src.getAddr32(x, y);
229 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000230 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000231 m[1] = SkGetPackedA32(*row0++);
232 m[2] = SkGetPackedA32(*row0++);
233 m[4] = SkGetPackedA32(*row1++);
234 m[5] = SkGetPackedA32(*row1++);
235 m[7] = SkGetPackedA32(*row2++);
236 m[8] = SkGetPackedA32(*row2++);
237 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700238 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
239 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000240 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000241 shiftMatrixLeft(m);
242 m[2] = SkGetPackedA32(*row0++);
243 m[5] = SkGetPackedA32(*row1++);
244 m[8] = SkGetPackedA32(*row2++);
245 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700246 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
247 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 }
249 shiftMatrixLeft(m);
250 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700251 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
252 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000253 }
254
255 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000256 int x = left;
257 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
258 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000259 int m[9];
260 m[1] = SkGetPackedA32(*row0++);
261 m[2] = SkGetPackedA32(*row0++);
262 m[4] = SkGetPackedA32(*row1++);
263 m[5] = SkGetPackedA32(*row1++);
264 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700265 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
266 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000267 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000268 {
269 shiftMatrixLeft(m);
270 m[2] = SkGetPackedA32(*row0++);
271 m[5] = SkGetPackedA32(*row1++);
272 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700273 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
274 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000275 }
276 shiftMatrixLeft(m);
277 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700278 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
279 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000280 }
281}
282
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000283SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000284 SkPoint3 point;
285 point.fX = buffer.readScalar();
286 point.fY = buffer.readScalar();
287 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000288 buffer.validate(SkScalarIsFinite(point.fX) &&
289 SkScalarIsFinite(point.fY) &&
290 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000291 return point;
292};
293
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000294void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000295 buffer.writeScalar(point.fX);
296 buffer.writeScalar(point.fY);
297 buffer.writeScalar(point.fZ);
298};
299
senorblancod0d37ca2015-04-02 04:54:56 -0700300enum BoundaryMode {
301 kTopLeft_BoundaryMode,
302 kTop_BoundaryMode,
303 kTopRight_BoundaryMode,
304 kLeft_BoundaryMode,
305 kInterior_BoundaryMode,
306 kRight_BoundaryMode,
307 kBottomLeft_BoundaryMode,
308 kBottom_BoundaryMode,
309 kBottomRight_BoundaryMode,
310
311 kBoundaryModeCount,
312};
313
314class SkLightingImageFilterInternal : public SkLightingImageFilter {
315protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700316 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700317 SkScalar surfaceScale,
318 SkImageFilter* input,
319 const CropRect* cropRect)
320 : INHERITED(light, surfaceScale, input, cropRect) {}
321
322#if SK_SUPPORT_GPU
323 bool canFilterImageGPU() const override { return true; }
324 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
325 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700326 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700327 const SkMatrix&,
328 const SkIRect& bounds,
329 BoundaryMode boundaryMode) const = 0;
330#endif
331private:
332#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700333 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700334 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700335 const SkMatrix& matrix,
336 const GrClip& clip,
337 const SkRect& dstRect,
338 BoundaryMode boundaryMode,
339 const SkIRect& bounds) const;
340#endif
341 typedef SkLightingImageFilter INHERITED;
342};
343
344#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700345void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700346 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700347 const SkMatrix& matrix,
348 const GrClip& clip,
349 const SkRect& dstRect,
350 BoundaryMode boundaryMode,
351 const SkIRect& bounds) const {
352 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700353 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700354 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700355 paint.addColorFragmentProcessor(fp)->unref();
robertphillips2e1e51f2015-10-15 08:01:48 -0700356 drawContext->drawNonAARectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700357}
358
359bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
360 const SkBitmap& src,
361 const Context& ctx,
362 SkBitmap* result,
363 SkIPoint* offset) const {
364 SkBitmap input = src;
365 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700366 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700367 return false;
368 }
369 SkIRect bounds;
370 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
371 return false;
372 }
373 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
374 SkIntToScalar(bounds.height()));
375 GrTexture* srcTexture = input.getTexture();
376 GrContext* context = srcTexture->getContext();
377
378 GrSurfaceDesc desc;
379 desc.fFlags = kRenderTarget_GrSurfaceFlag,
380 desc.fWidth = bounds.width();
381 desc.fHeight = bounds.height();
382 desc.fConfig = kRGBA_8888_GrPixelConfig;
383
senorblanco51eedb62015-10-23 09:56:48 -0700384 auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint());
385 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, constraint));
senorblancod0d37ca2015-04-02 04:54:56 -0700386 if (!dst) {
387 return false;
388 }
389
390 // setup new clip
391 GrClip clip(dstRect);
392
393 offset->fX = bounds.left();
394 offset->fY = bounds.top();
395 SkMatrix matrix(ctx.ctm());
396 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
397 bounds.offset(-srcOffset);
398 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
399 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
400 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
401 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
402 SkRect interior = dstRect.makeInset(1, 1);
403 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
404 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
405 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
406 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700407
robertphillips2e1e51f2015-10-15 08:01:48 -0700408 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700409 if (!drawContext) {
410 return false;
411 }
412
robertphillips2e1e51f2015-10-15 08:01:48 -0700413 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
414 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
415 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700416 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700417 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
418 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700419 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700420 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
421 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700422 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700423 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
424 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700425 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700426 WrapTexture(dst, bounds.width(), bounds.height(), result);
427 return true;
428}
429#endif
430
431class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000432public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700433 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
434 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700435 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700436
robertphillipsf3f5bad2014-12-19 13:49:15 -0800437 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000438 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000439 SkScalar kd() const { return fKD; }
440
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000441protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700442 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700443 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700444 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700445 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
446 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000447#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700448 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
449 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000450#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000451
452private:
reed9fa60da2014-08-21 07:59:51 -0700453 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700454 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000455 SkScalar fKD;
456};
457
senorblancod0d37ca2015-04-02 04:54:56 -0700458class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000459public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700460 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700461 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700462
robertphillipsf3f5bad2014-12-19 13:49:15 -0800463 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000464 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
465
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000466 SkScalar ks() const { return fKS; }
467 SkScalar shininess() const { return fShininess; }
468
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000469protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700470 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700471 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700472 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700473 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
474 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000475#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700476 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
477 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000478#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479
480private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481 SkScalar fKS;
482 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700483 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700484 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485};
486
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000487#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000488
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000489class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490public:
bsalomon4a339522015-10-06 08:40:50 -0700491 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
492 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493 virtual ~GrLightingEffect();
494
robertphillips2f0dbc72015-08-20 05:15:06 -0700495 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000497 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700498 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000499
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000500protected:
mtklein36352bf2015-03-25 18:17:31 -0700501 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000502
mtklein36352bf2015-03-25 18:17:31 -0700503 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700504 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800505 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700506 }
507
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700509 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000511 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700512 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700513
514 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515};
516
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000517class GrDiffuseLightingEffect : public GrLightingEffect {
518public:
bsalomon4a339522015-10-06 08:40:50 -0700519 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700520 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700521 SkScalar surfaceScale,
522 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700523 SkScalar kd,
524 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700525 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000526 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527
mtklein36352bf2015-03-25 18:17:31 -0700528 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000530 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000531
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000532private:
wangyixb1daa862015-08-18 11:29:31 -0700533 GrGLFragmentProcessor* onCreateGLInstance() const override;
534
wangyix4b3050b2015-08-04 07:59:37 -0700535 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
536
mtklein36352bf2015-03-25 18:17:31 -0700537 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000538
bsalomon4a339522015-10-06 08:40:50 -0700539 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700540 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000541 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000542 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700543 SkScalar kd,
544 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000545
joshualittb0a8a372014-09-23 09:50:21 -0700546 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000547 typedef GrLightingEffect INHERITED;
548 SkScalar fKD;
549};
550
551class GrSpecularLightingEffect : public GrLightingEffect {
552public:
bsalomon4a339522015-10-06 08:40:50 -0700553 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700554 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700555 SkScalar surfaceScale,
556 const SkMatrix& matrix,
557 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700558 SkScalar shininess,
559 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700560 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
561 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000562 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000563
mtklein36352bf2015-03-25 18:17:31 -0700564 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565
wangyixb1daa862015-08-18 11:29:31 -0700566 GrGLFragmentProcessor* onCreateGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800567
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000568 SkScalar ks() const { return fKS; }
569 SkScalar shininess() const { return fShininess; }
570
571private:
wangyix4b3050b2015-08-04 07:59:37 -0700572 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
573
mtklein36352bf2015-03-25 18:17:31 -0700574 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000575
bsalomon4a339522015-10-06 08:40:50 -0700576 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700577 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000578 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000579 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000580 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700581 SkScalar shininess,
582 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000583
joshualittb0a8a372014-09-23 09:50:21 -0700584 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000585 typedef GrLightingEffect INHERITED;
586 SkScalar fKS;
587 SkScalar fShininess;
588};
589
590///////////////////////////////////////////////////////////////////////////////
591
592class GrGLLight {
593public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000594 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000595
596 /**
597 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
598 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
599 */
joshualitt15988992014-10-09 15:04:05 -0700600 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000601
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000602 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000603 * These two functions are called from GrGLLightingEffect's emitCode() function.
604 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
605 * the light. The expression will be used in the FS. emitLightColor writes an expression into
606 * the FS that is the color of the light. Either function may add functions and/or uniforms to
607 * the FS. The default of emitLightColor appends the name of the constant light color uniform
608 * and so this function only needs to be overridden if the light color varies spatially.
609 */
joshualitt15988992014-10-09 15:04:05 -0700610 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
611 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000612
613 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
614 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700615 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000616
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000617protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000618 /**
619 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
620 * function.
621 */
622 UniformHandle lightColorUni() const { return fColorUni; }
623
624private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000625 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000626
627 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628};
629
630///////////////////////////////////////////////////////////////////////////////
631
632class GrGLDistantLight : public GrGLLight {
633public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000634 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700635 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700636 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000637
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638private:
639 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000640 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000641};
642
643///////////////////////////////////////////////////////////////////////////////
644
645class GrGLPointLight : public GrGLLight {
646public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000647 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700648 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700649 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000650
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000651private:
652 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000653 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000654};
655
656///////////////////////////////////////////////////////////////////////////////
657
658class GrGLSpotLight : public GrGLLight {
659public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000660 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700661 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700662 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
663 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000664
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000665private:
666 typedef GrGLLight INHERITED;
667
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000668 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000669 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000670 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000671 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000672 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000673 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000674 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000675};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000676#else
677
678class GrGLLight;
679
680#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000681
682};
683
684///////////////////////////////////////////////////////////////////////////////
685
robertphillips2f0dbc72015-08-20 05:15:06 -0700686class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000687public:
caryclark0bccd872015-10-20 10:04:03 -0700688
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000689
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000690 enum LightType {
691 kDistant_LightType,
692 kPoint_LightType,
693 kSpot_LightType,
694 };
695 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000696 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000697 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700698 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000699 return fColor == other.fColor;
700 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000701 // Called to know whether the generated GrGLLight will require access to the fragment position.
702 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700703 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000705 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000706 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700707 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000708
djsollen@google.com08337772012-06-26 14:33:13 +0000709protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700710 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700711 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
712 SkIntToScalar(SkColorGetG(color)),
713 SkIntToScalar(SkColorGetB(color)));
714 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700715 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000716 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700717 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000718 fColor = readPoint3(buffer);
719 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000720
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000721 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000722
djsollen@google.com08337772012-06-26 14:33:13 +0000723
724private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000725 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000726 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000727};
728
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000729///////////////////////////////////////////////////////////////////////////////
730
robertphillips2f0dbc72015-08-20 05:15:06 -0700731class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000732public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000733 SkDistantLight(const SkPoint3& direction, SkColor color)
734 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000735 }
djsollen@google.com08337772012-06-26 14:33:13 +0000736
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000737 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
738 return fDirection;
739 };
robertphillips3d32d762015-07-13 13:16:44 -0700740 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700741 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000742 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700743 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000744#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700745 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000746#else
747 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700748 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000749#endif
750 }
mtklein36352bf2015-03-25 18:17:31 -0700751 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000752
robertphillips2f0dbc72015-08-20 05:15:06 -0700753 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000754 if (other.type() != kDistant_LightType) {
755 return false;
756 }
757
758 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
759 return INHERITED::isEqual(other) &&
760 fDirection == o.fDirection;
761 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000762
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000763 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000764 fDirection = readPoint3(buffer);
765 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000766
djsollen@google.com08337772012-06-26 14:33:13 +0000767protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000768 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
769 : INHERITED(color), fDirection(direction) {
770 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700771 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000772 return new SkDistantLight(direction(), color());
773 }
mtklein36352bf2015-03-25 18:17:31 -0700774 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000775 writePoint3(fDirection, buffer);
776 }
777
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000778private:
779 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700780
781 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000782};
783
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000784///////////////////////////////////////////////////////////////////////////////
785
robertphillips2f0dbc72015-08-20 05:15:06 -0700786class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000787public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000788 SkPointLight(const SkPoint3& location, SkColor color)
789 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000790
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000791 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700792 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
793 fLocation.fY - SkIntToScalar(y),
794 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
795 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700796 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000797 return direction;
798 };
robertphillips3d32d762015-07-13 13:16:44 -0700799 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700800 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000801 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700802 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000803#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700804 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000805#else
806 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700807 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000808#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000809 }
mtklein36352bf2015-03-25 18:17:31 -0700810 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700811 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000812 if (other.type() != kPoint_LightType) {
813 return false;
814 }
815 const SkPointLight& o = static_cast<const SkPointLight&>(other);
816 return INHERITED::isEqual(other) &&
817 fLocation == o.fLocation;
818 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700819 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000820 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
821 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000822 // Use X scale and Y scale on Z and average the result
823 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
824 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700825 SkPoint3 location = SkPoint3::Make(location2.fX,
826 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700827 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000828 return new SkPointLight(location, color());
829 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000830
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000831 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000832 fLocation = readPoint3(buffer);
833 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000834
835protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000836 SkPointLight(const SkPoint3& location, const SkPoint3& color)
837 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700838 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000839 writePoint3(fLocation, buffer);
840 }
841
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000842private:
843 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700844
845 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000846};
847
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000848///////////////////////////////////////////////////////////////////////////////
849
robertphillips2f0dbc72015-08-20 05:15:06 -0700850class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851public:
senorblancod0d37ca2015-04-02 04:54:56 -0700852 SkSpotLight(const SkPoint3& location,
853 const SkPoint3& target,
854 SkScalar specularExponent,
855 SkScalar cutoffAngle,
856 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000857 : INHERITED(color),
858 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000859 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700860 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000861 {
862 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700863 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000864 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000865 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000866 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
867 fConeScale = SkScalarInvert(antiAliasThreshold);
868 }
djsollen@google.com08337772012-06-26 14:33:13 +0000869
robertphillips2f0dbc72015-08-20 05:15:06 -0700870 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000871 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
872 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000873 // Use X scale and Y scale on Z and average the result
874 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
875 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700876 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
877 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000878 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
879 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000880 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
881 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700882 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
883 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000884 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700885 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700886 return new SkSpotLight(location,
887 target,
888 fSpecularExponent,
889 fCosOuterConeAngle,
890 fCosInnerConeAngle,
891 fConeScale,
892 s,
893 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000894 }
895
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000896 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700897 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
898 fLocation.fY - SkIntToScalar(y),
899 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
900 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700901 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902 return direction;
903 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000904 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000905 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700906 SkScalar scale = 0;
907 if (cosAngle >= fCosOuterConeAngle) {
908 scale = SkScalarPow(cosAngle, fSpecularExponent);
909 if (cosAngle < fCosInnerConeAngle) {
910 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
911 scale *= fConeScale;
912 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000913 }
robertphillips3d32d762015-07-13 13:16:44 -0700914 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000915 }
mtklein36352bf2015-03-25 18:17:31 -0700916 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000917#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700918 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000919#else
920 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700921 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000922#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000923 }
mtklein36352bf2015-03-25 18:17:31 -0700924 bool requiresFragmentPosition() const override { return true; }
925 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000926 const SkPoint3& location() const { return fLocation; }
927 const SkPoint3& target() const { return fTarget; }
928 SkScalar specularExponent() const { return fSpecularExponent; }
929 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
930 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
931 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000932 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000933
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000934 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000935 fLocation = readPoint3(buffer);
936 fTarget = readPoint3(buffer);
937 fSpecularExponent = buffer.readScalar();
938 fCosOuterConeAngle = buffer.readScalar();
939 fCosInnerConeAngle = buffer.readScalar();
940 fConeScale = buffer.readScalar();
941 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000942 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
943 SkScalarIsFinite(fCosOuterConeAngle) &&
944 SkScalarIsFinite(fCosInnerConeAngle) &&
945 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000946 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000947protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700948 SkSpotLight(const SkPoint3& location,
949 const SkPoint3& target,
950 SkScalar specularExponent,
951 SkScalar cosOuterConeAngle,
952 SkScalar cosInnerConeAngle,
953 SkScalar coneScale,
954 const SkPoint3& s,
955 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000956 : INHERITED(color),
957 fLocation(location),
958 fTarget(target),
959 fSpecularExponent(specularExponent),
960 fCosOuterConeAngle(cosOuterConeAngle),
961 fCosInnerConeAngle(cosInnerConeAngle),
962 fConeScale(coneScale),
963 fS(s)
964 {
965 }
mtklein36352bf2015-03-25 18:17:31 -0700966 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000967 writePoint3(fLocation, buffer);
968 writePoint3(fTarget, buffer);
969 buffer.writeScalar(fSpecularExponent);
970 buffer.writeScalar(fCosOuterConeAngle);
971 buffer.writeScalar(fCosInnerConeAngle);
972 buffer.writeScalar(fConeScale);
973 writePoint3(fS, buffer);
974 }
975
robertphillips2f0dbc72015-08-20 05:15:06 -0700976 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000977 if (other.type() != kSpot_LightType) {
978 return false;
979 }
980
981 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
982 return INHERITED::isEqual(other) &&
983 fLocation == o.fLocation &&
984 fTarget == o.fTarget &&
985 fSpecularExponent == o.fSpecularExponent &&
986 fCosOuterConeAngle == o.fCosOuterConeAngle;
987 }
988
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000989private:
caryclark0bccd872015-10-20 10:04:03 -0700990 static const SkScalar kSpecularExponentMin;
991 static const SkScalar kSpecularExponentMax;
992
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000993 SkPoint3 fLocation;
994 SkPoint3 fTarget;
995 SkScalar fSpecularExponent;
996 SkScalar fCosOuterConeAngle;
997 SkScalar fCosInnerConeAngle;
998 SkScalar fConeScale;
999 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001000
1001 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001002};
1003
caryclark0bccd872015-10-20 10:04:03 -07001004// According to the spec, the specular term should be in the range [1, 128] :
1005// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1006const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1007const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1008
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001009///////////////////////////////////////////////////////////////////////////////
1010
robertphillips2f0dbc72015-08-20 05:15:06 -07001011void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001012 // Write type first, then baseclass, then subclass.
1013 buffer.writeInt(this->type());
1014 writePoint3(fColor, buffer);
1015 this->onFlattenLight(buffer);
1016}
1017
robertphillips2f0dbc72015-08-20 05:15:06 -07001018/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001019 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001020 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001021 switch (type) {
1022 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1023 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001024 case SkImageFilterLight::kDistant_LightType:
1025 return new SkDistantLight(buffer);
1026 case SkImageFilterLight::kPoint_LightType:
1027 return new SkPointLight(buffer);
1028 case SkImageFilterLight::kSpot_LightType:
1029 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001030 default:
1031 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001032 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001033 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001034 }
1035}
1036///////////////////////////////////////////////////////////////////////////////
1037
robertphillips2f0dbc72015-08-20 05:15:06 -07001038SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001039 SkImageFilter* input, const CropRect* cropRect)
1040 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001041 , fLight(SkRef(light))
1042 , fSurfaceScale(surfaceScale / 255)
1043{}
1044
1045SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1046 SkColor lightColor,
1047 SkScalar surfaceScale,
1048 SkScalar kd,
1049 SkImageFilter* input,
1050 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001051 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001052 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001053}
1054
reed9fa60da2014-08-21 07:59:51 -07001055SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1056 SkColor lightColor,
1057 SkScalar surfaceScale,
1058 SkScalar kd,
1059 SkImageFilter* input,
1060 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001061 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001062 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001063}
1064
reed9fa60da2014-08-21 07:59:51 -07001065SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1066 const SkPoint3& target,
1067 SkScalar specularExponent,
1068 SkScalar cutoffAngle,
1069 SkColor lightColor,
1070 SkScalar surfaceScale,
1071 SkScalar kd,
1072 SkImageFilter* input,
1073 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001074 SkAutoTUnref<SkImageFilterLight> light(
1075 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001076 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001077}
1078
reed9fa60da2014-08-21 07:59:51 -07001079SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1080 SkColor lightColor,
1081 SkScalar surfaceScale,
1082 SkScalar ks,
1083 SkScalar shine,
1084 SkImageFilter* input,
1085 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001086 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001087 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001088}
1089
reed9fa60da2014-08-21 07:59:51 -07001090SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1091 SkColor lightColor,
1092 SkScalar surfaceScale,
1093 SkScalar ks,
1094 SkScalar shine,
1095 SkImageFilter* input,
1096 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001097 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001098 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001099}
1100
reed9fa60da2014-08-21 07:59:51 -07001101SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1102 const SkPoint3& target,
1103 SkScalar specularExponent,
1104 SkScalar cutoffAngle,
1105 SkColor lightColor,
1106 SkScalar surfaceScale,
1107 SkScalar ks,
1108 SkScalar shine,
1109 SkImageFilter* input,
1110 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001111 SkAutoTUnref<SkImageFilterLight> light(
1112 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001113 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001114}
1115
reed9fa60da2014-08-21 07:59:51 -07001116SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001117
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001118void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001119 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001120 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001121 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001122}
1123
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001124///////////////////////////////////////////////////////////////////////////////
1125
robertphillips2f0dbc72015-08-20 05:15:06 -07001126SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1127 SkScalar surfaceScale,
1128 SkScalar kd,
1129 SkImageFilter* input,
1130 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001131 if (nullptr == light) {
1132 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001133 }
1134 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001135 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001136 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001137 // According to the spec, kd can be any non-negative number :
1138 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001139 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001140 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001141 }
halcanary385fe4d2015-08-26 13:07:48 -07001142 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001143}
1144
robertphillips2f0dbc72015-08-20 05:15:06 -07001145SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001146 SkScalar surfaceScale,
1147 SkScalar kd,
1148 SkImageFilter* input,
1149 const CropRect* cropRect)
1150 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001151 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001152{
1153}
1154
reed9fa60da2014-08-21 07:59:51 -07001155SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1156 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001157 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001158 SkScalar surfaceScale = buffer.readScalar();
1159 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001160 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001161}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001162
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001163void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001164 this->INHERITED::flatten(buffer);
1165 buffer.writeScalar(fKD);
1166}
1167
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001168bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1169 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001170 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001171 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001172 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001173 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001174 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001175 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001176 return false;
1177 }
1178
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001179 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001180 return false;
1181 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001182 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001183 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001184 return false;
1185 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001186
1187 if (bounds.width() < 2 || bounds.height() < 2) {
1188 return false;
1189 }
1190
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001191 SkAutoLockPixels alp(src);
1192 if (!src.getPixels()) {
1193 return false;
1194 }
1195
senorblanco1d3ff432015-10-20 10:17:34 -07001196 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1197 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001198 return false;
1199 }
senorblanco1d3ff432015-10-20 10:17:34 -07001200 *dst = device->accessBitmap(false);
1201 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001202
senorblanco7b7ecfc2015-08-26 14:26:40 -07001203 SkMatrix matrix(ctx.ctm());
1204 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1205 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001206
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001207 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001208 offset->fX = bounds.left();
1209 offset->fY = bounds.top();
1210 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001211 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001212 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001213 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1214 transformedLight,
1215 src,
1216 dst,
1217 surfaceScale(),
1218 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001219 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001220 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001221 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1222 transformedLight,
1223 src,
1224 dst,
1225 surfaceScale(),
1226 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001227 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001228 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001229 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1230 transformedLight,
1231 src,
1232 dst,
1233 surfaceScale(),
1234 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001235 break;
1236 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001237
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001238 return true;
1239}
1240
robertphillipsf3f5bad2014-12-19 13:49:15 -08001241#ifndef SK_IGNORE_TO_STRING
1242void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1243 str->appendf("SkDiffuseLightingImageFilter: (");
1244 str->appendf("kD: %f\n", fKD);
1245 str->append(")");
1246}
1247#endif
1248
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001249#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001250GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001251 GrTexture* texture,
1252 const SkMatrix& matrix,
1253 const SkIRect&,
1254 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001255) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001256 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001257 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1258 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001259}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001260#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001261
1262///////////////////////////////////////////////////////////////////////////////
1263
robertphillips2f0dbc72015-08-20 05:15:06 -07001264SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1265 SkScalar surfaceScale,
1266 SkScalar ks,
1267 SkScalar shininess,
1268 SkImageFilter* input,
1269 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001270 if (nullptr == light) {
1271 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001272 }
1273 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001274 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001275 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001276 // According to the spec, ks can be any non-negative number :
1277 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001278 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001279 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001280 }
halcanary385fe4d2015-08-26 13:07:48 -07001281 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001282}
1283
robertphillips2f0dbc72015-08-20 05:15:06 -07001284SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001285 SkScalar surfaceScale,
1286 SkScalar ks,
1287 SkScalar shininess,
1288 SkImageFilter* input,
1289 const CropRect* cropRect)
1290 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001291 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001292 fShininess(shininess)
1293{
1294}
1295
reed9fa60da2014-08-21 07:59:51 -07001296SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1297 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001298 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001299 SkScalar surfaceScale = buffer.readScalar();
1300 SkScalar ks = buffer.readScalar();
1301 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001302 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001303}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001304
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001305void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001306 this->INHERITED::flatten(buffer);
1307 buffer.writeScalar(fKS);
1308 buffer.writeScalar(fShininess);
1309}
1310
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001311bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1312 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001313 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001314 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001315 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001316 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001317 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001318 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001319 return false;
1320 }
1321
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001322 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001323 return false;
1324 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001325
1326 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001327 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001328 return false;
1329 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001330
1331 if (bounds.width() < 2 || bounds.height() < 2) {
1332 return false;
1333 }
1334
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001335 SkAutoLockPixels alp(src);
1336 if (!src.getPixels()) {
1337 return false;
1338 }
1339
senorblanco1d3ff432015-10-20 10:17:34 -07001340 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1341 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001342 return false;
1343 }
senorblanco1d3ff432015-10-20 10:17:34 -07001344 *dst = device->accessBitmap(false);
1345 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001346
1347 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001348 offset->fX = bounds.left();
1349 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001350 SkMatrix matrix(ctx.ctm());
1351 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1352 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001353 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001354 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001355 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001356 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1357 transformedLight,
1358 src,
1359 dst,
1360 surfaceScale(),
1361 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001362 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001363 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001364 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1365 transformedLight,
1366 src,
1367 dst,
1368 surfaceScale(),
1369 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001370 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001371 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001372 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1373 transformedLight,
1374 src,
1375 dst,
1376 surfaceScale(),
1377 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001378 break;
1379 }
1380 return true;
1381}
1382
robertphillipsf3f5bad2014-12-19 13:49:15 -08001383#ifndef SK_IGNORE_TO_STRING
1384void SkSpecularLightingImageFilter::toString(SkString* str) const {
1385 str->appendf("SkSpecularLightingImageFilter: (");
1386 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1387 str->append(")");
1388}
1389#endif
1390
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001391#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001392GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001393 GrTexture* texture,
1394 const SkMatrix& matrix,
1395 const SkIRect&,
1396 BoundaryMode boundaryMode) const {
1397 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001398 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1399 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001400}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001401#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001402
1403///////////////////////////////////////////////////////////////////////////////
1404
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001405#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001406
1407namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001408SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001409 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1410 SkScalarToFloat(random->nextSScalar1()),
1411 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001412}
1413
robertphillips2f0dbc72015-08-20 05:15:06 -07001414SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001415 int type = random->nextULessThan(3);
1416 switch (type) {
1417 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001418 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001419 }
1420 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001421 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001422 }
1423 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001424 return new SkSpotLight(random_point3(random), random_point3(random),
1425 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001426 }
1427 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001428 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001429 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001430 }
1431}
1432
senorblancod0d37ca2015-04-02 04:54:56 -07001433SkString emitNormalFunc(BoundaryMode mode,
1434 const char* pointToNormalName,
1435 const char* sobelFuncName) {
1436 SkString result;
1437 switch (mode) {
1438 case kTopLeft_BoundaryMode:
1439 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1440 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1441 "\t surfaceScale);\n",
1442 pointToNormalName, sobelFuncName, gTwoThirds,
1443 sobelFuncName, gTwoThirds);
1444 break;
1445 case kTop_BoundaryMode:
1446 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1447 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1448 "\t surfaceScale);\n",
1449 pointToNormalName, sobelFuncName, gOneThird,
1450 sobelFuncName, gOneHalf);
1451 break;
1452 case kTopRight_BoundaryMode:
1453 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1454 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1455 "\t surfaceScale);\n",
1456 pointToNormalName, sobelFuncName, gTwoThirds,
1457 sobelFuncName, gTwoThirds);
1458 break;
1459 case kLeft_BoundaryMode:
1460 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1461 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1462 "\t surfaceScale);\n",
1463 pointToNormalName, sobelFuncName, gOneHalf,
1464 sobelFuncName, gOneThird);
1465 break;
1466 case kInterior_BoundaryMode:
1467 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1468 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1469 "\t surfaceScale);\n",
1470 pointToNormalName, sobelFuncName, gOneQuarter,
1471 sobelFuncName, gOneQuarter);
1472 break;
1473 case kRight_BoundaryMode:
1474 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1475 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1476 "\t surfaceScale);\n",
1477 pointToNormalName, sobelFuncName, gOneHalf,
1478 sobelFuncName, gOneThird);
1479 break;
1480 case kBottomLeft_BoundaryMode:
1481 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1482 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1483 "\t surfaceScale);\n",
1484 pointToNormalName, sobelFuncName, gTwoThirds,
1485 sobelFuncName, gTwoThirds);
1486 break;
1487 case kBottom_BoundaryMode:
1488 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1489 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1490 "\t surfaceScale);\n",
1491 pointToNormalName, sobelFuncName, gOneThird,
1492 sobelFuncName, gOneHalf);
1493 break;
1494 case kBottomRight_BoundaryMode:
1495 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1496 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1497 "\t surfaceScale);\n",
1498 pointToNormalName, sobelFuncName, gTwoThirds,
1499 sobelFuncName, gTwoThirds);
1500 break;
1501 default:
1502 SkASSERT(false);
1503 break;
1504 }
1505 return result;
1506}
1507
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001508}
1509
joshualittb0a8a372014-09-23 09:50:21 -07001510class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001511public:
joshualitteb2a6762014-12-04 11:35:33 -08001512 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001513 virtual ~GrGLLightingEffect();
1514
wangyix7c157a92015-07-22 15:08:53 -07001515 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001516
jvanverthcfc18862015-04-28 08:48:20 -07001517 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001519protected:
wangyixb1daa862015-08-18 11:29:31 -07001520 /**
1521 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1522 */
egdaniel018fb622015-10-28 07:26:40 -07001523 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001524
joshualitt15988992014-10-09 15:04:05 -07001525 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001526
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001527private:
joshualittb0a8a372014-09-23 09:50:21 -07001528 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001529
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001530 UniformHandle fImageIncrementUni;
1531 UniformHandle fSurfaceScaleUni;
1532 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001533 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001534};
1535
1536///////////////////////////////////////////////////////////////////////////////
1537
1538class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1539public:
joshualitteb2a6762014-12-04 11:35:33 -08001540 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001541 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001542
1543protected:
egdaniel018fb622015-10-28 07:26:40 -07001544 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001545
1546private:
1547 typedef GrGLLightingEffect INHERITED;
1548
bsalomon@google.com032b2212012-07-16 13:36:18 +00001549 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001550};
1551
1552///////////////////////////////////////////////////////////////////////////////
1553
1554class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1555public:
joshualitteb2a6762014-12-04 11:35:33 -08001556 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001557 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001558
1559protected:
egdaniel018fb622015-10-28 07:26:40 -07001560 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001561
1562private:
1563 typedef GrGLLightingEffect INHERITED;
1564
bsalomon@google.com032b2212012-07-16 13:36:18 +00001565 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001566 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001567};
1568
1569///////////////////////////////////////////////////////////////////////////////
1570
bsalomon4a339522015-10-06 08:40:50 -07001571GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001572 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001573 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001574 const SkMatrix& matrix,
1575 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001576 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001577 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001578 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001579 , fFilterMatrix(matrix)
1580 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001581 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001582 if (light->requiresFragmentPosition()) {
1583 this->setWillReadFragmentPosition();
1584 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001585}
1586
1587GrLightingEffect::~GrLightingEffect() {
1588 fLight->unref();
1589}
1590
bsalomon0e08fc12014-10-15 08:19:04 -07001591bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001592 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001593 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001594 fSurfaceScale == s.fSurfaceScale &&
1595 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001596}
1597
1598///////////////////////////////////////////////////////////////////////////////
1599
bsalomon4a339522015-10-06 08:40:50 -07001600GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001601 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001602 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001603 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001604 SkScalar kd,
1605 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001606 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001607 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001608}
1609
bsalomon0e08fc12014-10-15 08:19:04 -07001610bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001611 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001612 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001613 this->kd() == s.kd();
1614}
1615
wangyix4b3050b2015-08-04 07:59:37 -07001616void GrDiffuseLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001617 GrProcessorKeyBuilder* b) const {
1618 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1619}
1620
wangyixb1daa862015-08-18 11:29:31 -07001621GrGLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001622 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001623}
1624
joshualittb0a8a372014-09-23 09:50:21 -07001625GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001626
bsalomonc21b09e2015-08-28 18:46:56 -07001627const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001628 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1629 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001630 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001631 SkMatrix matrix;
1632 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001633 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001634 }
joshualitt0067ff52015-07-08 14:26:19 -07001635 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001636 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001637 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001638}
1639
1640
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001641///////////////////////////////////////////////////////////////////////////////
1642
joshualitteb2a6762014-12-04 11:35:33 -08001643GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001644 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001645 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001646 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001647}
1648
1649GrGLLightingEffect::~GrGLLightingEffect() {
1650 delete fLight;
1651}
1652
wangyix7c157a92015-07-22 15:08:53 -07001653void GrGLLightingEffect::emitCode(EmitArgs& args) {
1654 fImageIncrementUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001655 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001656 "ImageIncrement");
wangyix7c157a92015-07-22 15:08:53 -07001657 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001658 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001659 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001660 fLight->emitLightColorUniform(args.fBuilder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001661 SkString lightFunc;
wangyix7c157a92015-07-22 15:08:53 -07001662 this->emitLightFunc(args.fBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001663 static const GrGLSLShaderVar gSobelArgs[] = {
1664 GrGLSLShaderVar("a", kFloat_GrSLType),
1665 GrGLSLShaderVar("b", kFloat_GrSLType),
1666 GrGLSLShaderVar("c", kFloat_GrSLType),
1667 GrGLSLShaderVar("d", kFloat_GrSLType),
1668 GrGLSLShaderVar("e", kFloat_GrSLType),
1669 GrGLSLShaderVar("f", kFloat_GrSLType),
1670 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001671 };
1672 SkString sobelFuncName;
wangyix7c157a92015-07-22 15:08:53 -07001673 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1674 SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001675
1676 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001677 "sobel",
1678 SK_ARRAY_COUNT(gSobelArgs),
1679 gSobelArgs,
1680 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1681 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001682 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1683 GrGLSLShaderVar("x", kFloat_GrSLType),
1684 GrGLSLShaderVar("y", kFloat_GrSLType),
1685 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001686 };
1687 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001688 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001689 "pointToNormal",
1690 SK_ARRAY_COUNT(gPointToNormalArgs),
1691 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001692 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001693 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001694
egdaniel0d3f0612015-10-21 10:45:48 -07001695 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1696 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1697 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001698 };
senorblancod0d37ca2015-04-02 04:54:56 -07001699 SkString normalBody = emitNormalFunc(fBoundaryMode,
1700 pointToNormalName.c_str(),
1701 sobelFuncName.c_str());
1702 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001703 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001704 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001705 SK_ARRAY_COUNT(gInteriorNormalArgs),
1706 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001707 normalBody.c_str(),
1708 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001709
joshualitt30ba4362014-08-21 20:18:45 -07001710 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1711 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001712
wangyix7c157a92015-07-22 15:08:53 -07001713 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1714 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001715
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001716 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001717 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001718 for (int dx = -1; dx <= 1; dx++) {
1719 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001720 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001721 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
wangyix7c157a92015-07-22 15:08:53 -07001722 fsBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001723 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001724 }
1725 }
joshualitt30ba4362014-08-21 20:18:45 -07001726 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001727 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001728 arg.appendf("%s * m[4]", surfScale);
wangyix7c157a92015-07-22 15:08:53 -07001729 fLight->emitSurfaceToLight(args.fBuilder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001730 fsBuilder->codeAppend(";\n");
1731 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
wangyix7c157a92015-07-22 15:08:53 -07001732 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1733 fLight->emitLightColor(args.fBuilder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001734 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001735 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001736 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001737 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001738}
1739
joshualittb0a8a372014-09-23 09:50:21 -07001740void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001741 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001742 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1743 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001744}
1745
egdaniel018fb622015-10-28 07:26:40 -07001746void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1747 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001748 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001749 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001750 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001751 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1752 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001753 SkAutoTUnref<SkImageFilterLight> transformedLight(
1754 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001755 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001756}
1757
1758///////////////////////////////////////////////////////////////////////////////
1759
1760///////////////////////////////////////////////////////////////////////////////
1761
joshualitteb2a6762014-12-04 11:35:33 -08001762GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1763 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001764}
1765
joshualitt15988992014-10-09 15:04:05 -07001766void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001767 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001768 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001769 kFloat_GrSLType, kDefault_GrSLPrecision,
1770 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001771
egdaniel0d3f0612015-10-21 10:45:48 -07001772 static const GrGLSLShaderVar gLightArgs[] = {
1773 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1774 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1775 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001776 };
1777 SkString lightBody;
1778 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1779 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001780 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1781 "light",
1782 SK_ARRAY_COUNT(gLightArgs),
1783 gLightArgs,
1784 lightBody.c_str(),
1785 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001786}
1787
egdaniel018fb622015-10-28 07:26:40 -07001788void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1789 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001790 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001791 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001792 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001793}
1794
1795///////////////////////////////////////////////////////////////////////////////
1796
bsalomon4a339522015-10-06 08:40:50 -07001797GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001798 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001799 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001800 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001801 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001802 SkScalar shininess,
1803 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001804 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001805 , fKS(ks)
1806 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001807 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001808}
1809
bsalomon0e08fc12014-10-15 08:19:04 -07001810bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001811 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001812 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001813 this->ks() == s.ks() &&
1814 this->shininess() == s.shininess();
1815}
1816
wangyix4b3050b2015-08-04 07:59:37 -07001817void GrSpecularLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001818 GrProcessorKeyBuilder* b) const {
1819 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1820}
1821
wangyixb1daa862015-08-18 11:29:31 -07001822GrGLFragmentProcessor* GrSpecularLightingEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001823 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001824}
1825
joshualittb0a8a372014-09-23 09:50:21 -07001826GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001827
bsalomonc21b09e2015-08-28 18:46:56 -07001828const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001829 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1830 SkScalar ks = d->fRandom->nextUScalar1();
1831 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001832 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001833 SkMatrix matrix;
1834 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001835 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001836 }
joshualitt0067ff52015-07-08 14:26:19 -07001837 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001838 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001839 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001840}
1841
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001842///////////////////////////////////////////////////////////////////////////////
1843
joshualitteb2a6762014-12-04 11:35:33 -08001844GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1845 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001846}
1847
joshualitt15988992014-10-09 15:04:05 -07001848void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001849 const char* ks;
1850 const char* shininess;
1851
joshualitt30ba4362014-08-21 20:18:45 -07001852 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001853 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001854 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001855 kFloat_GrSLType,
1856 kDefault_GrSLPrecision,
1857 "Shininess",
1858 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001859
egdaniel0d3f0612015-10-21 10:45:48 -07001860 static const GrGLSLShaderVar gLightArgs[] = {
1861 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1862 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1863 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001864 };
1865 SkString lightBody;
1866 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1867 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001868 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1869 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001870 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1871 "light",
1872 SK_ARRAY_COUNT(gLightArgs),
1873 gLightArgs,
1874 lightBody.c_str(),
1875 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001876}
1877
egdaniel018fb622015-10-28 07:26:40 -07001878void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1879 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001880 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001881 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001882 pdman.set1f(fKSUni, spec.ks());
1883 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001884}
1885
1886///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001887void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001888 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001889 kVec3f_GrSLType, kDefault_GrSLPrecision,
1890 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001891}
1892
robertphillips3d32d762015-07-13 13:16:44 -07001893void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001894 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001895}
1896
egdaniel018fb622015-10-28 07:26:40 -07001897void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001898 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001899 setUniformPoint3(pdman, fColorUni,
1900 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001901}
1902
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001903///////////////////////////////////////////////////////////////////////////////
1904
egdaniel018fb622015-10-28 07:26:40 -07001905void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001906 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001907 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001908 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001909 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001910 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001911}
1912
joshualitt15988992014-10-09 15:04:05 -07001913void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001914 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001915 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1916 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001917 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001918 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001919}
1920
1921///////////////////////////////////////////////////////////////////////////////
1922
egdaniel018fb622015-10-28 07:26:40 -07001923void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001924 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001925 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001926 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001927 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001928 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001929}
1930
joshualitt15988992014-10-09 15:04:05 -07001931void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001932 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001933 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1934 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001935 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001936 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001937 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1938 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001939}
1940
1941///////////////////////////////////////////////////////////////////////////////
1942
egdaniel018fb622015-10-28 07:26:40 -07001943void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001944 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001945 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001946 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001947 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001948 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1949 pdman.set1f(fExponentUni, spotLight->specularExponent());
1950 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1951 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1952 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1953 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001954}
1955
joshualitt15988992014-10-09 15:04:05 -07001956void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001957 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001958 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001959 kVec3f_GrSLType, kDefault_GrSLPrecision,
1960 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001961
egdaniel29bee0f2015-04-29 11:54:42 -07001962 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001963 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1964 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001965}
1966
joshualitt15988992014-10-09 15:04:05 -07001967void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001968 const char *surfaceToLight) {
1969
1970 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1971
1972 const char* exponent;
1973 const char* cosInner;
1974 const char* cosOuter;
1975 const char* coneScale;
1976 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001977 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001978 kFloat_GrSLType, kDefault_GrSLPrecision,
1979 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001980 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001981 kFloat_GrSLType, kDefault_GrSLPrecision,
1982 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001983 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001984 kFloat_GrSLType, kDefault_GrSLPrecision,
1985 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001986 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001987 kFloat_GrSLType, kDefault_GrSLPrecision,
1988 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001989 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001990 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001991
egdaniel0d3f0612015-10-21 10:45:48 -07001992 static const GrGLSLShaderVar gLightColorArgs[] = {
1993 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001994 };
1995 SkString lightColorBody;
1996 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1997 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1998 lightColorBody.appendf("\t\treturn vec3(0);\n");
1999 lightColorBody.appendf("\t}\n");
2000 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2001 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2002 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2003 color, cosOuter, coneScale);
2004 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002005 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07002006 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002007 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002008 "lightColor",
2009 SK_ARRAY_COUNT(gLightColorArgs),
2010 gLightColorArgs,
2011 lightColorBody.c_str(),
2012 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002013
joshualitt30ba4362014-08-21 20:18:45 -07002014 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002015}
2016
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002017#endif
2018
djsollen@google.com08337772012-06-26 14:33:13 +00002019SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2020 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2021 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002022SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END