blob: 972d9ac68ba5ae8a737b84896529c54525dfe669 [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"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000015#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
joshualitteb2a6762014-12-04 11:35:33 -080018#include "GrFragmentProcessor.h"
19#include "GrInvariantOutput.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000020#include "effects/GrSingleTextureEffect.h"
joshualittb0a8a372014-09-23 09:50:21 -070021#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070022#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000023
24class GrGLDiffuseLightingEffect;
25class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000026
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000027// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070028typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000029#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000030
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000031namespace {
32
33const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
34const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000035const SkScalar gOneHalf = 0.5f;
36const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000038#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070039void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
40 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000041 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070042 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000043}
44
joshualittb0a8a372014-09-23 09:50:21 -070045void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
46 const SkPoint3& point) {
kkinnunen7510b222014-07-30 00:04:16 -070047 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000048}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000049#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000050
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000051// Shift matrix components to the left, as we advance pixels to the right.
52inline void shiftMatrixLeft(int m[9]) {
53 m[0] = m[1];
54 m[3] = m[4];
55 m[6] = m[7];
56 m[1] = m[2];
57 m[4] = m[5];
58 m[7] = m[8];
59}
60
61class DiffuseLightingType {
62public:
63 DiffuseLightingType(SkScalar kd)
64 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070065 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
66 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000067 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
68 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
69 SkPoint3 color(lightColor * colorScale);
70 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000071 SkClampMax(SkScalarRoundToInt(color.fX), 255),
72 SkClampMax(SkScalarRoundToInt(color.fY), 255),
73 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000074 }
75private:
76 SkScalar fKD;
77};
78
79class SpecularLightingType {
80public:
81 SpecularLightingType(SkScalar ks, SkScalar shininess)
82 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070083 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
84 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 SkPoint3 halfDir(surfaceTolight);
86 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
87 halfDir.normalize();
88 SkScalar colorScale = SkScalarMul(fKS,
89 SkScalarPow(normal.dot(halfDir), fShininess));
90 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
91 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000092 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
93 SkClampMax(SkScalarRoundToInt(color.fX), 255),
94 SkClampMax(SkScalarRoundToInt(color.fY), 255),
95 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000096 }
97private:
98 SkScalar fKS;
99 SkScalar fShininess;
100};
101
102inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
103 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
104}
105
106inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
107 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
108 SkScalarMul(-y, surfaceScale),
109 SK_Scalar1);
110 vector.normalize();
111 return vector;
112}
113
114inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
116 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
117 surfaceScale);
118}
119
120inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
122 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
123 surfaceScale);
124}
125
126inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
128 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
129 surfaceScale);
130}
131
132inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
134 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
135 surfaceScale);
136}
137
138
139inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
141 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
142 surfaceScale);
143}
144
145inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
147 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
148 surfaceScale);
149}
150
151inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
153 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
159 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
160 surfaceScale);
161}
162
163inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
165 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
166 surfaceScale);
167}
168
joshualittb0a8a372014-09-23 09:50:21 -0700169template <class LightingType, class LightType> void lightBitmap(
170 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
171 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000172 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000173 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000174 int left = bounds.left(), right = bounds.right();
175 int bottom = bounds.bottom();
176 int y = bounds.top();
177 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000178 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000179 int x = left;
180 const SkPMColor* row1 = src.getAddr32(x, y);
181 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000182 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000183 m[4] = SkGetPackedA32(*row1++);
184 m[5] = SkGetPackedA32(*row1++);
185 m[7] = SkGetPackedA32(*row2++);
186 m[8] = SkGetPackedA32(*row2++);
187 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700188 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
189 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000190 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 {
192 shiftMatrixLeft(m);
193 m[5] = SkGetPackedA32(*row1++);
194 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000195 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700196 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
197 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000198 }
199 shiftMatrixLeft(m);
200 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700201 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
202 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000203 }
204
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000205 for (++y; y < bottom - 1; ++y) {
206 int x = left;
207 const SkPMColor* row0 = src.getAddr32(x, y - 1);
208 const SkPMColor* row1 = src.getAddr32(x, y);
209 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000211 m[1] = SkGetPackedA32(*row0++);
212 m[2] = SkGetPackedA32(*row0++);
213 m[4] = SkGetPackedA32(*row1++);
214 m[5] = SkGetPackedA32(*row1++);
215 m[7] = SkGetPackedA32(*row2++);
216 m[8] = SkGetPackedA32(*row2++);
217 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700218 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
219 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000220 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 shiftMatrixLeft(m);
222 m[2] = SkGetPackedA32(*row0++);
223 m[5] = SkGetPackedA32(*row1++);
224 m[8] = SkGetPackedA32(*row2++);
225 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700226 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
227 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000228 }
229 shiftMatrixLeft(m);
230 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700231 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
232 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 }
234
235 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000236 int x = left;
237 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
238 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 int m[9];
240 m[1] = SkGetPackedA32(*row0++);
241 m[2] = SkGetPackedA32(*row0++);
242 m[4] = SkGetPackedA32(*row1++);
243 m[5] = SkGetPackedA32(*row1++);
244 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700245 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
246 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000247 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 {
249 shiftMatrixLeft(m);
250 m[2] = SkGetPackedA32(*row0++);
251 m[5] = SkGetPackedA32(*row1++);
252 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700253 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
254 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000255 }
256 shiftMatrixLeft(m);
257 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700258 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
259 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000260 }
261}
262
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000263SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SkPoint3 point;
265 point.fX = buffer.readScalar();
266 point.fY = buffer.readScalar();
267 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000268 buffer.validate(SkScalarIsFinite(point.fX) &&
269 SkScalarIsFinite(point.fY) &&
270 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271 return point;
272};
273
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000274void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000275 buffer.writeScalar(point.fX);
276 buffer.writeScalar(point.fY);
277 buffer.writeScalar(point.fZ);
278};
279
senorblancod0d37ca2015-04-02 04:54:56 -0700280enum BoundaryMode {
281 kTopLeft_BoundaryMode,
282 kTop_BoundaryMode,
283 kTopRight_BoundaryMode,
284 kLeft_BoundaryMode,
285 kInterior_BoundaryMode,
286 kRight_BoundaryMode,
287 kBottomLeft_BoundaryMode,
288 kBottom_BoundaryMode,
289 kBottomRight_BoundaryMode,
290
291 kBoundaryModeCount,
292};
293
294class SkLightingImageFilterInternal : public SkLightingImageFilter {
295protected:
296 SkLightingImageFilterInternal(SkLight* light,
297 SkScalar surfaceScale,
298 SkImageFilter* input,
299 const CropRect* cropRect)
300 : INHERITED(light, surfaceScale, input, cropRect) {}
301
302#if SK_SUPPORT_GPU
303 bool canFilterImageGPU() const override { return true; }
304 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
305 SkBitmap* result, SkIPoint* offset) const override;
306 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
307 const SkMatrix&,
308 const SkIRect& bounds,
309 BoundaryMode boundaryMode) const = 0;
310#endif
311private:
312#if SK_SUPPORT_GPU
313 void drawRect(GrContext* context,
314 GrTexture* src,
315 GrTexture* dst,
316 const SkMatrix& matrix,
317 const GrClip& clip,
318 const SkRect& dstRect,
319 BoundaryMode boundaryMode,
320 const SkIRect& bounds) const;
321#endif
322 typedef SkLightingImageFilter INHERITED;
323};
324
325#if SK_SUPPORT_GPU
326void SkLightingImageFilterInternal::drawRect(GrContext* context,
327 GrTexture* src,
328 GrTexture* dst,
329 const SkMatrix& matrix,
330 const GrClip& clip,
331 const SkRect& dstRect,
332 BoundaryMode boundaryMode,
333 const SkIRect& bounds) const {
334 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
335 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
336 GrPaint paint;
337 paint.addColorProcessor(fp)->unref();
338 context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
339 dstRect, srcRect);
340}
341
342bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
343 const SkBitmap& src,
344 const Context& ctx,
345 SkBitmap* result,
346 SkIPoint* offset) const {
347 SkBitmap input = src;
348 SkIPoint srcOffset = SkIPoint::Make(0, 0);
349 if (this->getInput(0) &&
350 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
351 return false;
352 }
353 SkIRect bounds;
354 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
355 return false;
356 }
357 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
358 SkIntToScalar(bounds.height()));
359 GrTexture* srcTexture = input.getTexture();
360 GrContext* context = srcTexture->getContext();
361
362 GrSurfaceDesc desc;
363 desc.fFlags = kRenderTarget_GrSurfaceFlag,
364 desc.fWidth = bounds.width();
365 desc.fHeight = bounds.height();
366 desc.fConfig = kRGBA_8888_GrPixelConfig;
367
368 SkAutoTUnref<GrTexture> dst(
369 context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
370 if (!dst) {
371 return false;
372 }
373
374 // setup new clip
375 GrClip clip(dstRect);
376
377 offset->fX = bounds.left();
378 offset->fY = bounds.top();
379 SkMatrix matrix(ctx.ctm());
380 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
381 bounds.offset(-srcOffset);
382 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
383 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
384 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
385 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
386 SkRect interior = dstRect.makeInset(1, 1);
387 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
388 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
389 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
390 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
391 this->drawRect(context, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
392 this->drawRect(context, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
393 this->drawRect(context, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
394 bounds);
395 this->drawRect(context, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
396 this->drawRect(context, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
397 bounds);
398 this->drawRect(context, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
399 this->drawRect(context, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
400 bounds);
401 this->drawRect(context, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
402 this->drawRect(context, srcTexture, dst, matrix, clip, bottomRight, kBottomRight_BoundaryMode,
403 bounds);
404 WrapTexture(dst, bounds.width(), bounds.height(), result);
405 return true;
406}
407#endif
408
409class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000410public:
reed9fa60da2014-08-21 07:59:51 -0700411 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700412 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700413
robertphillipsf3f5bad2014-12-19 13:49:15 -0800414 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000415 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000416 SkScalar kd() const { return fKD; }
417
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000418protected:
reed9fa60da2014-08-21 07:59:51 -0700419 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700420 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700421 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700422 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
423 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000424#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -0700425 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&,
426 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000427#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000428
429private:
reed9fa60da2014-08-21 07:59:51 -0700430 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700431 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000432 SkScalar fKD;
433};
434
senorblancod0d37ca2015-04-02 04:54:56 -0700435class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000436public:
reed9fa60da2014-08-21 07:59:51 -0700437 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700438 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700439
robertphillipsf3f5bad2014-12-19 13:49:15 -0800440 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000441 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
442
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000443 SkScalar ks() const { return fKS; }
444 SkScalar shininess() const { return fShininess; }
445
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000446protected:
reed9fa60da2014-08-21 07:59:51 -0700447 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700448 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700449 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700450 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
451 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000452#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -0700453 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&,
454 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000455#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456
457private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000458 SkScalar fKS;
459 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700460 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700461 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000462};
463
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000464#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000465
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000466class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000467public:
senorblancod0d37ca2015-04-02 04:54:56 -0700468 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale,
469 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000470 virtual ~GrLightingEffect();
471
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000472 const SkLight* light() const { return fLight; }
473 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000474 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700475 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000476
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000477protected:
mtklein36352bf2015-03-25 18:17:31 -0700478 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000479
mtklein36352bf2015-03-25 18:17:31 -0700480 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700481 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800482 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700483 }
484
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000485private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000486 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000487 const SkLight* fLight;
488 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000489 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700490 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000491};
492
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493class GrDiffuseLightingEffect : public GrLightingEffect {
494public:
joshualittb0a8a372014-09-23 09:50:21 -0700495 static GrFragmentProcessor* Create(GrTexture* texture,
496 const SkLight* light,
497 SkScalar surfaceScale,
498 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700499 SkScalar kd,
500 BoundaryMode boundaryMode) {
bsalomon55fad7a2014-07-08 07:34:20 -0700501 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
502 light,
503 surfaceScale,
504 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700505 kd,
506 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000507 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508
mtklein36352bf2015-03-25 18:17:31 -0700509 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510
mtklein36352bf2015-03-25 18:17:31 -0700511 void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000512
mtklein36352bf2015-03-25 18:17:31 -0700513 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800514
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000515 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000516
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000517private:
mtklein36352bf2015-03-25 18:17:31 -0700518 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000519
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000520 GrDiffuseLightingEffect(GrTexture* texture,
521 const SkLight* light,
522 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000523 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700524 SkScalar kd,
525 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000526
joshualittb0a8a372014-09-23 09:50:21 -0700527 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000528 typedef GrLightingEffect INHERITED;
529 SkScalar fKD;
530};
531
532class GrSpecularLightingEffect : public GrLightingEffect {
533public:
joshualittb0a8a372014-09-23 09:50:21 -0700534 static GrFragmentProcessor* Create(GrTexture* texture,
535 const SkLight* light,
536 SkScalar surfaceScale,
537 const SkMatrix& matrix,
538 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700539 SkScalar shininess,
540 BoundaryMode boundaryMode) {
bsalomon55fad7a2014-07-08 07:34:20 -0700541 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
542 light,
543 surfaceScale,
544 matrix,
545 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700546 shininess,
547 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000548 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000549
mtklein36352bf2015-03-25 18:17:31 -0700550 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000551
mtklein36352bf2015-03-25 18:17:31 -0700552 void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800553
mtklein36352bf2015-03-25 18:17:31 -0700554 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800555
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000556 SkScalar ks() const { return fKS; }
557 SkScalar shininess() const { return fShininess; }
558
559private:
mtklein36352bf2015-03-25 18:17:31 -0700560 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000561
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000562 GrSpecularLightingEffect(GrTexture* texture,
563 const SkLight* light,
564 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000565 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000566 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700567 SkScalar shininess,
568 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000569
joshualittb0a8a372014-09-23 09:50:21 -0700570 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000571 typedef GrLightingEffect INHERITED;
572 SkScalar fKS;
573 SkScalar fShininess;
574};
575
576///////////////////////////////////////////////////////////////////////////////
577
578class GrGLLight {
579public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000580 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000581
582 /**
583 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
584 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
585 */
joshualitt15988992014-10-09 15:04:05 -0700586 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000587
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000588 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000589 * These two functions are called from GrGLLightingEffect's emitCode() function.
590 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
591 * the light. The expression will be used in the FS. emitLightColor writes an expression into
592 * the FS that is the color of the light. Either function may add functions and/or uniforms to
593 * the FS. The default of emitLightColor appends the name of the constant light color uniform
594 * and so this function only needs to be overridden if the light color varies spatially.
595 */
joshualitt15988992014-10-09 15:04:05 -0700596 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
597 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000598
599 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
600 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700601 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000602 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000603
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000604protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000605 /**
606 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
607 * function.
608 */
609 UniformHandle lightColorUni() const { return fColorUni; }
610
611private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000612 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000613
614 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000615};
616
617///////////////////////////////////////////////////////////////////////////////
618
619class GrGLDistantLight : public GrGLLight {
620public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000621 virtual ~GrGLDistantLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700622 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700623 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000624
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625private:
626 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000627 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000628};
629
630///////////////////////////////////////////////////////////////////////////////
631
632class GrGLPointLight : public GrGLLight {
633public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000634 virtual ~GrGLPointLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700635 void setData(const GrGLProgramDataManager&, const SkLight* 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 fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000641};
642
643///////////////////////////////////////////////////////////////////////////////
644
645class GrGLSpotLight : public GrGLLight {
646public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000647 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700648 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700649 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
650 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000651
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000652private:
653 typedef GrGLLight INHERITED;
654
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000655 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000656 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000657 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000658 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000659 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000660 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000661 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000663#else
664
665class GrGLLight;
666
667#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000668
669};
670
671///////////////////////////////////////////////////////////////////////////////
672
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000673class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000674public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000675 SK_DECLARE_INST_COUNT(SkLight)
676
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000677 enum LightType {
678 kDistant_LightType,
679 kPoint_LightType,
680 kSpot_LightType,
681 };
682 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000683 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000684 virtual GrGLLight* createGLLight() const = 0;
685 virtual bool isEqual(const SkLight& other) const {
686 return fColor == other.fColor;
687 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000688 // Called to know whether the generated GrGLLight will require access to the fragment position.
689 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000690 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000692 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000693 void flattenLight(SkWriteBuffer& buffer) const;
694 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000695
djsollen@google.com08337772012-06-26 14:33:13 +0000696protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000697 SkLight(SkColor color)
698 : fColor(SkIntToScalar(SkColorGetR(color)),
699 SkIntToScalar(SkColorGetG(color)),
700 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000701 SkLight(const SkPoint3& color)
702 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000703 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000704 fColor = readPoint3(buffer);
705 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000706
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000707 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000708
djsollen@google.com08337772012-06-26 14:33:13 +0000709
710private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000711 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000712 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000713};
714
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000715///////////////////////////////////////////////////////////////////////////////
716
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000717class SkDistantLight : public SkLight {
718public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000719 SkDistantLight(const SkPoint3& direction, SkColor color)
720 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000721 }
djsollen@google.com08337772012-06-26 14:33:13 +0000722
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000723 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
724 return fDirection;
725 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000726 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700727 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000728 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700729 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000730#if SK_SUPPORT_GPU
731 return SkNEW(GrGLDistantLight);
732#else
733 SkDEBUGFAIL("Should not call in GPU-less build");
734 return NULL;
735#endif
736 }
mtklein36352bf2015-03-25 18:17:31 -0700737 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000738
mtklein36352bf2015-03-25 18:17:31 -0700739 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000740 if (other.type() != kDistant_LightType) {
741 return false;
742 }
743
744 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
745 return INHERITED::isEqual(other) &&
746 fDirection == o.fDirection;
747 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000748
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000749 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000750 fDirection = readPoint3(buffer);
751 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000752
djsollen@google.com08337772012-06-26 14:33:13 +0000753protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000754 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
755 : INHERITED(color), fDirection(direction) {
756 }
mtklein36352bf2015-03-25 18:17:31 -0700757 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000758 return new SkDistantLight(direction(), color());
759 }
mtklein36352bf2015-03-25 18:17:31 -0700760 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000761 writePoint3(fDirection, buffer);
762 }
763
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000764private:
djsollen@google.com08337772012-06-26 14:33:13 +0000765 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000766 SkPoint3 fDirection;
767};
768
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000769///////////////////////////////////////////////////////////////////////////////
770
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000771class SkPointLight : public SkLight {
772public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000773 SkPointLight(const SkPoint3& location, SkColor color)
774 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000775
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000776 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
777 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
778 fLocation.fY - SkIntToScalar(y),
779 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
780 direction.normalize();
781 return direction;
782 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000783 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700784 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000785 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700786 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000787#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000788 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000789#else
790 SkDEBUGFAIL("Should not call in GPU-less build");
791 return NULL;
792#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000793 }
mtklein36352bf2015-03-25 18:17:31 -0700794 bool requiresFragmentPosition() const override { return true; }
795 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000796 if (other.type() != kPoint_LightType) {
797 return false;
798 }
799 const SkPointLight& o = static_cast<const SkPointLight&>(other);
800 return INHERITED::isEqual(other) &&
801 fLocation == o.fLocation;
802 }
mtklein36352bf2015-03-25 18:17:31 -0700803 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000804 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
805 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000806 // Use X scale and Y scale on Z and average the result
807 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
808 matrix.mapVectors(&locationZ, 1);
809 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000810 return new SkPointLight(location, color());
811 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000812
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000813 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000814 fLocation = readPoint3(buffer);
815 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000816
817protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000818 SkPointLight(const SkPoint3& location, const SkPoint3& color)
819 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700820 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000821 writePoint3(fLocation, buffer);
822 }
823
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000824private:
djsollen@google.com08337772012-06-26 14:33:13 +0000825 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000826 SkPoint3 fLocation;
827};
828
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000829///////////////////////////////////////////////////////////////////////////////
830
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000831class SkSpotLight : public SkLight {
832public:
senorblancod0d37ca2015-04-02 04:54:56 -0700833 SkSpotLight(const SkPoint3& location,
834 const SkPoint3& target,
835 SkScalar specularExponent,
836 SkScalar cutoffAngle,
837 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000838 : INHERITED(color),
839 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000840 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000841 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000842 {
843 fS = target - location;
844 fS.normalize();
845 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000846 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000847 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
848 fConeScale = SkScalarInvert(antiAliasThreshold);
849 }
djsollen@google.com08337772012-06-26 14:33:13 +0000850
mtklein36352bf2015-03-25 18:17:31 -0700851 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000852 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
853 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000854 // Use X scale and Y scale on Z and average the result
855 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
856 matrix.mapVectors(&locationZ, 1);
857 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000858 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
859 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000860 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
861 matrix.mapVectors(&targetZ, 1);
862 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
863 SkPoint3 s = target - location;
864 s.normalize();
senorblancod0d37ca2015-04-02 04:54:56 -0700865 return new SkSpotLight(location,
866 target,
867 fSpecularExponent,
868 fCosOuterConeAngle,
869 fCosInnerConeAngle,
870 fConeScale,
871 s,
872 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000873 }
874
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000875 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
876 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
877 fLocation.fY - SkIntToScalar(y),
878 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
879 direction.normalize();
880 return direction;
881 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000882 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000883 SkScalar cosAngle = -surfaceToLight.dot(fS);
884 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000885 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000886 }
887 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
888 if (cosAngle < fCosInnerConeAngle) {
889 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000890 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000891 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000892 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000893 }
mtklein36352bf2015-03-25 18:17:31 -0700894 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000895#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000896 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000897#else
898 SkDEBUGFAIL("Should not call in GPU-less build");
899 return NULL;
900#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000901 }
mtklein36352bf2015-03-25 18:17:31 -0700902 bool requiresFragmentPosition() const override { return true; }
903 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000904 const SkPoint3& location() const { return fLocation; }
905 const SkPoint3& target() const { return fTarget; }
906 SkScalar specularExponent() const { return fSpecularExponent; }
907 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
908 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
909 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000910 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000911
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000912 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000913 fLocation = readPoint3(buffer);
914 fTarget = readPoint3(buffer);
915 fSpecularExponent = buffer.readScalar();
916 fCosOuterConeAngle = buffer.readScalar();
917 fCosInnerConeAngle = buffer.readScalar();
918 fConeScale = buffer.readScalar();
919 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000920 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
921 SkScalarIsFinite(fCosOuterConeAngle) &&
922 SkScalarIsFinite(fCosInnerConeAngle) &&
923 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000924 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000925protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700926 SkSpotLight(const SkPoint3& location,
927 const SkPoint3& target,
928 SkScalar specularExponent,
929 SkScalar cosOuterConeAngle,
930 SkScalar cosInnerConeAngle,
931 SkScalar coneScale,
932 const SkPoint3& s,
933 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000934 : INHERITED(color),
935 fLocation(location),
936 fTarget(target),
937 fSpecularExponent(specularExponent),
938 fCosOuterConeAngle(cosOuterConeAngle),
939 fCosInnerConeAngle(cosInnerConeAngle),
940 fConeScale(coneScale),
941 fS(s)
942 {
943 }
mtklein36352bf2015-03-25 18:17:31 -0700944 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000945 writePoint3(fLocation, buffer);
946 writePoint3(fTarget, buffer);
947 buffer.writeScalar(fSpecularExponent);
948 buffer.writeScalar(fCosOuterConeAngle);
949 buffer.writeScalar(fCosInnerConeAngle);
950 buffer.writeScalar(fConeScale);
951 writePoint3(fS, buffer);
952 }
953
mtklein36352bf2015-03-25 18:17:31 -0700954 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000955 if (other.type() != kSpot_LightType) {
956 return false;
957 }
958
959 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
960 return INHERITED::isEqual(other) &&
961 fLocation == o.fLocation &&
962 fTarget == o.fTarget &&
963 fSpecularExponent == o.fSpecularExponent &&
964 fCosOuterConeAngle == o.fCosOuterConeAngle;
965 }
966
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000967private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000968 static const SkScalar kSpecularExponentMin;
969 static const SkScalar kSpecularExponentMax;
970
djsollen@google.com08337772012-06-26 14:33:13 +0000971 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000972 SkPoint3 fLocation;
973 SkPoint3 fTarget;
974 SkScalar fSpecularExponent;
975 SkScalar fCosOuterConeAngle;
976 SkScalar fCosInnerConeAngle;
977 SkScalar fConeScale;
978 SkPoint3 fS;
979};
980
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000981// According to the spec, the specular term should be in the range [1, 128] :
982// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000983const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
984const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000985
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000986///////////////////////////////////////////////////////////////////////////////
987
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000988void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000989 // Write type first, then baseclass, then subclass.
990 buffer.writeInt(this->type());
991 writePoint3(fColor, buffer);
992 this->onFlattenLight(buffer);
993}
994
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000995/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000996 // Read type first.
997 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
998 switch (type) {
999 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1000 // then subclass, same order as flattenLight.
1001 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1002 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1003 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1004 default:
1005 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001006 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001007 return NULL;
1008 }
1009}
1010///////////////////////////////////////////////////////////////////////////////
1011
senorblanco9ea3d572014-07-08 09:16:22 -07001012SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001013 SkImageFilter* input, const CropRect* cropRect)
1014 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001015 , fLight(SkRef(light))
1016 , fSurfaceScale(surfaceScale / 255)
1017{}
1018
1019SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1020 SkColor lightColor,
1021 SkScalar surfaceScale,
1022 SkScalar kd,
1023 SkImageFilter* input,
1024 const CropRect* cropRect) {
1025 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1026 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001027}
1028
reed9fa60da2014-08-21 07:59:51 -07001029SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1030 SkColor lightColor,
1031 SkScalar surfaceScale,
1032 SkScalar kd,
1033 SkImageFilter* input,
1034 const CropRect* cropRect) {
1035 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1036 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001037}
1038
reed9fa60da2014-08-21 07:59:51 -07001039SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1040 const SkPoint3& target,
1041 SkScalar specularExponent,
1042 SkScalar cutoffAngle,
1043 SkColor lightColor,
1044 SkScalar surfaceScale,
1045 SkScalar kd,
1046 SkImageFilter* input,
1047 const CropRect* cropRect) {
1048 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1049 cutoffAngle, lightColor)));
1050 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001051}
1052
reed9fa60da2014-08-21 07:59:51 -07001053SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1054 SkColor lightColor,
1055 SkScalar surfaceScale,
1056 SkScalar ks,
1057 SkScalar shine,
1058 SkImageFilter* input,
1059 const CropRect* cropRect) {
1060 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1061 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001062}
1063
reed9fa60da2014-08-21 07:59:51 -07001064SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1065 SkColor lightColor,
1066 SkScalar surfaceScale,
1067 SkScalar ks,
1068 SkScalar shine,
1069 SkImageFilter* input,
1070 const CropRect* cropRect) {
1071 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1072 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001073}
1074
reed9fa60da2014-08-21 07:59:51 -07001075SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1076 const SkPoint3& target,
1077 SkScalar specularExponent,
1078 SkScalar cutoffAngle,
1079 SkColor lightColor,
1080 SkScalar surfaceScale,
1081 SkScalar ks,
1082 SkScalar shine,
1083 SkImageFilter* input,
1084 const CropRect* cropRect) {
1085 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1086 cutoffAngle, lightColor)));
1087 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 -07001090SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001091
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001092void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001093 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001094 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001095 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001096}
1097
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001098///////////////////////////////////////////////////////////////////////////////
1099
reed9fa60da2014-08-21 07:59:51 -07001100SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001101 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001102 if (NULL == light) {
1103 return NULL;
1104 }
1105 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1106 return NULL;
1107 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001108 // According to the spec, kd can be any non-negative number :
1109 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001110 if (kd < 0) {
1111 return NULL;
1112 }
senorblanco24e06d52015-03-18 12:11:33 -07001113 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001114}
1115
senorblancod0d37ca2015-04-02 04:54:56 -07001116SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1117 SkScalar surfaceScale,
1118 SkScalar kd,
1119 SkImageFilter* input,
1120 const CropRect* cropRect)
1121 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001122 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001123{
1124}
1125
reed9fa60da2014-08-21 07:59:51 -07001126SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1127 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1128 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1129 SkScalar surfaceScale = buffer.readScalar();
1130 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001131 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001132}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001133
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001134void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001135 this->INHERITED::flatten(buffer);
1136 buffer.writeScalar(fKD);
1137}
1138
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001139bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1140 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001141 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001142 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001143 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001144 SkImageFilter* input = getInput(0);
1145 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001146 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001147 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001148 return false;
1149 }
1150
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001151 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001152 return false;
1153 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001154 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001155 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001156 return false;
1157 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001158
1159 if (bounds.width() < 2 || bounds.height() < 2) {
1160 return false;
1161 }
1162
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001163 SkAutoLockPixels alp(src);
1164 if (!src.getPixels()) {
1165 return false;
1166 }
1167
reed84825042014-09-02 12:50:45 -07001168 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001169 return false;
1170 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001171
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001172 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001173
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001174 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001175 offset->fX = bounds.left();
1176 offset->fY = bounds.top();
1177 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001178 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001179 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001180 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1181 transformedLight,
1182 src,
1183 dst,
1184 surfaceScale(),
1185 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001186 break;
1187 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001188 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1189 transformedLight,
1190 src,
1191 dst,
1192 surfaceScale(),
1193 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001194 break;
1195 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001196 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1197 transformedLight,
1198 src,
1199 dst,
1200 surfaceScale(),
1201 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001202 break;
1203 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001204
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001205 return true;
1206}
1207
robertphillipsf3f5bad2014-12-19 13:49:15 -08001208#ifndef SK_IGNORE_TO_STRING
1209void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1210 str->appendf("SkDiffuseLightingImageFilter: (");
1211 str->appendf("kD: %f\n", fKD);
1212 str->append(")");
1213}
1214#endif
1215
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001216#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001217GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualittb0a8a372014-09-23 09:50:21 -07001218 GrTexture* texture,
1219 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001220 const SkIRect&,
1221 BoundaryMode boundaryMode
1222) const {
1223 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1224 return GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001225}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001226#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001227
1228///////////////////////////////////////////////////////////////////////////////
1229
reed9fa60da2014-08-21 07:59:51 -07001230SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001231 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001232 if (NULL == light) {
1233 return NULL;
1234 }
1235 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1236 return NULL;
1237 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001238 // According to the spec, ks can be any non-negative number :
1239 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001240 if (ks < 0) {
1241 return NULL;
1242 }
1243 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001244 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001245}
1246
senorblancod0d37ca2015-04-02 04:54:56 -07001247SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1248 SkScalar surfaceScale,
1249 SkScalar ks,
1250 SkScalar shininess,
1251 SkImageFilter* input,
1252 const CropRect* cropRect)
1253 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001254 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001255 fShininess(shininess)
1256{
1257}
1258
reed9fa60da2014-08-21 07:59:51 -07001259SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1260 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1261 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1262 SkScalar surfaceScale = buffer.readScalar();
1263 SkScalar ks = buffer.readScalar();
1264 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001265 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001266}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001267
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001268void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001269 this->INHERITED::flatten(buffer);
1270 buffer.writeScalar(fKS);
1271 buffer.writeScalar(fShininess);
1272}
1273
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001274bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1275 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001276 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001277 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001278 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001279 SkImageFilter* input = getInput(0);
1280 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001281 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001282 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001283 return false;
1284 }
1285
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001286 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001287 return false;
1288 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001289
1290 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001291 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001292 return false;
1293 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001294
1295 if (bounds.width() < 2 || bounds.height() < 2) {
1296 return false;
1297 }
1298
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001299 SkAutoLockPixels alp(src);
1300 if (!src.getPixels()) {
1301 return false;
1302 }
1303
reed84825042014-09-02 12:50:45 -07001304 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001305 return false;
1306 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001307
1308 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001309 offset->fX = bounds.left();
1310 offset->fY = bounds.top();
1311 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001312 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001313 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001314 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001315 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1316 transformedLight,
1317 src,
1318 dst,
1319 surfaceScale(),
1320 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001321 break;
1322 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001323 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1324 transformedLight,
1325 src,
1326 dst,
1327 surfaceScale(),
1328 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001329 break;
1330 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001331 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1332 transformedLight,
1333 src,
1334 dst,
1335 surfaceScale(),
1336 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001337 break;
1338 }
1339 return true;
1340}
1341
robertphillipsf3f5bad2014-12-19 13:49:15 -08001342#ifndef SK_IGNORE_TO_STRING
1343void SkSpecularLightingImageFilter::toString(SkString* str) const {
1344 str->appendf("SkSpecularLightingImageFilter: (");
1345 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1346 str->append(")");
1347}
1348#endif
1349
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001350#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001351GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
1352 GrTexture* texture,
1353 const SkMatrix& matrix,
1354 const SkIRect&,
1355 BoundaryMode boundaryMode) const {
1356 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1357 return GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess(),
1358 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001359}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001360#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001361
1362///////////////////////////////////////////////////////////////////////////////
1363
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001364#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001365
1366namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001367SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001368 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1369 SkScalarToFloat(random->nextSScalar1()),
1370 SkScalarToFloat(random->nextSScalar1()));
1371}
1372
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001373SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001374 int type = random->nextULessThan(3);
1375 switch (type) {
1376 case 0: {
1377 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1378 }
1379 case 1: {
1380 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1381 }
1382 case 2: {
1383 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1384 random_point3(random),
1385 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001386 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001387 random->nextU()));
1388 }
1389 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001390 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001391 return NULL;
1392 }
1393}
1394
senorblancod0d37ca2015-04-02 04:54:56 -07001395SkString emitNormalFunc(BoundaryMode mode,
1396 const char* pointToNormalName,
1397 const char* sobelFuncName) {
1398 SkString result;
1399 switch (mode) {
1400 case kTopLeft_BoundaryMode:
1401 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1402 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1403 "\t surfaceScale);\n",
1404 pointToNormalName, sobelFuncName, gTwoThirds,
1405 sobelFuncName, gTwoThirds);
1406 break;
1407 case kTop_BoundaryMode:
1408 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1409 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1410 "\t surfaceScale);\n",
1411 pointToNormalName, sobelFuncName, gOneThird,
1412 sobelFuncName, gOneHalf);
1413 break;
1414 case kTopRight_BoundaryMode:
1415 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1416 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1417 "\t surfaceScale);\n",
1418 pointToNormalName, sobelFuncName, gTwoThirds,
1419 sobelFuncName, gTwoThirds);
1420 break;
1421 case kLeft_BoundaryMode:
1422 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1423 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1424 "\t surfaceScale);\n",
1425 pointToNormalName, sobelFuncName, gOneHalf,
1426 sobelFuncName, gOneThird);
1427 break;
1428 case kInterior_BoundaryMode:
1429 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1430 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1431 "\t surfaceScale);\n",
1432 pointToNormalName, sobelFuncName, gOneQuarter,
1433 sobelFuncName, gOneQuarter);
1434 break;
1435 case kRight_BoundaryMode:
1436 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1437 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1438 "\t surfaceScale);\n",
1439 pointToNormalName, sobelFuncName, gOneHalf,
1440 sobelFuncName, gOneThird);
1441 break;
1442 case kBottomLeft_BoundaryMode:
1443 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1444 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1445 "\t surfaceScale);\n",
1446 pointToNormalName, sobelFuncName, gTwoThirds,
1447 sobelFuncName, gTwoThirds);
1448 break;
1449 case kBottom_BoundaryMode:
1450 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1451 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1452 "\t surfaceScale);\n",
1453 pointToNormalName, sobelFuncName, gOneThird,
1454 sobelFuncName, gOneHalf);
1455 break;
1456 case kBottomRight_BoundaryMode:
1457 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1458 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1459 "\t surfaceScale);\n",
1460 pointToNormalName, sobelFuncName, gTwoThirds,
1461 sobelFuncName, gTwoThirds);
1462 break;
1463 default:
1464 SkASSERT(false);
1465 break;
1466 }
1467 return result;
1468}
1469
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001470}
1471
joshualittb0a8a372014-09-23 09:50:21 -07001472class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001473public:
joshualitteb2a6762014-12-04 11:35:33 -08001474 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001475 virtual ~GrGLLightingEffect();
1476
senorblancod0d37ca2015-04-02 04:54:56 -07001477 void emitCode(GrGLFPBuilder*,
1478 const GrFragmentProcessor&,
1479 const char* outputColor,
1480 const char* inputColor,
1481 const TransformedCoordsArray&,
1482 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001483
joshualittb0a8a372014-09-23 09:50:21 -07001484 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001485
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001486 /**
1487 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1488 */
mtklein36352bf2015-03-25 18:17:31 -07001489 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001490
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001491protected:
joshualitt15988992014-10-09 15:04:05 -07001492 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001493
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001494private:
joshualittb0a8a372014-09-23 09:50:21 -07001495 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001496
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001497 UniformHandle fImageIncrementUni;
1498 UniformHandle fSurfaceScaleUni;
1499 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001500 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001501};
1502
1503///////////////////////////////////////////////////////////////////////////////
1504
1505class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1506public:
joshualitteb2a6762014-12-04 11:35:33 -08001507 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001508 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1509 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001510
1511private:
1512 typedef GrGLLightingEffect INHERITED;
1513
bsalomon@google.com032b2212012-07-16 13:36:18 +00001514 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001515};
1516
1517///////////////////////////////////////////////////////////////////////////////
1518
1519class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1520public:
joshualitteb2a6762014-12-04 11:35:33 -08001521 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001522 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1523 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001524
1525private:
1526 typedef GrGLLightingEffect INHERITED;
1527
bsalomon@google.com032b2212012-07-16 13:36:18 +00001528 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001529 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001530};
1531
1532///////////////////////////////////////////////////////////////////////////////
1533
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001534GrLightingEffect::GrLightingEffect(GrTexture* texture,
1535 const SkLight* light,
1536 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001537 const SkMatrix& matrix,
1538 BoundaryMode boundaryMode)
bsalomon6267f812014-08-29 15:05:53 -07001539 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001540 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001541 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001542 , fFilterMatrix(matrix)
1543 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001544 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001545 if (light->requiresFragmentPosition()) {
1546 this->setWillReadFragmentPosition();
1547 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001548}
1549
1550GrLightingEffect::~GrLightingEffect() {
1551 fLight->unref();
1552}
1553
bsalomon0e08fc12014-10-15 08:19:04 -07001554bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001555 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001556 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001557 fSurfaceScale == s.fSurfaceScale &&
1558 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001559}
1560
1561///////////////////////////////////////////////////////////////////////////////
1562
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001563GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1564 const SkLight* light,
1565 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001566 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001567 SkScalar kd,
1568 BoundaryMode boundaryMode)
1569 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001570 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001571}
1572
bsalomon0e08fc12014-10-15 08:19:04 -07001573bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001574 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001575 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001576 this->kd() == s.kd();
1577}
1578
joshualitteb2a6762014-12-04 11:35:33 -08001579void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1580 GrProcessorKeyBuilder* b) const {
1581 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1582}
1583
1584GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1585 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1586}
1587
joshualittb0a8a372014-09-23 09:50:21 -07001588GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001589
joshualittb0a8a372014-09-23 09:50:21 -07001590GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001591 GrContext* context,
1592 const GrDrawTargetCaps&,
1593 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001594 SkScalar surfaceScale = random->nextSScalar1();
1595 SkScalar kd = random->nextUScalar1();
1596 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001597 SkMatrix matrix;
1598 for (int i = 0; i < 9; i++) {
1599 matrix[i] = random->nextUScalar1();
1600 }
senorblancod0d37ca2015-04-02 04:54:56 -07001601 BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount);
joshualittb0a8a372014-09-23 09:50:21 -07001602 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001603 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001604}
1605
1606
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001607///////////////////////////////////////////////////////////////////////////////
1608
joshualitteb2a6762014-12-04 11:35:33 -08001609GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001610 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001611 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001612 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001613}
1614
1615GrGLLightingEffect::~GrGLLightingEffect() {
1616 delete fLight;
1617}
1618
joshualitt15988992014-10-09 15:04:05 -07001619void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001620 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001621 const char* outputColor,
1622 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001623 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001624 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001625 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001626 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001627 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001628 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001629 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001630 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001631 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001632 SkString lightFunc;
1633 this->emitLightFunc(builder, &lightFunc);
1634 static const GrGLShaderVar gSobelArgs[] = {
1635 GrGLShaderVar("a", kFloat_GrSLType),
1636 GrGLShaderVar("b", kFloat_GrSLType),
1637 GrGLShaderVar("c", kFloat_GrSLType),
1638 GrGLShaderVar("d", kFloat_GrSLType),
1639 GrGLShaderVar("e", kFloat_GrSLType),
1640 GrGLShaderVar("f", kFloat_GrSLType),
1641 GrGLShaderVar("scale", kFloat_GrSLType),
1642 };
1643 SkString sobelFuncName;
joshualitt15988992014-10-09 15:04:05 -07001644 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001645 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1646
1647 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001648 "sobel",
1649 SK_ARRAY_COUNT(gSobelArgs),
1650 gSobelArgs,
1651 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1652 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001653 static const GrGLShaderVar gPointToNormalArgs[] = {
1654 GrGLShaderVar("x", kFloat_GrSLType),
1655 GrGLShaderVar("y", kFloat_GrSLType),
1656 GrGLShaderVar("scale", kFloat_GrSLType),
1657 };
1658 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001659 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001660 "pointToNormal",
1661 SK_ARRAY_COUNT(gPointToNormalArgs),
1662 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001663 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001664 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001665
1666 static const GrGLShaderVar gInteriorNormalArgs[] = {
1667 GrGLShaderVar("m", kFloat_GrSLType, 9),
1668 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1669 };
senorblancod0d37ca2015-04-02 04:54:56 -07001670 SkString normalBody = emitNormalFunc(fBoundaryMode,
1671 pointToNormalName.c_str(),
1672 sobelFuncName.c_str());
1673 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001674 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001675 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001676 SK_ARRAY_COUNT(gInteriorNormalArgs),
1677 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001678 normalBody.c_str(),
1679 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001680
joshualitt30ba4362014-08-21 20:18:45 -07001681 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1682 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001683
1684 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1685 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1686
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001687 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001688 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001689 for (int dx = -1; dx <= 1; dx++) {
1690 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001691 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001692 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1693 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1694 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001695 }
1696 }
joshualitt30ba4362014-08-21 20:18:45 -07001697 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001698 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001699 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001700 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001701 fsBuilder->codeAppend(";\n");
1702 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
senorblancod0d37ca2015-04-02 04:54:56 -07001703 outputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001704 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001705 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001706 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001707 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001708 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001709}
1710
joshualittb0a8a372014-09-23 09:50:21 -07001711void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1712 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001713 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1714 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001715}
1716
kkinnunen7510b222014-07-30 00:04:16 -07001717void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001718 const GrProcessor& proc) {
1719 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001720 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001721 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001722 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1723 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001724 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001725 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001726}
1727
1728///////////////////////////////////////////////////////////////////////////////
1729
1730///////////////////////////////////////////////////////////////////////////////
1731
joshualitteb2a6762014-12-04 11:35:33 -08001732GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1733 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001734}
1735
joshualitt15988992014-10-09 15:04:05 -07001736void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001737 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001738 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001739 kFloat_GrSLType, kDefault_GrSLPrecision,
1740 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001741
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001742 static const GrGLShaderVar gLightArgs[] = {
1743 GrGLShaderVar("normal", kVec3f_GrSLType),
1744 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1745 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1746 };
1747 SkString lightBody;
1748 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1749 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001750 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1751 "light",
1752 SK_ARRAY_COUNT(gLightArgs),
1753 gLightArgs,
1754 lightBody.c_str(),
1755 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001756}
1757
kkinnunen7510b222014-07-30 00:04:16 -07001758void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001759 const GrProcessor& proc) {
1760 INHERITED::setData(pdman, proc);
1761 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001762 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001763}
1764
1765///////////////////////////////////////////////////////////////////////////////
1766
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001767GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1768 const SkLight* light,
1769 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001770 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001771 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001772 SkScalar shininess,
1773 BoundaryMode boundaryMode)
1774 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001775 fKS(ks),
1776 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001777 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001778}
1779
bsalomon0e08fc12014-10-15 08:19:04 -07001780bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001781 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001782 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001783 this->ks() == s.ks() &&
1784 this->shininess() == s.shininess();
1785}
1786
joshualitteb2a6762014-12-04 11:35:33 -08001787void GrSpecularLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1788 GrProcessorKeyBuilder* b) const {
1789 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1790}
1791
1792GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1793 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1794}
1795
joshualittb0a8a372014-09-23 09:50:21 -07001796GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001797
joshualittb0a8a372014-09-23 09:50:21 -07001798GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1799 GrContext* context,
1800 const GrDrawTargetCaps&,
1801 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001802 SkScalar surfaceScale = random->nextSScalar1();
1803 SkScalar ks = random->nextUScalar1();
1804 SkScalar shininess = random->nextUScalar1();
1805 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001806 SkMatrix matrix;
1807 for (int i = 0; i < 9; i++) {
1808 matrix[i] = random->nextUScalar1();
1809 }
senorblancod0d37ca2015-04-02 04:54:56 -07001810 BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount);
joshualittb0a8a372014-09-23 09:50:21 -07001811 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001812 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001813}
1814
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001815///////////////////////////////////////////////////////////////////////////////
1816
joshualitteb2a6762014-12-04 11:35:33 -08001817GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1818 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001819}
1820
joshualitt15988992014-10-09 15:04:05 -07001821void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001822 const char* ks;
1823 const char* shininess;
1824
joshualitt30ba4362014-08-21 20:18:45 -07001825 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001826 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001827 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001828 kFloat_GrSLType,
1829 kDefault_GrSLPrecision,
1830 "Shininess",
1831 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001832
1833 static const GrGLShaderVar gLightArgs[] = {
1834 GrGLShaderVar("normal", kVec3f_GrSLType),
1835 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1836 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1837 };
1838 SkString lightBody;
1839 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1840 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001841 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1842 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001843 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1844 "light",
1845 SK_ARRAY_COUNT(gLightArgs),
1846 gLightArgs,
1847 lightBody.c_str(),
1848 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001849}
1850
kkinnunen7510b222014-07-30 00:04:16 -07001851void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001852 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001853 INHERITED::setData(pdman, effect);
1854 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001855 pdman.set1f(fKSUni, spec.ks());
1856 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001857}
1858
1859///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001860void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001861 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001862 kVec3f_GrSLType, kDefault_GrSLPrecision,
1863 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001864}
1865
joshualitt15988992014-10-09 15:04:05 -07001866void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001867 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001868 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001869}
1870
kkinnunen7510b222014-07-30 00:04:16 -07001871void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001872 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001873 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001874}
1875
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001876///////////////////////////////////////////////////////////////////////////////
1877
kkinnunen7510b222014-07-30 00:04:16 -07001878void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001879 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001880 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001881 SkASSERT(light->type() == SkLight::kDistant_LightType);
1882 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001883 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001884}
1885
joshualitt15988992014-10-09 15:04:05 -07001886void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001887 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001888 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1889 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001890 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001891 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001892}
1893
1894///////////////////////////////////////////////////////////////////////////////
1895
kkinnunen7510b222014-07-30 00:04:16 -07001896void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001897 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001898 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001899 SkASSERT(light->type() == SkLight::kPoint_LightType);
1900 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001901 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001902}
1903
joshualitt15988992014-10-09 15:04:05 -07001904void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001905 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001906 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1907 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001908 "LightLocation", &loc);
joshualitt15988992014-10-09 15:04:05 -07001909 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001910 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1911 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001912}
1913
1914///////////////////////////////////////////////////////////////////////////////
1915
kkinnunen7510b222014-07-30 00:04:16 -07001916void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001917 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001918 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001919 SkASSERT(light->type() == SkLight::kSpot_LightType);
1920 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001921 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1922 pdman.set1f(fExponentUni, spotLight->specularExponent());
1923 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1924 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1925 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1926 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001927}
1928
joshualitt15988992014-10-09 15:04:05 -07001929void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001930 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001931 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001932 kVec3f_GrSLType, kDefault_GrSLPrecision,
1933 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001934
joshualitt15988992014-10-09 15:04:05 -07001935 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001936 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1937 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001938}
1939
joshualitt15988992014-10-09 15:04:05 -07001940void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001941 const char *surfaceToLight) {
1942
1943 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1944
1945 const char* exponent;
1946 const char* cosInner;
1947 const char* cosOuter;
1948 const char* coneScale;
1949 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001950 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001951 kFloat_GrSLType, kDefault_GrSLPrecision,
1952 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001953 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001954 kFloat_GrSLType, kDefault_GrSLPrecision,
1955 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001956 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001957 kFloat_GrSLType, kDefault_GrSLPrecision,
1958 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001959 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001960 kFloat_GrSLType, kDefault_GrSLPrecision,
1961 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001962 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001963 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001964
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001965 static const GrGLShaderVar gLightColorArgs[] = {
1966 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1967 };
1968 SkString lightColorBody;
1969 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1970 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1971 lightColorBody.appendf("\t\treturn vec3(0);\n");
1972 lightColorBody.appendf("\t}\n");
1973 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1974 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1975 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1976 color, cosOuter, coneScale);
1977 lightColorBody.appendf("\t}\n");
1978 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt15988992014-10-09 15:04:05 -07001979 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001980 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001981 "lightColor",
1982 SK_ARRAY_COUNT(gLightColorArgs),
1983 gLightColorArgs,
1984 lightColorBody.c_str(),
1985 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001986
joshualitt30ba4362014-08-21 20:18:45 -07001987 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001988}
1989
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001990#endif
1991
djsollen@google.com08337772012-06-26 14:33:13 +00001992SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1993 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1994 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001995SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END