blob: 3e6a903eabebb249838629ae913df9a210b61a2d [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
kkinnunencabe20c2015-06-01 01:37:26 -070018#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070019#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
21#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070022#include "GrPaint.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000023#include "effects/GrSingleTextureEffect.h"
joshualittb0a8a372014-09-23 09:50:21 -070024#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070025#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000026
27class GrGLDiffuseLightingEffect;
28class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000029
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000030// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070031typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000032#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000033
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000034namespace {
35
reed80ea19c2015-05-12 10:37:34 -070036const SkScalar gOneThird = SkIntToScalar(1) / 3;
37const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000038const SkScalar gOneHalf = 0.5f;
39const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000040
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000041#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070042void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
43 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000044 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070045 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000046}
47
joshualittb0a8a372014-09-23 09:50:21 -070048void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
49 const SkPoint3& point) {
kkinnunen7510b222014-07-30 00:04:16 -070050 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000051}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000052#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000053
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000054// Shift matrix components to the left, as we advance pixels to the right.
55inline void shiftMatrixLeft(int m[9]) {
56 m[0] = m[1];
57 m[3] = m[4];
58 m[6] = m[7];
59 m[1] = m[2];
60 m[4] = m[5];
61 m[7] = m[8];
62}
63
64class DiffuseLightingType {
65public:
66 DiffuseLightingType(SkScalar kd)
67 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070068 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
69 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000070 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
71 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
72 SkPoint3 color(lightColor * colorScale);
73 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000074 SkClampMax(SkScalarRoundToInt(color.fX), 255),
75 SkClampMax(SkScalarRoundToInt(color.fY), 255),
76 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000077 }
78private:
79 SkScalar fKD;
80};
81
82class SpecularLightingType {
83public:
84 SpecularLightingType(SkScalar ks, SkScalar shininess)
85 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070086 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
87 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000088 SkPoint3 halfDir(surfaceTolight);
89 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
90 halfDir.normalize();
91 SkScalar colorScale = SkScalarMul(fKS,
92 SkScalarPow(normal.dot(halfDir), fShininess));
93 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
94 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000095 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
96 SkClampMax(SkScalarRoundToInt(color.fX), 255),
97 SkClampMax(SkScalarRoundToInt(color.fY), 255),
98 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000099 }
100private:
101 SkScalar fKS;
102 SkScalar fShininess;
103};
104
105inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
106 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
107}
108
109inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
110 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
111 SkScalarMul(-y, surfaceScale),
112 SK_Scalar1);
113 vector.normalize();
114 return vector;
115}
116
117inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
118 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
119 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
120 surfaceScale);
121}
122
123inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
124 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
125 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
126 surfaceScale);
127}
128
129inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
130 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
131 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
132 surfaceScale);
133}
134
135inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
137 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
138 surfaceScale);
139}
140
141
142inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
143 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
144 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
145 surfaceScale);
146}
147
148inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
149 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
150 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
151 surfaceScale);
152}
153
154inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
155 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
156 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
157 surfaceScale);
158}
159
160inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
161 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
162 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
163 surfaceScale);
164}
165
166inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
167 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
168 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
169 surfaceScale);
170}
171
joshualittb0a8a372014-09-23 09:50:21 -0700172template <class LightingType, class LightType> void lightBitmap(
173 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
174 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000175 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000176 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000177 int left = bounds.left(), right = bounds.right();
178 int bottom = bounds.bottom();
179 int y = bounds.top();
180 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000181 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000182 int x = left;
183 const SkPMColor* row1 = src.getAddr32(x, y);
184 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000185 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000186 m[4] = SkGetPackedA32(*row1++);
187 m[5] = SkGetPackedA32(*row1++);
188 m[7] = SkGetPackedA32(*row2++);
189 m[8] = SkGetPackedA32(*row2++);
190 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700191 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
192 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000193 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000194 {
195 shiftMatrixLeft(m);
196 m[5] = SkGetPackedA32(*row1++);
197 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000198 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700199 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
200 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000201 }
202 shiftMatrixLeft(m);
203 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700204 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
205 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000206 }
207
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000208 for (++y; y < bottom - 1; ++y) {
209 int x = left;
210 const SkPMColor* row0 = src.getAddr32(x, y - 1);
211 const SkPMColor* row1 = src.getAddr32(x, y);
212 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000213 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000214 m[1] = SkGetPackedA32(*row0++);
215 m[2] = SkGetPackedA32(*row0++);
216 m[4] = SkGetPackedA32(*row1++);
217 m[5] = SkGetPackedA32(*row1++);
218 m[7] = SkGetPackedA32(*row2++);
219 m[8] = SkGetPackedA32(*row2++);
220 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700221 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
222 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000223 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000224 shiftMatrixLeft(m);
225 m[2] = SkGetPackedA32(*row0++);
226 m[5] = SkGetPackedA32(*row1++);
227 m[8] = SkGetPackedA32(*row2++);
228 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700229 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
230 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000231 }
232 shiftMatrixLeft(m);
233 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700234 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
235 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000236 }
237
238 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000239 int x = left;
240 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
241 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000242 int m[9];
243 m[1] = SkGetPackedA32(*row0++);
244 m[2] = SkGetPackedA32(*row0++);
245 m[4] = SkGetPackedA32(*row1++);
246 m[5] = SkGetPackedA32(*row1++);
247 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700248 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
249 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000250 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000251 {
252 shiftMatrixLeft(m);
253 m[2] = SkGetPackedA32(*row0++);
254 m[5] = SkGetPackedA32(*row1++);
255 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700256 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
257 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000258 }
259 shiftMatrixLeft(m);
260 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700261 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
262 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000263 }
264}
265
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000266SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000267 SkPoint3 point;
268 point.fX = buffer.readScalar();
269 point.fY = buffer.readScalar();
270 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000271 buffer.validate(SkScalarIsFinite(point.fX) &&
272 SkScalarIsFinite(point.fY) &&
273 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000274 return point;
275};
276
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000277void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000278 buffer.writeScalar(point.fX);
279 buffer.writeScalar(point.fY);
280 buffer.writeScalar(point.fZ);
281};
282
senorblancod0d37ca2015-04-02 04:54:56 -0700283enum BoundaryMode {
284 kTopLeft_BoundaryMode,
285 kTop_BoundaryMode,
286 kTopRight_BoundaryMode,
287 kLeft_BoundaryMode,
288 kInterior_BoundaryMode,
289 kRight_BoundaryMode,
290 kBottomLeft_BoundaryMode,
291 kBottom_BoundaryMode,
292 kBottomRight_BoundaryMode,
293
294 kBoundaryModeCount,
295};
296
297class SkLightingImageFilterInternal : public SkLightingImageFilter {
298protected:
299 SkLightingImageFilterInternal(SkLight* light,
300 SkScalar surfaceScale,
301 SkImageFilter* input,
302 const CropRect* cropRect)
303 : INHERITED(light, surfaceScale, input, cropRect) {}
304
305#if SK_SUPPORT_GPU
306 bool canFilterImageGPU() const override { return true; }
307 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
308 SkBitmap* result, SkIPoint* offset) const override;
309 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
310 const SkMatrix&,
311 const SkIRect& bounds,
312 BoundaryMode boundaryMode) const = 0;
313#endif
314private:
315#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700316 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700317 GrTexture* src,
318 GrTexture* dst,
319 const SkMatrix& matrix,
320 const GrClip& clip,
321 const SkRect& dstRect,
322 BoundaryMode boundaryMode,
323 const SkIRect& bounds) const;
324#endif
325 typedef SkLightingImageFilter INHERITED;
326};
327
328#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700329void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700330 GrTexture* src,
331 GrTexture* dst,
332 const SkMatrix& matrix,
333 const GrClip& clip,
334 const SkRect& dstRect,
335 BoundaryMode boundaryMode,
336 const SkIRect& bounds) const {
337 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
338 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
339 GrPaint paint;
340 paint.addColorProcessor(fp)->unref();
robertphillipsea461502015-05-26 11:38:03 -0700341 drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
342 dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700343}
344
345bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
346 const SkBitmap& src,
347 const Context& ctx,
348 SkBitmap* result,
349 SkIPoint* offset) const {
350 SkBitmap input = src;
351 SkIPoint srcOffset = SkIPoint::Make(0, 0);
352 if (this->getInput(0) &&
353 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
354 return false;
355 }
356 SkIRect bounds;
357 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
358 return false;
359 }
360 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
361 SkIntToScalar(bounds.height()));
362 GrTexture* srcTexture = input.getTexture();
363 GrContext* context = srcTexture->getContext();
364
365 GrSurfaceDesc desc;
366 desc.fFlags = kRenderTarget_GrSurfaceFlag,
367 desc.fWidth = bounds.width();
368 desc.fHeight = bounds.height();
369 desc.fConfig = kRGBA_8888_GrPixelConfig;
370
bsalomond309e7a2015-04-30 14:18:54 -0700371 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(desc,
372 GrTextureProvider::kApprox_ScratchTexMatch));
senorblancod0d37ca2015-04-02 04:54:56 -0700373 if (!dst) {
374 return false;
375 }
376
377 // setup new clip
378 GrClip clip(dstRect);
379
380 offset->fX = bounds.left();
381 offset->fY = bounds.top();
382 SkMatrix matrix(ctx.ctm());
383 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
384 bounds.offset(-srcOffset);
385 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
386 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
387 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
388 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
389 SkRect interior = dstRect.makeInset(1, 1);
390 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
391 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
392 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
393 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700394
395 GrDrawContext* drawContext = context->drawContext();
396 if (!drawContext) {
397 return false;
398 }
399
400 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700401 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700402 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
403 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700404 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700405 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
406 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700407 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700408 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
409 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700410 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700411 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
412 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
413 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700414 WrapTexture(dst, bounds.width(), bounds.height(), result);
415 return true;
416}
417#endif
418
419class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000420public:
reed9fa60da2014-08-21 07:59:51 -0700421 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700422 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700423
robertphillipsf3f5bad2014-12-19 13:49:15 -0800424 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000425 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000426 SkScalar kd() const { return fKD; }
427
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000428protected:
reed9fa60da2014-08-21 07:59:51 -0700429 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700430 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700431 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700432 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
433 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000434#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -0700435 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&,
436 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000437#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000438
439private:
reed9fa60da2014-08-21 07:59:51 -0700440 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700441 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000442 SkScalar fKD;
443};
444
senorblancod0d37ca2015-04-02 04:54:56 -0700445class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000446public:
reed9fa60da2014-08-21 07:59:51 -0700447 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700448 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700449
robertphillipsf3f5bad2014-12-19 13:49:15 -0800450 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000451 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
452
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000453 SkScalar ks() const { return fKS; }
454 SkScalar shininess() const { return fShininess; }
455
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456protected:
reed9fa60da2014-08-21 07:59:51 -0700457 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700458 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700459 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700460 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
461 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000462#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -0700463 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&,
464 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000465#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000466
467private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000468 SkScalar fKS;
469 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700470 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700471 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000472};
473
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000474#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000475
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000476class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000477public:
senorblancod0d37ca2015-04-02 04:54:56 -0700478 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale,
479 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000480 virtual ~GrLightingEffect();
481
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000482 const SkLight* light() const { return fLight; }
483 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000484 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700485 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000486
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000487protected:
mtklein36352bf2015-03-25 18:17:31 -0700488 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000489
mtklein36352bf2015-03-25 18:17:31 -0700490 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700491 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800492 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700493 }
494
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000495private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000496 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000497 const SkLight* fLight;
498 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000499 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700500 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000501};
502
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000503class GrDiffuseLightingEffect : public GrLightingEffect {
504public:
joshualittb0a8a372014-09-23 09:50:21 -0700505 static GrFragmentProcessor* Create(GrTexture* texture,
506 const SkLight* light,
507 SkScalar surfaceScale,
508 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700509 SkScalar kd,
510 BoundaryMode boundaryMode) {
bsalomon55fad7a2014-07-08 07:34:20 -0700511 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
512 light,
513 surfaceScale,
514 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700515 kd,
516 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000517 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518
mtklein36352bf2015-03-25 18:17:31 -0700519 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000520
jvanverthcfc18862015-04-28 08:48:20 -0700521 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000522
mtklein36352bf2015-03-25 18:17:31 -0700523 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800524
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000525 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000526
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527private:
mtklein36352bf2015-03-25 18:17:31 -0700528 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000529
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000530 GrDiffuseLightingEffect(GrTexture* texture,
531 const SkLight* light,
532 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000533 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700534 SkScalar kd,
535 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000536
joshualittb0a8a372014-09-23 09:50:21 -0700537 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000538 typedef GrLightingEffect INHERITED;
539 SkScalar fKD;
540};
541
542class GrSpecularLightingEffect : public GrLightingEffect {
543public:
joshualittb0a8a372014-09-23 09:50:21 -0700544 static GrFragmentProcessor* Create(GrTexture* texture,
545 const SkLight* light,
546 SkScalar surfaceScale,
547 const SkMatrix& matrix,
548 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700549 SkScalar shininess,
550 BoundaryMode boundaryMode) {
bsalomon55fad7a2014-07-08 07:34:20 -0700551 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
552 light,
553 surfaceScale,
554 matrix,
555 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700556 shininess,
557 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000558 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000559
mtklein36352bf2015-03-25 18:17:31 -0700560 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000561
jvanverthcfc18862015-04-28 08:48:20 -0700562 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800563
mtklein36352bf2015-03-25 18:17:31 -0700564 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800565
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566 SkScalar ks() const { return fKS; }
567 SkScalar shininess() const { return fShininess; }
568
569private:
mtklein36352bf2015-03-25 18:17:31 -0700570 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000571
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000572 GrSpecularLightingEffect(GrTexture* texture,
573 const SkLight* light,
574 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000575 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000576 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700577 SkScalar shininess,
578 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000579
joshualittb0a8a372014-09-23 09:50:21 -0700580 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000581 typedef GrLightingEffect INHERITED;
582 SkScalar fKS;
583 SkScalar fShininess;
584};
585
586///////////////////////////////////////////////////////////////////////////////
587
588class GrGLLight {
589public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000590 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000591
592 /**
593 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
594 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
595 */
joshualitt15988992014-10-09 15:04:05 -0700596 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000597
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000598 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000599 * These two functions are called from GrGLLightingEffect's emitCode() function.
600 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
601 * the light. The expression will be used in the FS. emitLightColor writes an expression into
602 * the FS that is the color of the light. Either function may add functions and/or uniforms to
603 * the FS. The default of emitLightColor appends the name of the constant light color uniform
604 * and so this function only needs to be overridden if the light color varies spatially.
605 */
joshualitt15988992014-10-09 15:04:05 -0700606 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
607 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000608
609 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
610 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700611 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000612 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000613
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000614protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000615 /**
616 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
617 * function.
618 */
619 UniformHandle lightColorUni() const { return fColorUni; }
620
621private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000622 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000623
624 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625};
626
627///////////////////////////////////////////////////////////////////////////////
628
629class GrGLDistantLight : public GrGLLight {
630public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000631 virtual ~GrGLDistantLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700632 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700633 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000634
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000635private:
636 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000637 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000638};
639
640///////////////////////////////////////////////////////////////////////////////
641
642class GrGLPointLight : public GrGLLight {
643public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000644 virtual ~GrGLPointLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700645 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700646 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000647
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000648private:
649 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000650 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000651};
652
653///////////////////////////////////////////////////////////////////////////////
654
655class GrGLSpotLight : public GrGLLight {
656public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000657 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700658 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700659 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
660 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000661
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662private:
663 typedef GrGLLight INHERITED;
664
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000665 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000666 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000667 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000668 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000669 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000670 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000671 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000672};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000673#else
674
675class GrGLLight;
676
677#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000678
679};
680
681///////////////////////////////////////////////////////////////////////////////
682
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000683class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000684public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000685 SK_DECLARE_INST_COUNT(SkLight)
686
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000687 enum LightType {
688 kDistant_LightType,
689 kPoint_LightType,
690 kSpot_LightType,
691 };
692 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000693 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000694 virtual GrGLLight* createGLLight() const = 0;
695 virtual bool isEqual(const SkLight& other) const {
696 return fColor == other.fColor;
697 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000698 // Called to know whether the generated GrGLLight will require access to the fragment position.
699 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000700 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000702 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000703 void flattenLight(SkWriteBuffer& buffer) const;
704 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000705
djsollen@google.com08337772012-06-26 14:33:13 +0000706protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000707 SkLight(SkColor color)
708 : fColor(SkIntToScalar(SkColorGetR(color)),
709 SkIntToScalar(SkColorGetG(color)),
710 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000711 SkLight(const SkPoint3& color)
712 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000713 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000714 fColor = readPoint3(buffer);
715 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000716
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000717 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000718
djsollen@google.com08337772012-06-26 14:33:13 +0000719
720private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000721 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000722 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000723};
724
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000725///////////////////////////////////////////////////////////////////////////////
726
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000727class SkDistantLight : public SkLight {
728public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000729 SkDistantLight(const SkPoint3& direction, SkColor color)
730 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 }
djsollen@google.com08337772012-06-26 14:33:13 +0000732
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000733 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
734 return fDirection;
735 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000736 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700737 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000738 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700739 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000740#if SK_SUPPORT_GPU
741 return SkNEW(GrGLDistantLight);
742#else
743 SkDEBUGFAIL("Should not call in GPU-less build");
744 return NULL;
745#endif
746 }
mtklein36352bf2015-03-25 18:17:31 -0700747 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000748
mtklein36352bf2015-03-25 18:17:31 -0700749 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000750 if (other.type() != kDistant_LightType) {
751 return false;
752 }
753
754 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
755 return INHERITED::isEqual(other) &&
756 fDirection == o.fDirection;
757 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000758
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000759 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000760 fDirection = readPoint3(buffer);
761 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000762
djsollen@google.com08337772012-06-26 14:33:13 +0000763protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000764 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
765 : INHERITED(color), fDirection(direction) {
766 }
mtklein36352bf2015-03-25 18:17:31 -0700767 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000768 return new SkDistantLight(direction(), color());
769 }
mtklein36352bf2015-03-25 18:17:31 -0700770 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000771 writePoint3(fDirection, buffer);
772 }
773
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774private:
djsollen@google.com08337772012-06-26 14:33:13 +0000775 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000776 SkPoint3 fDirection;
777};
778
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000779///////////////////////////////////////////////////////////////////////////////
780
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000781class SkPointLight : public SkLight {
782public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000783 SkPointLight(const SkPoint3& location, SkColor color)
784 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000785
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
787 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
788 fLocation.fY - SkIntToScalar(y),
789 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
790 direction.normalize();
791 return direction;
792 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000793 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700794 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000795 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700796 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000797#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000798 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000799#else
800 SkDEBUGFAIL("Should not call in GPU-less build");
801 return NULL;
802#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000803 }
mtklein36352bf2015-03-25 18:17:31 -0700804 bool requiresFragmentPosition() const override { return true; }
805 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000806 if (other.type() != kPoint_LightType) {
807 return false;
808 }
809 const SkPointLight& o = static_cast<const SkPointLight&>(other);
810 return INHERITED::isEqual(other) &&
811 fLocation == o.fLocation;
812 }
mtklein36352bf2015-03-25 18:17:31 -0700813 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000814 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
815 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000816 // Use X scale and Y scale on Z and average the result
817 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
818 matrix.mapVectors(&locationZ, 1);
819 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000820 return new SkPointLight(location, color());
821 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000822
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000823 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000824 fLocation = readPoint3(buffer);
825 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000826
827protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000828 SkPointLight(const SkPoint3& location, const SkPoint3& color)
829 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700830 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000831 writePoint3(fLocation, buffer);
832 }
833
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000834private:
djsollen@google.com08337772012-06-26 14:33:13 +0000835 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000836 SkPoint3 fLocation;
837};
838
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000839///////////////////////////////////////////////////////////////////////////////
840
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000841class SkSpotLight : public SkLight {
842public:
senorblancod0d37ca2015-04-02 04:54:56 -0700843 SkSpotLight(const SkPoint3& location,
844 const SkPoint3& target,
845 SkScalar specularExponent,
846 SkScalar cutoffAngle,
847 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000848 : INHERITED(color),
849 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000851 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000852 {
853 fS = target - location;
854 fS.normalize();
855 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000856 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000857 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
858 fConeScale = SkScalarInvert(antiAliasThreshold);
859 }
djsollen@google.com08337772012-06-26 14:33:13 +0000860
mtklein36352bf2015-03-25 18:17:31 -0700861 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000862 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
863 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000864 // Use X scale and Y scale on Z and average the result
865 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
866 matrix.mapVectors(&locationZ, 1);
867 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000868 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
869 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000870 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
871 matrix.mapVectors(&targetZ, 1);
872 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
873 SkPoint3 s = target - location;
874 s.normalize();
senorblancod0d37ca2015-04-02 04:54:56 -0700875 return new SkSpotLight(location,
876 target,
877 fSpecularExponent,
878 fCosOuterConeAngle,
879 fCosInnerConeAngle,
880 fConeScale,
881 s,
882 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000883 }
884
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000885 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
886 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
887 fLocation.fY - SkIntToScalar(y),
888 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
889 direction.normalize();
890 return direction;
891 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000892 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000893 SkScalar cosAngle = -surfaceToLight.dot(fS);
894 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000895 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000896 }
897 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
898 if (cosAngle < fCosInnerConeAngle) {
899 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000900 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000901 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000902 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000903 }
mtklein36352bf2015-03-25 18:17:31 -0700904 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000905#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000906 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000907#else
908 SkDEBUGFAIL("Should not call in GPU-less build");
909 return NULL;
910#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000911 }
mtklein36352bf2015-03-25 18:17:31 -0700912 bool requiresFragmentPosition() const override { return true; }
913 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000914 const SkPoint3& location() const { return fLocation; }
915 const SkPoint3& target() const { return fTarget; }
916 SkScalar specularExponent() const { return fSpecularExponent; }
917 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
918 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
919 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000920 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000921
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000922 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000923 fLocation = readPoint3(buffer);
924 fTarget = readPoint3(buffer);
925 fSpecularExponent = buffer.readScalar();
926 fCosOuterConeAngle = buffer.readScalar();
927 fCosInnerConeAngle = buffer.readScalar();
928 fConeScale = buffer.readScalar();
929 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000930 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
931 SkScalarIsFinite(fCosOuterConeAngle) &&
932 SkScalarIsFinite(fCosInnerConeAngle) &&
933 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000934 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000935protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700936 SkSpotLight(const SkPoint3& location,
937 const SkPoint3& target,
938 SkScalar specularExponent,
939 SkScalar cosOuterConeAngle,
940 SkScalar cosInnerConeAngle,
941 SkScalar coneScale,
942 const SkPoint3& s,
943 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000944 : INHERITED(color),
945 fLocation(location),
946 fTarget(target),
947 fSpecularExponent(specularExponent),
948 fCosOuterConeAngle(cosOuterConeAngle),
949 fCosInnerConeAngle(cosInnerConeAngle),
950 fConeScale(coneScale),
951 fS(s)
952 {
953 }
mtklein36352bf2015-03-25 18:17:31 -0700954 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000955 writePoint3(fLocation, buffer);
956 writePoint3(fTarget, buffer);
957 buffer.writeScalar(fSpecularExponent);
958 buffer.writeScalar(fCosOuterConeAngle);
959 buffer.writeScalar(fCosInnerConeAngle);
960 buffer.writeScalar(fConeScale);
961 writePoint3(fS, buffer);
962 }
963
mtklein36352bf2015-03-25 18:17:31 -0700964 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000965 if (other.type() != kSpot_LightType) {
966 return false;
967 }
968
969 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
970 return INHERITED::isEqual(other) &&
971 fLocation == o.fLocation &&
972 fTarget == o.fTarget &&
973 fSpecularExponent == o.fSpecularExponent &&
974 fCosOuterConeAngle == o.fCosOuterConeAngle;
975 }
976
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000977private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000978 static const SkScalar kSpecularExponentMin;
979 static const SkScalar kSpecularExponentMax;
980
djsollen@google.com08337772012-06-26 14:33:13 +0000981 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000982 SkPoint3 fLocation;
983 SkPoint3 fTarget;
984 SkScalar fSpecularExponent;
985 SkScalar fCosOuterConeAngle;
986 SkScalar fCosInnerConeAngle;
987 SkScalar fConeScale;
988 SkPoint3 fS;
989};
990
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000991// According to the spec, the specular term should be in the range [1, 128] :
992// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000993const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
994const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000995
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000996///////////////////////////////////////////////////////////////////////////////
997
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000998void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000999 // Write type first, then baseclass, then subclass.
1000 buffer.writeInt(this->type());
1001 writePoint3(fColor, buffer);
1002 this->onFlattenLight(buffer);
1003}
1004
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001005/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001006 // Read type first.
1007 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
1008 switch (type) {
1009 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1010 // then subclass, same order as flattenLight.
1011 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1012 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1013 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1014 default:
1015 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001016 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001017 return NULL;
1018 }
1019}
1020///////////////////////////////////////////////////////////////////////////////
1021
senorblanco9ea3d572014-07-08 09:16:22 -07001022SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001023 SkImageFilter* input, const CropRect* cropRect)
1024 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001025 , fLight(SkRef(light))
1026 , fSurfaceScale(surfaceScale / 255)
1027{}
1028
1029SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1030 SkColor lightColor,
1031 SkScalar surfaceScale,
1032 SkScalar kd,
1033 SkImageFilter* input,
1034 const CropRect* cropRect) {
1035 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, 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::CreatePointLitDiffuse(const SkPoint3& location,
1040 SkColor lightColor,
1041 SkScalar surfaceScale,
1042 SkScalar kd,
1043 SkImageFilter* input,
1044 const CropRect* cropRect) {
1045 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1046 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001047}
1048
reed9fa60da2014-08-21 07:59:51 -07001049SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1050 const SkPoint3& target,
1051 SkScalar specularExponent,
1052 SkScalar cutoffAngle,
1053 SkColor lightColor,
1054 SkScalar surfaceScale,
1055 SkScalar kd,
1056 SkImageFilter* input,
1057 const CropRect* cropRect) {
1058 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1059 cutoffAngle, lightColor)));
1060 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001061}
1062
reed9fa60da2014-08-21 07:59:51 -07001063SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1064 SkColor lightColor,
1065 SkScalar surfaceScale,
1066 SkScalar ks,
1067 SkScalar shine,
1068 SkImageFilter* input,
1069 const CropRect* cropRect) {
1070 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1071 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001072}
1073
reed9fa60da2014-08-21 07:59:51 -07001074SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1075 SkColor lightColor,
1076 SkScalar surfaceScale,
1077 SkScalar ks,
1078 SkScalar shine,
1079 SkImageFilter* input,
1080 const CropRect* cropRect) {
1081 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1082 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001083}
1084
reed9fa60da2014-08-21 07:59:51 -07001085SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1086 const SkPoint3& target,
1087 SkScalar specularExponent,
1088 SkScalar cutoffAngle,
1089 SkColor lightColor,
1090 SkScalar surfaceScale,
1091 SkScalar ks,
1092 SkScalar shine,
1093 SkImageFilter* input,
1094 const CropRect* cropRect) {
1095 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1096 cutoffAngle, lightColor)));
1097 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001098}
1099
reed9fa60da2014-08-21 07:59:51 -07001100SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001101
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001102void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001103 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001104 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001105 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001106}
1107
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001108///////////////////////////////////////////////////////////////////////////////
1109
reed9fa60da2014-08-21 07:59:51 -07001110SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001111 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001112 if (NULL == light) {
1113 return NULL;
1114 }
1115 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1116 return NULL;
1117 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001118 // According to the spec, kd can be any non-negative number :
1119 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001120 if (kd < 0) {
1121 return NULL;
1122 }
senorblanco24e06d52015-03-18 12:11:33 -07001123 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001124}
1125
senorblancod0d37ca2015-04-02 04:54:56 -07001126SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1127 SkScalar surfaceScale,
1128 SkScalar kd,
1129 SkImageFilter* input,
1130 const CropRect* cropRect)
1131 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001132 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001133{
1134}
1135
reed9fa60da2014-08-21 07:59:51 -07001136SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1137 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1138 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1139 SkScalar surfaceScale = buffer.readScalar();
1140 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001141 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001142}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001143
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001144void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001145 this->INHERITED::flatten(buffer);
1146 buffer.writeScalar(fKD);
1147}
1148
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001149bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1150 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001151 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001152 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001153 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001154 SkImageFilter* input = getInput(0);
1155 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001156 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001157 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001158 return false;
1159 }
1160
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001161 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001162 return false;
1163 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001164 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001165 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001166 return false;
1167 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001168
1169 if (bounds.width() < 2 || bounds.height() < 2) {
1170 return false;
1171 }
1172
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001173 SkAutoLockPixels alp(src);
1174 if (!src.getPixels()) {
1175 return false;
1176 }
1177
reed84825042014-09-02 12:50:45 -07001178 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001179 return false;
1180 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001181
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001182 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001183
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001184 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001185 offset->fX = bounds.left();
1186 offset->fY = bounds.top();
1187 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001188 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001189 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001190 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1191 transformedLight,
1192 src,
1193 dst,
1194 surfaceScale(),
1195 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001196 break;
1197 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001198 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1199 transformedLight,
1200 src,
1201 dst,
1202 surfaceScale(),
1203 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001204 break;
1205 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001206 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1207 transformedLight,
1208 src,
1209 dst,
1210 surfaceScale(),
1211 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001212 break;
1213 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001214
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001215 return true;
1216}
1217
robertphillipsf3f5bad2014-12-19 13:49:15 -08001218#ifndef SK_IGNORE_TO_STRING
1219void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1220 str->appendf("SkDiffuseLightingImageFilter: (");
1221 str->appendf("kD: %f\n", fKD);
1222 str->append(")");
1223}
1224#endif
1225
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001226#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001227GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualittb0a8a372014-09-23 09:50:21 -07001228 GrTexture* texture,
1229 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001230 const SkIRect&,
1231 BoundaryMode boundaryMode
1232) const {
1233 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1234 return GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001235}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001236#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001237
1238///////////////////////////////////////////////////////////////////////////////
1239
reed9fa60da2014-08-21 07:59:51 -07001240SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001241 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001242 if (NULL == light) {
1243 return NULL;
1244 }
1245 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1246 return NULL;
1247 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001248 // According to the spec, ks can be any non-negative number :
1249 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001250 if (ks < 0) {
1251 return NULL;
1252 }
1253 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001254 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001255}
1256
senorblancod0d37ca2015-04-02 04:54:56 -07001257SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1258 SkScalar surfaceScale,
1259 SkScalar ks,
1260 SkScalar shininess,
1261 SkImageFilter* input,
1262 const CropRect* cropRect)
1263 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001264 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001265 fShininess(shininess)
1266{
1267}
1268
reed9fa60da2014-08-21 07:59:51 -07001269SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1270 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1271 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1272 SkScalar surfaceScale = buffer.readScalar();
1273 SkScalar ks = buffer.readScalar();
1274 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001275 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001276}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001277
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001278void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001279 this->INHERITED::flatten(buffer);
1280 buffer.writeScalar(fKS);
1281 buffer.writeScalar(fShininess);
1282}
1283
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001284bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1285 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001286 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001287 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001288 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001289 SkImageFilter* input = getInput(0);
1290 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001291 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001292 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001293 return false;
1294 }
1295
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001296 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001297 return false;
1298 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001299
1300 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001301 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001302 return false;
1303 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001304
1305 if (bounds.width() < 2 || bounds.height() < 2) {
1306 return false;
1307 }
1308
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001309 SkAutoLockPixels alp(src);
1310 if (!src.getPixels()) {
1311 return false;
1312 }
1313
reed84825042014-09-02 12:50:45 -07001314 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001315 return false;
1316 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001317
1318 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001319 offset->fX = bounds.left();
1320 offset->fY = bounds.top();
1321 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001322 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001323 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001324 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001325 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1326 transformedLight,
1327 src,
1328 dst,
1329 surfaceScale(),
1330 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001331 break;
1332 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001333 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1334 transformedLight,
1335 src,
1336 dst,
1337 surfaceScale(),
1338 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001339 break;
1340 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001341 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1342 transformedLight,
1343 src,
1344 dst,
1345 surfaceScale(),
1346 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001347 break;
1348 }
1349 return true;
1350}
1351
robertphillipsf3f5bad2014-12-19 13:49:15 -08001352#ifndef SK_IGNORE_TO_STRING
1353void SkSpecularLightingImageFilter::toString(SkString* str) const {
1354 str->appendf("SkSpecularLightingImageFilter: (");
1355 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1356 str->append(")");
1357}
1358#endif
1359
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001360#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001361GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
1362 GrTexture* texture,
1363 const SkMatrix& matrix,
1364 const SkIRect&,
1365 BoundaryMode boundaryMode) const {
1366 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1367 return GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess(),
1368 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001369}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001370#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001371
1372///////////////////////////////////////////////////////////////////////////////
1373
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001374#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001375
1376namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001377SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001378 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1379 SkScalarToFloat(random->nextSScalar1()),
1380 SkScalarToFloat(random->nextSScalar1()));
1381}
1382
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001383SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001384 int type = random->nextULessThan(3);
1385 switch (type) {
1386 case 0: {
1387 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1388 }
1389 case 1: {
1390 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1391 }
1392 case 2: {
1393 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1394 random_point3(random),
1395 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001396 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001397 random->nextU()));
1398 }
1399 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001400 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001401 return NULL;
1402 }
1403}
1404
senorblancod0d37ca2015-04-02 04:54:56 -07001405SkString emitNormalFunc(BoundaryMode mode,
1406 const char* pointToNormalName,
1407 const char* sobelFuncName) {
1408 SkString result;
1409 switch (mode) {
1410 case kTopLeft_BoundaryMode:
1411 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1412 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1413 "\t surfaceScale);\n",
1414 pointToNormalName, sobelFuncName, gTwoThirds,
1415 sobelFuncName, gTwoThirds);
1416 break;
1417 case kTop_BoundaryMode:
1418 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1419 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1420 "\t surfaceScale);\n",
1421 pointToNormalName, sobelFuncName, gOneThird,
1422 sobelFuncName, gOneHalf);
1423 break;
1424 case kTopRight_BoundaryMode:
1425 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1426 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1427 "\t surfaceScale);\n",
1428 pointToNormalName, sobelFuncName, gTwoThirds,
1429 sobelFuncName, gTwoThirds);
1430 break;
1431 case kLeft_BoundaryMode:
1432 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1433 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1434 "\t surfaceScale);\n",
1435 pointToNormalName, sobelFuncName, gOneHalf,
1436 sobelFuncName, gOneThird);
1437 break;
1438 case kInterior_BoundaryMode:
1439 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1440 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1441 "\t surfaceScale);\n",
1442 pointToNormalName, sobelFuncName, gOneQuarter,
1443 sobelFuncName, gOneQuarter);
1444 break;
1445 case kRight_BoundaryMode:
1446 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1447 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1448 "\t surfaceScale);\n",
1449 pointToNormalName, sobelFuncName, gOneHalf,
1450 sobelFuncName, gOneThird);
1451 break;
1452 case kBottomLeft_BoundaryMode:
1453 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1454 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1455 "\t surfaceScale);\n",
1456 pointToNormalName, sobelFuncName, gTwoThirds,
1457 sobelFuncName, gTwoThirds);
1458 break;
1459 case kBottom_BoundaryMode:
1460 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1461 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1462 "\t surfaceScale);\n",
1463 pointToNormalName, sobelFuncName, gOneThird,
1464 sobelFuncName, gOneHalf);
1465 break;
1466 case kBottomRight_BoundaryMode:
1467 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1468 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1469 "\t surfaceScale);\n",
1470 pointToNormalName, sobelFuncName, gTwoThirds,
1471 sobelFuncName, gTwoThirds);
1472 break;
1473 default:
1474 SkASSERT(false);
1475 break;
1476 }
1477 return result;
1478}
1479
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001480}
1481
joshualittb0a8a372014-09-23 09:50:21 -07001482class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001483public:
joshualitteb2a6762014-12-04 11:35:33 -08001484 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001485 virtual ~GrGLLightingEffect();
1486
senorblancod0d37ca2015-04-02 04:54:56 -07001487 void emitCode(GrGLFPBuilder*,
1488 const GrFragmentProcessor&,
1489 const char* outputColor,
1490 const char* inputColor,
1491 const TransformedCoordsArray&,
1492 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001493
jvanverthcfc18862015-04-28 08:48:20 -07001494 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001495
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001496 /**
1497 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1498 */
mtklein36352bf2015-03-25 18:17:31 -07001499 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001500
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001501protected:
joshualitt15988992014-10-09 15:04:05 -07001502 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001503
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001504private:
joshualittb0a8a372014-09-23 09:50:21 -07001505 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001506
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001507 UniformHandle fImageIncrementUni;
1508 UniformHandle fSurfaceScaleUni;
1509 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001510 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001511};
1512
1513///////////////////////////////////////////////////////////////////////////////
1514
1515class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1516public:
joshualitteb2a6762014-12-04 11:35:33 -08001517 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001518 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1519 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001520
1521private:
1522 typedef GrGLLightingEffect INHERITED;
1523
bsalomon@google.com032b2212012-07-16 13:36:18 +00001524 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525};
1526
1527///////////////////////////////////////////////////////////////////////////////
1528
1529class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1530public:
joshualitteb2a6762014-12-04 11:35:33 -08001531 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001532 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1533 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001534
1535private:
1536 typedef GrGLLightingEffect INHERITED;
1537
bsalomon@google.com032b2212012-07-16 13:36:18 +00001538 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001539 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001540};
1541
1542///////////////////////////////////////////////////////////////////////////////
1543
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001544GrLightingEffect::GrLightingEffect(GrTexture* texture,
1545 const SkLight* light,
1546 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001547 const SkMatrix& matrix,
1548 BoundaryMode boundaryMode)
bsalomon6267f812014-08-29 15:05:53 -07001549 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001550 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001551 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001552 , fFilterMatrix(matrix)
1553 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001554 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001555 if (light->requiresFragmentPosition()) {
1556 this->setWillReadFragmentPosition();
1557 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001558}
1559
1560GrLightingEffect::~GrLightingEffect() {
1561 fLight->unref();
1562}
1563
bsalomon0e08fc12014-10-15 08:19:04 -07001564bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001565 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001566 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001567 fSurfaceScale == s.fSurfaceScale &&
1568 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001569}
1570
1571///////////////////////////////////////////////////////////////////////////////
1572
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001573GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1574 const SkLight* light,
1575 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001576 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001577 SkScalar kd,
1578 BoundaryMode boundaryMode)
1579 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001580 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001581}
1582
bsalomon0e08fc12014-10-15 08:19:04 -07001583bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001584 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001585 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001586 this->kd() == s.kd();
1587}
1588
jvanverthcfc18862015-04-28 08:48:20 -07001589void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001590 GrProcessorKeyBuilder* b) const {
1591 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1592}
1593
1594GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1595 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1596}
1597
joshualittb0a8a372014-09-23 09:50:21 -07001598GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001599
joshualittb0a8a372014-09-23 09:50:21 -07001600GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001601 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -07001602 const GrCaps&,
bsalomon83d081a2014-07-08 09:56:10 -07001603 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001604 SkScalar surfaceScale = random->nextSScalar1();
1605 SkScalar kd = random->nextUScalar1();
1606 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001607 SkMatrix matrix;
1608 for (int i = 0; i < 9; i++) {
1609 matrix[i] = random->nextUScalar1();
1610 }
senorblancod0d37ca2015-04-02 04:54:56 -07001611 BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount);
joshualittb0a8a372014-09-23 09:50:21 -07001612 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001613 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001614}
1615
1616
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001617///////////////////////////////////////////////////////////////////////////////
1618
joshualitteb2a6762014-12-04 11:35:33 -08001619GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001620 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001621 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001622 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001623}
1624
1625GrGLLightingEffect::~GrGLLightingEffect() {
1626 delete fLight;
1627}
1628
joshualitt15988992014-10-09 15:04:05 -07001629void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001630 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001631 const char* outputColor,
1632 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001633 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001634 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001635 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001636 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001637 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001638 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001639 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001640 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001641 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001642 SkString lightFunc;
1643 this->emitLightFunc(builder, &lightFunc);
1644 static const GrGLShaderVar gSobelArgs[] = {
1645 GrGLShaderVar("a", kFloat_GrSLType),
1646 GrGLShaderVar("b", kFloat_GrSLType),
1647 GrGLShaderVar("c", kFloat_GrSLType),
1648 GrGLShaderVar("d", kFloat_GrSLType),
1649 GrGLShaderVar("e", kFloat_GrSLType),
1650 GrGLShaderVar("f", kFloat_GrSLType),
1651 GrGLShaderVar("scale", kFloat_GrSLType),
1652 };
1653 SkString sobelFuncName;
egdaniel29bee0f2015-04-29 11:54:42 -07001654 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001655 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1656
1657 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001658 "sobel",
1659 SK_ARRAY_COUNT(gSobelArgs),
1660 gSobelArgs,
1661 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1662 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001663 static const GrGLShaderVar gPointToNormalArgs[] = {
1664 GrGLShaderVar("x", kFloat_GrSLType),
1665 GrGLShaderVar("y", kFloat_GrSLType),
1666 GrGLShaderVar("scale", kFloat_GrSLType),
1667 };
1668 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001669 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001670 "pointToNormal",
1671 SK_ARRAY_COUNT(gPointToNormalArgs),
1672 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001673 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001674 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001675
1676 static const GrGLShaderVar gInteriorNormalArgs[] = {
1677 GrGLShaderVar("m", kFloat_GrSLType, 9),
1678 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1679 };
senorblancod0d37ca2015-04-02 04:54:56 -07001680 SkString normalBody = emitNormalFunc(fBoundaryMode,
1681 pointToNormalName.c_str(),
1682 sobelFuncName.c_str());
1683 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001684 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001685 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001686 SK_ARRAY_COUNT(gInteriorNormalArgs),
1687 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001688 normalBody.c_str(),
1689 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001690
joshualitt30ba4362014-08-21 20:18:45 -07001691 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1692 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001693
1694 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1695 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1696
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001697 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001698 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001699 for (int dx = -1; dx <= 1; dx++) {
1700 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001701 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001702 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1703 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1704 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001705 }
1706 }
joshualitt30ba4362014-08-21 20:18:45 -07001707 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001708 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001709 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001710 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001711 fsBuilder->codeAppend(";\n");
1712 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
senorblancod0d37ca2015-04-02 04:54:56 -07001713 outputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001714 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001715 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001716 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001717 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001718 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001719}
1720
joshualittb0a8a372014-09-23 09:50:21 -07001721void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001722 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001723 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1724 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001725}
1726
kkinnunen7510b222014-07-30 00:04:16 -07001727void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001728 const GrProcessor& proc) {
1729 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001730 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001731 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001732 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1733 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001734 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001735 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001736}
1737
1738///////////////////////////////////////////////////////////////////////////////
1739
1740///////////////////////////////////////////////////////////////////////////////
1741
joshualitteb2a6762014-12-04 11:35:33 -08001742GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1743 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001744}
1745
joshualitt15988992014-10-09 15:04:05 -07001746void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001747 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001748 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001749 kFloat_GrSLType, kDefault_GrSLPrecision,
1750 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001751
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001752 static const GrGLShaderVar gLightArgs[] = {
1753 GrGLShaderVar("normal", kVec3f_GrSLType),
1754 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1755 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1756 };
1757 SkString lightBody;
1758 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1759 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001760 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1761 "light",
1762 SK_ARRAY_COUNT(gLightArgs),
1763 gLightArgs,
1764 lightBody.c_str(),
1765 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001766}
1767
kkinnunen7510b222014-07-30 00:04:16 -07001768void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001769 const GrProcessor& proc) {
1770 INHERITED::setData(pdman, proc);
1771 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001772 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001773}
1774
1775///////////////////////////////////////////////////////////////////////////////
1776
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001777GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1778 const SkLight* light,
1779 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001780 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001781 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001782 SkScalar shininess,
1783 BoundaryMode boundaryMode)
1784 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001785 fKS(ks),
1786 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001787 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001788}
1789
bsalomon0e08fc12014-10-15 08:19:04 -07001790bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001791 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001792 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001793 this->ks() == s.ks() &&
1794 this->shininess() == s.shininess();
1795}
1796
jvanverthcfc18862015-04-28 08:48:20 -07001797void GrSpecularLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001798 GrProcessorKeyBuilder* b) const {
1799 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1800}
1801
1802GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1803 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1804}
1805
joshualittb0a8a372014-09-23 09:50:21 -07001806GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001807
joshualittb0a8a372014-09-23 09:50:21 -07001808GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1809 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -07001810 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001811 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001812 SkScalar surfaceScale = random->nextSScalar1();
1813 SkScalar ks = random->nextUScalar1();
1814 SkScalar shininess = random->nextUScalar1();
1815 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001816 SkMatrix matrix;
1817 for (int i = 0; i < 9; i++) {
1818 matrix[i] = random->nextUScalar1();
1819 }
senorblancod0d37ca2015-04-02 04:54:56 -07001820 BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount);
joshualittb0a8a372014-09-23 09:50:21 -07001821 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001822 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001823}
1824
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001825///////////////////////////////////////////////////////////////////////////////
1826
joshualitteb2a6762014-12-04 11:35:33 -08001827GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1828 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001829}
1830
joshualitt15988992014-10-09 15:04:05 -07001831void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001832 const char* ks;
1833 const char* shininess;
1834
joshualitt30ba4362014-08-21 20:18:45 -07001835 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001836 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001837 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001838 kFloat_GrSLType,
1839 kDefault_GrSLPrecision,
1840 "Shininess",
1841 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001842
1843 static const GrGLShaderVar gLightArgs[] = {
1844 GrGLShaderVar("normal", kVec3f_GrSLType),
1845 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1846 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1847 };
1848 SkString lightBody;
1849 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1850 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001851 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1852 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001853 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1854 "light",
1855 SK_ARRAY_COUNT(gLightArgs),
1856 gLightArgs,
1857 lightBody.c_str(),
1858 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001859}
1860
kkinnunen7510b222014-07-30 00:04:16 -07001861void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001862 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001863 INHERITED::setData(pdman, effect);
1864 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001865 pdman.set1f(fKSUni, spec.ks());
1866 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001867}
1868
1869///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001870void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001871 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001872 kVec3f_GrSLType, kDefault_GrSLPrecision,
1873 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001874}
1875
joshualitt15988992014-10-09 15:04:05 -07001876void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001877 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001878 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001879}
1880
kkinnunen7510b222014-07-30 00:04:16 -07001881void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001882 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001883 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001884}
1885
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001886///////////////////////////////////////////////////////////////////////////////
1887
kkinnunen7510b222014-07-30 00:04:16 -07001888void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001889 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001890 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001891 SkASSERT(light->type() == SkLight::kDistant_LightType);
1892 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001893 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001894}
1895
joshualitt15988992014-10-09 15:04:05 -07001896void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001897 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001898 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1899 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001900 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001901 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001902}
1903
1904///////////////////////////////////////////////////////////////////////////////
1905
kkinnunen7510b222014-07-30 00:04:16 -07001906void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001907 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001908 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001909 SkASSERT(light->type() == SkLight::kPoint_LightType);
1910 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001911 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001912}
1913
joshualitt15988992014-10-09 15:04:05 -07001914void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001915 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001916 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1917 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001918 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001919 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001920 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1921 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001922}
1923
1924///////////////////////////////////////////////////////////////////////////////
1925
kkinnunen7510b222014-07-30 00:04:16 -07001926void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001927 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001928 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001929 SkASSERT(light->type() == SkLight::kSpot_LightType);
1930 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001931 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1932 pdman.set1f(fExponentUni, spotLight->specularExponent());
1933 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1934 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1935 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1936 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001937}
1938
joshualitt15988992014-10-09 15:04:05 -07001939void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001940 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001941 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001942 kVec3f_GrSLType, kDefault_GrSLPrecision,
1943 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001944
egdaniel29bee0f2015-04-29 11:54:42 -07001945 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001946 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1947 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001948}
1949
joshualitt15988992014-10-09 15:04:05 -07001950void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001951 const char *surfaceToLight) {
1952
1953 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1954
1955 const char* exponent;
1956 const char* cosInner;
1957 const char* cosOuter;
1958 const char* coneScale;
1959 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001960 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001961 kFloat_GrSLType, kDefault_GrSLPrecision,
1962 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001963 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001964 kFloat_GrSLType, kDefault_GrSLPrecision,
1965 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001966 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001967 kFloat_GrSLType, kDefault_GrSLPrecision,
1968 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001969 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001970 kFloat_GrSLType, kDefault_GrSLPrecision,
1971 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001972 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001973 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001974
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001975 static const GrGLShaderVar gLightColorArgs[] = {
1976 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1977 };
1978 SkString lightColorBody;
1979 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1980 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1981 lightColorBody.appendf("\t\treturn vec3(0);\n");
1982 lightColorBody.appendf("\t}\n");
1983 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1984 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1985 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1986 color, cosOuter, coneScale);
1987 lightColorBody.appendf("\t}\n");
1988 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07001989 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001990 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001991 "lightColor",
1992 SK_ARRAY_COUNT(gLightColorArgs),
1993 gLightColorArgs,
1994 lightColorBody.c_str(),
1995 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001996
joshualitt30ba4362014-08-21 20:18:45 -07001997 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001998}
1999
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002000#endif
2001
djsollen@google.com08337772012-06-26 14:33:13 +00002002SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2003 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2004 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002005SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END