blob: 0df6f7a76f018e80a734ffde3f650be6c09fc7a9 [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;
joshualitt5f10b5c2015-07-09 10:24:35 -0700309 virtual GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*,
310 GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700311 const SkMatrix&,
312 const SkIRect& bounds,
313 BoundaryMode boundaryMode) const = 0;
314#endif
315private:
316#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700317 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700318 GrTexture* src,
319 GrTexture* dst,
320 const SkMatrix& matrix,
321 const GrClip& clip,
322 const SkRect& dstRect,
323 BoundaryMode boundaryMode,
324 const SkIRect& bounds) const;
325#endif
326 typedef SkLightingImageFilter INHERITED;
327};
328
329#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700330void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700331 GrTexture* src,
332 GrTexture* dst,
333 const SkMatrix& matrix,
334 const GrClip& clip,
335 const SkRect& dstRect,
336 BoundaryMode boundaryMode,
337 const SkIRect& bounds) const {
338 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700339 GrPaint paint;
joshualitt5f10b5c2015-07-09 10:24:35 -0700340 GrFragmentProcessor* fp = this->getFragmentProcessor(paint.getProcessorDataManager(), src,
341 matrix, bounds, boundaryMode);
senorblancod0d37ca2015-04-02 04:54:56 -0700342 paint.addColorProcessor(fp)->unref();
robertphillipsea461502015-05-26 11:38:03 -0700343 drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
344 dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700345}
346
347bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
348 const SkBitmap& src,
349 const Context& ctx,
350 SkBitmap* result,
351 SkIPoint* offset) const {
352 SkBitmap input = src;
353 SkIPoint srcOffset = SkIPoint::Make(0, 0);
354 if (this->getInput(0) &&
355 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
356 return false;
357 }
358 SkIRect bounds;
359 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
360 return false;
361 }
362 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
363 SkIntToScalar(bounds.height()));
364 GrTexture* srcTexture = input.getTexture();
365 GrContext* context = srcTexture->getContext();
366
367 GrSurfaceDesc desc;
368 desc.fFlags = kRenderTarget_GrSurfaceFlag,
369 desc.fWidth = bounds.width();
370 desc.fHeight = bounds.height();
371 desc.fConfig = kRGBA_8888_GrPixelConfig;
372
bsalomond309e7a2015-04-30 14:18:54 -0700373 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(desc,
374 GrTextureProvider::kApprox_ScratchTexMatch));
senorblancod0d37ca2015-04-02 04:54:56 -0700375 if (!dst) {
376 return false;
377 }
378
379 // setup new clip
380 GrClip clip(dstRect);
381
382 offset->fX = bounds.left();
383 offset->fY = bounds.top();
384 SkMatrix matrix(ctx.ctm());
385 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
386 bounds.offset(-srcOffset);
387 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
388 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
389 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
390 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
391 SkRect interior = dstRect.makeInset(1, 1);
392 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
393 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
394 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
395 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700396
397 GrDrawContext* drawContext = context->drawContext();
398 if (!drawContext) {
399 return false;
400 }
401
402 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700403 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700404 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
405 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700406 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700407 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
408 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700409 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700410 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
411 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700412 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700413 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
414 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
415 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700416 WrapTexture(dst, bounds.width(), bounds.height(), result);
417 return true;
418}
419#endif
420
421class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000422public:
reed9fa60da2014-08-21 07:59:51 -0700423 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700424 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700425
robertphillipsf3f5bad2014-12-19 13:49:15 -0800426 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000427 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000428 SkScalar kd() const { return fKD; }
429
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000430protected:
reed9fa60da2014-08-21 07:59:51 -0700431 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700432 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700433 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700434 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
435 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000436#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700437 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700438 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000439#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000440
441private:
reed9fa60da2014-08-21 07:59:51 -0700442 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700443 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000444 SkScalar fKD;
445};
446
senorblancod0d37ca2015-04-02 04:54:56 -0700447class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000448public:
reed9fa60da2014-08-21 07:59:51 -0700449 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700450 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700451
robertphillipsf3f5bad2014-12-19 13:49:15 -0800452 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000453 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
454
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000455 SkScalar ks() const { return fKS; }
456 SkScalar shininess() const { return fShininess; }
457
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000458protected:
reed9fa60da2014-08-21 07:59:51 -0700459 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700460 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700461 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700462 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
463 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000464#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700465 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700466 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000467#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000468
469private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000470 SkScalar fKS;
471 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700472 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700473 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000474};
475
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000476#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000477
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000478class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000479public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700480 GrLightingEffect(GrProcessorDataManager*, GrTexture* texture, const SkLight* light,
481 SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000482 virtual ~GrLightingEffect();
483
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000484 const SkLight* light() const { return fLight; }
485 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000486 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700487 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000488
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000489protected:
mtklein36352bf2015-03-25 18:17:31 -0700490 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000491
mtklein36352bf2015-03-25 18:17:31 -0700492 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700493 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800494 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700495 }
496
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000497private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000498 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000499 const SkLight* fLight;
500 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000501 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700502 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000503};
504
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000505class GrDiffuseLightingEffect : public GrLightingEffect {
506public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700507 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
508 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700509 const SkLight* light,
510 SkScalar surfaceScale,
511 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700512 SkScalar kd,
513 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700514 return SkNEW_ARGS(GrDiffuseLightingEffect, (procDataManager,
515 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700516 light,
517 surfaceScale,
518 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700519 kd,
520 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000521 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000522
mtklein36352bf2015-03-25 18:17:31 -0700523 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000524
jvanverthcfc18862015-04-28 08:48:20 -0700525 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000526
mtklein36352bf2015-03-25 18:17:31 -0700527 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800528
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000530
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000531private:
mtklein36352bf2015-03-25 18:17:31 -0700532 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000533
joshualitt5f10b5c2015-07-09 10:24:35 -0700534 GrDiffuseLightingEffect(GrProcessorDataManager*,
535 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000536 const SkLight* light,
537 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000538 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700539 SkScalar kd,
540 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000541
joshualittb0a8a372014-09-23 09:50:21 -0700542 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000543 typedef GrLightingEffect INHERITED;
544 SkScalar fKD;
545};
546
547class GrSpecularLightingEffect : public GrLightingEffect {
548public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700549 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
550 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700551 const SkLight* light,
552 SkScalar surfaceScale,
553 const SkMatrix& matrix,
554 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700555 SkScalar shininess,
556 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700557 return SkNEW_ARGS(GrSpecularLightingEffect, (procDataManager,
558 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700559 light,
560 surfaceScale,
561 matrix,
562 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700563 shininess,
564 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000565 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000566
mtklein36352bf2015-03-25 18:17:31 -0700567 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000568
jvanverthcfc18862015-04-28 08:48:20 -0700569 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800570
mtklein36352bf2015-03-25 18:17:31 -0700571 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800572
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000573 SkScalar ks() const { return fKS; }
574 SkScalar shininess() const { return fShininess; }
575
576private:
mtklein36352bf2015-03-25 18:17:31 -0700577 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000578
joshualitt5f10b5c2015-07-09 10:24:35 -0700579 GrSpecularLightingEffect(GrProcessorDataManager*,
580 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000581 const SkLight* light,
582 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000583 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000584 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700585 SkScalar shininess,
586 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000587
joshualittb0a8a372014-09-23 09:50:21 -0700588 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000589 typedef GrLightingEffect INHERITED;
590 SkScalar fKS;
591 SkScalar fShininess;
592};
593
594///////////////////////////////////////////////////////////////////////////////
595
596class GrGLLight {
597public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000598 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000599
600 /**
601 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
602 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
603 */
joshualitt15988992014-10-09 15:04:05 -0700604 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000605
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000606 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000607 * These two functions are called from GrGLLightingEffect's emitCode() function.
608 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
609 * the light. The expression will be used in the FS. emitLightColor writes an expression into
610 * the FS that is the color of the light. Either function may add functions and/or uniforms to
611 * the FS. The default of emitLightColor appends the name of the constant light color uniform
612 * and so this function only needs to be overridden if the light color varies spatially.
613 */
joshualitt15988992014-10-09 15:04:05 -0700614 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
615 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000616
617 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
618 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700619 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000620 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000621
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000622protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000623 /**
624 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
625 * function.
626 */
627 UniformHandle lightColorUni() const { return fColorUni; }
628
629private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000630 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000631
632 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633};
634
635///////////////////////////////////////////////////////////////////////////////
636
637class GrGLDistantLight : public GrGLLight {
638public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000639 virtual ~GrGLDistantLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700640 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700641 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000642
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000643private:
644 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000645 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000646};
647
648///////////////////////////////////////////////////////////////////////////////
649
650class GrGLPointLight : public GrGLLight {
651public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000652 virtual ~GrGLPointLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700653 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700654 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000655
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000656private:
657 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000658 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000659};
660
661///////////////////////////////////////////////////////////////////////////////
662
663class GrGLSpotLight : public GrGLLight {
664public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000665 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700666 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700667 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
668 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000669
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000670private:
671 typedef GrGLLight INHERITED;
672
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000673 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000674 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000675 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000676 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000677 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000678 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000679 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000680};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000681#else
682
683class GrGLLight;
684
685#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000686
687};
688
689///////////////////////////////////////////////////////////////////////////////
690
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000691class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000692public:
mtklein2766c002015-06-26 11:45:03 -0700693
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000694
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695 enum LightType {
696 kDistant_LightType,
697 kPoint_LightType,
698 kSpot_LightType,
699 };
700 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000701 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000702 virtual GrGLLight* createGLLight() const = 0;
703 virtual bool isEqual(const SkLight& other) const {
704 return fColor == other.fColor;
705 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000706 // Called to know whether the generated GrGLLight will require access to the fragment position.
707 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000708 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000709
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000710 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000711 void flattenLight(SkWriteBuffer& buffer) const;
712 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000713
djsollen@google.com08337772012-06-26 14:33:13 +0000714protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000715 SkLight(SkColor color)
716 : fColor(SkIntToScalar(SkColorGetR(color)),
717 SkIntToScalar(SkColorGetG(color)),
718 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000719 SkLight(const SkPoint3& color)
720 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000721 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000722 fColor = readPoint3(buffer);
723 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000724
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000725 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000726
djsollen@google.com08337772012-06-26 14:33:13 +0000727
728private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000729 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000730 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731};
732
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000733///////////////////////////////////////////////////////////////////////////////
734
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000735class SkDistantLight : public SkLight {
736public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000737 SkDistantLight(const SkPoint3& direction, SkColor color)
738 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000739 }
djsollen@google.com08337772012-06-26 14:33:13 +0000740
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000741 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
742 return fDirection;
743 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000744 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700745 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000746 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700747 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000748#if SK_SUPPORT_GPU
749 return SkNEW(GrGLDistantLight);
750#else
751 SkDEBUGFAIL("Should not call in GPU-less build");
752 return NULL;
753#endif
754 }
mtklein36352bf2015-03-25 18:17:31 -0700755 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000756
mtklein36352bf2015-03-25 18:17:31 -0700757 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000758 if (other.type() != kDistant_LightType) {
759 return false;
760 }
761
762 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
763 return INHERITED::isEqual(other) &&
764 fDirection == o.fDirection;
765 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000766
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000767 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000768 fDirection = readPoint3(buffer);
769 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000770
djsollen@google.com08337772012-06-26 14:33:13 +0000771protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000772 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
773 : INHERITED(color), fDirection(direction) {
774 }
mtklein36352bf2015-03-25 18:17:31 -0700775 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000776 return new SkDistantLight(direction(), color());
777 }
mtklein36352bf2015-03-25 18:17:31 -0700778 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000779 writePoint3(fDirection, buffer);
780 }
781
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000782private:
djsollen@google.com08337772012-06-26 14:33:13 +0000783 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784 SkPoint3 fDirection;
785};
786
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000787///////////////////////////////////////////////////////////////////////////////
788
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000789class SkPointLight : public SkLight {
790public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000791 SkPointLight(const SkPoint3& location, SkColor color)
792 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000793
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000794 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
795 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
796 fLocation.fY - SkIntToScalar(y),
797 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
798 direction.normalize();
799 return direction;
800 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000801 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700802 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000803 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700804 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000805#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000806 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000807#else
808 SkDEBUGFAIL("Should not call in GPU-less build");
809 return NULL;
810#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000811 }
mtklein36352bf2015-03-25 18:17:31 -0700812 bool requiresFragmentPosition() const override { return true; }
813 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000814 if (other.type() != kPoint_LightType) {
815 return false;
816 }
817 const SkPointLight& o = static_cast<const SkPointLight&>(other);
818 return INHERITED::isEqual(other) &&
819 fLocation == o.fLocation;
820 }
mtklein36352bf2015-03-25 18:17:31 -0700821 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000822 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
823 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000824 // Use X scale and Y scale on Z and average the result
825 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
826 matrix.mapVectors(&locationZ, 1);
827 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000828 return new SkPointLight(location, color());
829 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000830
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000831 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000832 fLocation = readPoint3(buffer);
833 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000834
835protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000836 SkPointLight(const SkPoint3& location, const SkPoint3& color)
837 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700838 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000839 writePoint3(fLocation, buffer);
840 }
841
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000842private:
djsollen@google.com08337772012-06-26 14:33:13 +0000843 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000844 SkPoint3 fLocation;
845};
846
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000847///////////////////////////////////////////////////////////////////////////////
848
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000849class SkSpotLight : public SkLight {
850public:
senorblancod0d37ca2015-04-02 04:54:56 -0700851 SkSpotLight(const SkPoint3& location,
852 const SkPoint3& target,
853 SkScalar specularExponent,
854 SkScalar cutoffAngle,
855 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000856 : INHERITED(color),
857 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000858 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000859 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000860 {
861 fS = target - location;
862 fS.normalize();
863 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000864 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000865 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
866 fConeScale = SkScalarInvert(antiAliasThreshold);
867 }
djsollen@google.com08337772012-06-26 14:33:13 +0000868
mtklein36352bf2015-03-25 18:17:31 -0700869 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000870 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
871 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000872 // Use X scale and Y scale on Z and average the result
873 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
874 matrix.mapVectors(&locationZ, 1);
875 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000876 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
877 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000878 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
879 matrix.mapVectors(&targetZ, 1);
880 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
881 SkPoint3 s = target - location;
882 s.normalize();
senorblancod0d37ca2015-04-02 04:54:56 -0700883 return new SkSpotLight(location,
884 target,
885 fSpecularExponent,
886 fCosOuterConeAngle,
887 fCosInnerConeAngle,
888 fConeScale,
889 s,
890 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000891 }
892
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000893 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
894 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
895 fLocation.fY - SkIntToScalar(y),
896 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
897 direction.normalize();
898 return direction;
899 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000900 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000901 SkScalar cosAngle = -surfaceToLight.dot(fS);
902 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000903 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904 }
905 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
906 if (cosAngle < fCosInnerConeAngle) {
907 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000908 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000909 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000910 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 }
mtklein36352bf2015-03-25 18:17:31 -0700912 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000913#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000914 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000915#else
916 SkDEBUGFAIL("Should not call in GPU-less build");
917 return NULL;
918#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000919 }
mtklein36352bf2015-03-25 18:17:31 -0700920 bool requiresFragmentPosition() const override { return true; }
921 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000922 const SkPoint3& location() const { return fLocation; }
923 const SkPoint3& target() const { return fTarget; }
924 SkScalar specularExponent() const { return fSpecularExponent; }
925 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
926 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
927 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000928 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000929
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000930 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000931 fLocation = readPoint3(buffer);
932 fTarget = readPoint3(buffer);
933 fSpecularExponent = buffer.readScalar();
934 fCosOuterConeAngle = buffer.readScalar();
935 fCosInnerConeAngle = buffer.readScalar();
936 fConeScale = buffer.readScalar();
937 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000938 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
939 SkScalarIsFinite(fCosOuterConeAngle) &&
940 SkScalarIsFinite(fCosInnerConeAngle) &&
941 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000942 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000943protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700944 SkSpotLight(const SkPoint3& location,
945 const SkPoint3& target,
946 SkScalar specularExponent,
947 SkScalar cosOuterConeAngle,
948 SkScalar cosInnerConeAngle,
949 SkScalar coneScale,
950 const SkPoint3& s,
951 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000952 : INHERITED(color),
953 fLocation(location),
954 fTarget(target),
955 fSpecularExponent(specularExponent),
956 fCosOuterConeAngle(cosOuterConeAngle),
957 fCosInnerConeAngle(cosInnerConeAngle),
958 fConeScale(coneScale),
959 fS(s)
960 {
961 }
mtklein36352bf2015-03-25 18:17:31 -0700962 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000963 writePoint3(fLocation, buffer);
964 writePoint3(fTarget, buffer);
965 buffer.writeScalar(fSpecularExponent);
966 buffer.writeScalar(fCosOuterConeAngle);
967 buffer.writeScalar(fCosInnerConeAngle);
968 buffer.writeScalar(fConeScale);
969 writePoint3(fS, buffer);
970 }
971
mtklein36352bf2015-03-25 18:17:31 -0700972 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000973 if (other.type() != kSpot_LightType) {
974 return false;
975 }
976
977 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
978 return INHERITED::isEqual(other) &&
979 fLocation == o.fLocation &&
980 fTarget == o.fTarget &&
981 fSpecularExponent == o.fSpecularExponent &&
982 fCosOuterConeAngle == o.fCosOuterConeAngle;
983 }
984
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000985private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000986 static const SkScalar kSpecularExponentMin;
987 static const SkScalar kSpecularExponentMax;
988
djsollen@google.com08337772012-06-26 14:33:13 +0000989 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000990 SkPoint3 fLocation;
991 SkPoint3 fTarget;
992 SkScalar fSpecularExponent;
993 SkScalar fCosOuterConeAngle;
994 SkScalar fCosInnerConeAngle;
995 SkScalar fConeScale;
996 SkPoint3 fS;
997};
998
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000999// According to the spec, the specular term should be in the range [1, 128] :
1000// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001001const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1002const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001003
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001004///////////////////////////////////////////////////////////////////////////////
1005
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001006void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001007 // Write type first, then baseclass, then subclass.
1008 buffer.writeInt(this->type());
1009 writePoint3(fColor, buffer);
1010 this->onFlattenLight(buffer);
1011}
1012
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001013/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001014 // Read type first.
1015 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
1016 switch (type) {
1017 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1018 // then subclass, same order as flattenLight.
1019 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1020 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1021 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1022 default:
1023 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001024 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001025 return NULL;
1026 }
1027}
1028///////////////////////////////////////////////////////////////////////////////
1029
senorblanco9ea3d572014-07-08 09:16:22 -07001030SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001031 SkImageFilter* input, const CropRect* cropRect)
1032 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001033 , fLight(SkRef(light))
1034 , fSurfaceScale(surfaceScale / 255)
1035{}
1036
1037SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1038 SkColor lightColor,
1039 SkScalar surfaceScale,
1040 SkScalar kd,
1041 SkImageFilter* input,
1042 const CropRect* cropRect) {
1043 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1044 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001045}
1046
reed9fa60da2014-08-21 07:59:51 -07001047SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1048 SkColor lightColor,
1049 SkScalar surfaceScale,
1050 SkScalar kd,
1051 SkImageFilter* input,
1052 const CropRect* cropRect) {
1053 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1054 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001055}
1056
reed9fa60da2014-08-21 07:59:51 -07001057SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1058 const SkPoint3& target,
1059 SkScalar specularExponent,
1060 SkScalar cutoffAngle,
1061 SkColor lightColor,
1062 SkScalar surfaceScale,
1063 SkScalar kd,
1064 SkImageFilter* input,
1065 const CropRect* cropRect) {
1066 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1067 cutoffAngle, lightColor)));
1068 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001069}
1070
reed9fa60da2014-08-21 07:59:51 -07001071SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1072 SkColor lightColor,
1073 SkScalar surfaceScale,
1074 SkScalar ks,
1075 SkScalar shine,
1076 SkImageFilter* input,
1077 const CropRect* cropRect) {
1078 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1079 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001080}
1081
reed9fa60da2014-08-21 07:59:51 -07001082SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1083 SkColor lightColor,
1084 SkScalar surfaceScale,
1085 SkScalar ks,
1086 SkScalar shine,
1087 SkImageFilter* input,
1088 const CropRect* cropRect) {
1089 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1090 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001091}
1092
reed9fa60da2014-08-21 07:59:51 -07001093SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1094 const SkPoint3& target,
1095 SkScalar specularExponent,
1096 SkScalar cutoffAngle,
1097 SkColor lightColor,
1098 SkScalar surfaceScale,
1099 SkScalar ks,
1100 SkScalar shine,
1101 SkImageFilter* input,
1102 const CropRect* cropRect) {
1103 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1104 cutoffAngle, lightColor)));
1105 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001106}
1107
reed9fa60da2014-08-21 07:59:51 -07001108SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001109
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001110void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001111 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001112 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001113 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001114}
1115
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001116///////////////////////////////////////////////////////////////////////////////
1117
reed9fa60da2014-08-21 07:59:51 -07001118SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001119 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001120 if (NULL == light) {
1121 return NULL;
1122 }
1123 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1124 return NULL;
1125 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001126 // According to the spec, kd can be any non-negative number :
1127 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001128 if (kd < 0) {
1129 return NULL;
1130 }
senorblanco24e06d52015-03-18 12:11:33 -07001131 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001132}
1133
senorblancod0d37ca2015-04-02 04:54:56 -07001134SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1135 SkScalar surfaceScale,
1136 SkScalar kd,
1137 SkImageFilter* input,
1138 const CropRect* cropRect)
1139 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001140 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001141{
1142}
1143
reed9fa60da2014-08-21 07:59:51 -07001144SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1145 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1146 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1147 SkScalar surfaceScale = buffer.readScalar();
1148 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001149 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001150}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001151
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001152void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001153 this->INHERITED::flatten(buffer);
1154 buffer.writeScalar(fKD);
1155}
1156
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001157bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1158 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001159 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001160 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001161 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001162 SkImageFilter* input = getInput(0);
1163 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001164 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001165 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001166 return false;
1167 }
1168
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001169 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170 return false;
1171 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001172 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001173 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001174 return false;
1175 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001176
1177 if (bounds.width() < 2 || bounds.height() < 2) {
1178 return false;
1179 }
1180
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001181 SkAutoLockPixels alp(src);
1182 if (!src.getPixels()) {
1183 return false;
1184 }
1185
reed84825042014-09-02 12:50:45 -07001186 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001187 return false;
1188 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001189
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001190 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001191
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001192 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001193 offset->fX = bounds.left();
1194 offset->fY = bounds.top();
1195 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001196 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001197 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001198 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1199 transformedLight,
1200 src,
1201 dst,
1202 surfaceScale(),
1203 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001204 break;
1205 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001206 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1207 transformedLight,
1208 src,
1209 dst,
1210 surfaceScale(),
1211 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001212 break;
1213 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001214 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1215 transformedLight,
1216 src,
1217 dst,
1218 surfaceScale(),
1219 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001220 break;
1221 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001222
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001223 return true;
1224}
1225
robertphillipsf3f5bad2014-12-19 13:49:15 -08001226#ifndef SK_IGNORE_TO_STRING
1227void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1228 str->appendf("SkDiffuseLightingImageFilter: (");
1229 str->appendf("kD: %f\n", fKD);
1230 str->append(")");
1231}
1232#endif
1233
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001234#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001235GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001236 GrProcessorDataManager* procDataManager,
1237 GrTexture* texture,
1238 const SkMatrix& matrix,
1239 const SkIRect&,
1240 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001241) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001242 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1243 return GrDiffuseLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1244 this->kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001245}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001246#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001247
1248///////////////////////////////////////////////////////////////////////////////
1249
reed9fa60da2014-08-21 07:59:51 -07001250SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001251 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001252 if (NULL == light) {
1253 return NULL;
1254 }
1255 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1256 return NULL;
1257 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001258 // According to the spec, ks can be any non-negative number :
1259 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001260 if (ks < 0) {
1261 return NULL;
1262 }
1263 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001264 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001265}
1266
senorblancod0d37ca2015-04-02 04:54:56 -07001267SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1268 SkScalar surfaceScale,
1269 SkScalar ks,
1270 SkScalar shininess,
1271 SkImageFilter* input,
1272 const CropRect* cropRect)
1273 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001274 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001275 fShininess(shininess)
1276{
1277}
1278
reed9fa60da2014-08-21 07:59:51 -07001279SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1280 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1281 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1282 SkScalar surfaceScale = buffer.readScalar();
1283 SkScalar ks = buffer.readScalar();
1284 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001285 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001286}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001287
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001288void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001289 this->INHERITED::flatten(buffer);
1290 buffer.writeScalar(fKS);
1291 buffer.writeScalar(fShininess);
1292}
1293
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001294bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1295 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001296 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001297 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001298 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001299 SkImageFilter* input = getInput(0);
1300 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001301 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001302 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001303 return false;
1304 }
1305
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001306 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001307 return false;
1308 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001309
1310 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001311 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001312 return false;
1313 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001314
1315 if (bounds.width() < 2 || bounds.height() < 2) {
1316 return false;
1317 }
1318
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001319 SkAutoLockPixels alp(src);
1320 if (!src.getPixels()) {
1321 return false;
1322 }
1323
reed84825042014-09-02 12:50:45 -07001324 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001325 return false;
1326 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001327
1328 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001329 offset->fX = bounds.left();
1330 offset->fY = bounds.top();
1331 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001332 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001333 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001334 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001335 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1336 transformedLight,
1337 src,
1338 dst,
1339 surfaceScale(),
1340 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001341 break;
1342 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001343 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1344 transformedLight,
1345 src,
1346 dst,
1347 surfaceScale(),
1348 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001349 break;
1350 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001351 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1352 transformedLight,
1353 src,
1354 dst,
1355 surfaceScale(),
1356 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001357 break;
1358 }
1359 return true;
1360}
1361
robertphillipsf3f5bad2014-12-19 13:49:15 -08001362#ifndef SK_IGNORE_TO_STRING
1363void SkSpecularLightingImageFilter::toString(SkString* str) const {
1364 str->appendf("SkSpecularLightingImageFilter: (");
1365 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1366 str->append(")");
1367}
1368#endif
1369
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001370#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001371GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001372 GrProcessorDataManager* procDataManager,
1373 GrTexture* texture,
1374 const SkMatrix& matrix,
1375 const SkIRect&,
1376 BoundaryMode boundaryMode) const {
1377 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1378 return GrSpecularLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1379 this->ks(), this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001380}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001381#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001382
1383///////////////////////////////////////////////////////////////////////////////
1384
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001385#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001386
1387namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001388SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001389 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1390 SkScalarToFloat(random->nextSScalar1()),
1391 SkScalarToFloat(random->nextSScalar1()));
1392}
1393
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001394SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001395 int type = random->nextULessThan(3);
1396 switch (type) {
1397 case 0: {
1398 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1399 }
1400 case 1: {
1401 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1402 }
1403 case 2: {
1404 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1405 random_point3(random),
1406 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001407 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001408 random->nextU()));
1409 }
1410 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001411 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001412 return NULL;
1413 }
1414}
1415
senorblancod0d37ca2015-04-02 04:54:56 -07001416SkString emitNormalFunc(BoundaryMode mode,
1417 const char* pointToNormalName,
1418 const char* sobelFuncName) {
1419 SkString result;
1420 switch (mode) {
1421 case kTopLeft_BoundaryMode:
1422 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1423 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1424 "\t surfaceScale);\n",
1425 pointToNormalName, sobelFuncName, gTwoThirds,
1426 sobelFuncName, gTwoThirds);
1427 break;
1428 case kTop_BoundaryMode:
1429 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1430 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1431 "\t surfaceScale);\n",
1432 pointToNormalName, sobelFuncName, gOneThird,
1433 sobelFuncName, gOneHalf);
1434 break;
1435 case kTopRight_BoundaryMode:
1436 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1437 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1438 "\t surfaceScale);\n",
1439 pointToNormalName, sobelFuncName, gTwoThirds,
1440 sobelFuncName, gTwoThirds);
1441 break;
1442 case kLeft_BoundaryMode:
1443 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1444 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1445 "\t surfaceScale);\n",
1446 pointToNormalName, sobelFuncName, gOneHalf,
1447 sobelFuncName, gOneThird);
1448 break;
1449 case kInterior_BoundaryMode:
1450 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1451 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1452 "\t surfaceScale);\n",
1453 pointToNormalName, sobelFuncName, gOneQuarter,
1454 sobelFuncName, gOneQuarter);
1455 break;
1456 case kRight_BoundaryMode:
1457 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1458 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1459 "\t surfaceScale);\n",
1460 pointToNormalName, sobelFuncName, gOneHalf,
1461 sobelFuncName, gOneThird);
1462 break;
1463 case kBottomLeft_BoundaryMode:
1464 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1465 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1466 "\t surfaceScale);\n",
1467 pointToNormalName, sobelFuncName, gTwoThirds,
1468 sobelFuncName, gTwoThirds);
1469 break;
1470 case kBottom_BoundaryMode:
1471 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1472 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1473 "\t surfaceScale);\n",
1474 pointToNormalName, sobelFuncName, gOneThird,
1475 sobelFuncName, gOneHalf);
1476 break;
1477 case kBottomRight_BoundaryMode:
1478 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1479 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1480 "\t surfaceScale);\n",
1481 pointToNormalName, sobelFuncName, gTwoThirds,
1482 sobelFuncName, gTwoThirds);
1483 break;
1484 default:
1485 SkASSERT(false);
1486 break;
1487 }
1488 return result;
1489}
1490
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001491}
1492
joshualittb0a8a372014-09-23 09:50:21 -07001493class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001494public:
joshualitteb2a6762014-12-04 11:35:33 -08001495 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001496 virtual ~GrGLLightingEffect();
1497
senorblancod0d37ca2015-04-02 04:54:56 -07001498 void emitCode(GrGLFPBuilder*,
1499 const GrFragmentProcessor&,
1500 const char* outputColor,
1501 const char* inputColor,
1502 const TransformedCoordsArray&,
1503 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001504
jvanverthcfc18862015-04-28 08:48:20 -07001505 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001506
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001507 /**
1508 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1509 */
mtklein36352bf2015-03-25 18:17:31 -07001510 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001511
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001512protected:
joshualitt15988992014-10-09 15:04:05 -07001513 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001514
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001515private:
joshualittb0a8a372014-09-23 09:50:21 -07001516 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001517
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001518 UniformHandle fImageIncrementUni;
1519 UniformHandle fSurfaceScaleUni;
1520 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001521 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001522};
1523
1524///////////////////////////////////////////////////////////////////////////////
1525
1526class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1527public:
joshualitteb2a6762014-12-04 11:35:33 -08001528 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001529 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1530 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001531
1532private:
1533 typedef GrGLLightingEffect INHERITED;
1534
bsalomon@google.com032b2212012-07-16 13:36:18 +00001535 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001536};
1537
1538///////////////////////////////////////////////////////////////////////////////
1539
1540class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1541public:
joshualitteb2a6762014-12-04 11:35:33 -08001542 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001543 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1544 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001545
1546private:
1547 typedef GrGLLightingEffect INHERITED;
1548
bsalomon@google.com032b2212012-07-16 13:36:18 +00001549 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001550 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001551};
1552
1553///////////////////////////////////////////////////////////////////////////////
1554
joshualitt5f10b5c2015-07-09 10:24:35 -07001555GrLightingEffect::GrLightingEffect(GrProcessorDataManager* procDataManager,
1556 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001557 const SkLight* light,
1558 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001559 const SkMatrix& matrix,
1560 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001561 : INHERITED(procDataManager, texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001562 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001563 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001564 , fFilterMatrix(matrix)
1565 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001566 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001567 if (light->requiresFragmentPosition()) {
1568 this->setWillReadFragmentPosition();
1569 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001570}
1571
1572GrLightingEffect::~GrLightingEffect() {
1573 fLight->unref();
1574}
1575
bsalomon0e08fc12014-10-15 08:19:04 -07001576bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001577 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001578 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001579 fSurfaceScale == s.fSurfaceScale &&
1580 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001581}
1582
1583///////////////////////////////////////////////////////////////////////////////
1584
joshualitt5f10b5c2015-07-09 10:24:35 -07001585GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrProcessorDataManager* procDataManager,
1586 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001587 const SkLight* light,
1588 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001589 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001590 SkScalar kd,
1591 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001592 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001593 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001594}
1595
bsalomon0e08fc12014-10-15 08:19:04 -07001596bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001597 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001598 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001599 this->kd() == s.kd();
1600}
1601
jvanverthcfc18862015-04-28 08:48:20 -07001602void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001603 GrProcessorKeyBuilder* b) const {
1604 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1605}
1606
1607GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1608 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1609}
1610
joshualittb0a8a372014-09-23 09:50:21 -07001611GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001612
joshualitt0067ff52015-07-08 14:26:19 -07001613GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
1614 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1615 SkScalar kd = d->fRandom->nextUScalar1();
1616 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001617 SkMatrix matrix;
1618 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001619 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001620 }
joshualitt0067ff52015-07-08 14:26:19 -07001621 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001622 return GrDiffuseLightingEffect::Create(d->fProcDataManager,
1623 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001624 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001625}
1626
1627
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001628///////////////////////////////////////////////////////////////////////////////
1629
joshualitteb2a6762014-12-04 11:35:33 -08001630GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001631 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001632 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001633 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001634}
1635
1636GrGLLightingEffect::~GrGLLightingEffect() {
1637 delete fLight;
1638}
1639
joshualitt15988992014-10-09 15:04:05 -07001640void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001641 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001642 const char* outputColor,
1643 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001644 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001645 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001646 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001647 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001648 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001649 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001650 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001651 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001652 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001653 SkString lightFunc;
1654 this->emitLightFunc(builder, &lightFunc);
1655 static const GrGLShaderVar gSobelArgs[] = {
1656 GrGLShaderVar("a", kFloat_GrSLType),
1657 GrGLShaderVar("b", kFloat_GrSLType),
1658 GrGLShaderVar("c", kFloat_GrSLType),
1659 GrGLShaderVar("d", kFloat_GrSLType),
1660 GrGLShaderVar("e", kFloat_GrSLType),
1661 GrGLShaderVar("f", kFloat_GrSLType),
1662 GrGLShaderVar("scale", kFloat_GrSLType),
1663 };
1664 SkString sobelFuncName;
egdaniel29bee0f2015-04-29 11:54:42 -07001665 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001666 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1667
1668 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001669 "sobel",
1670 SK_ARRAY_COUNT(gSobelArgs),
1671 gSobelArgs,
1672 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1673 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001674 static const GrGLShaderVar gPointToNormalArgs[] = {
1675 GrGLShaderVar("x", kFloat_GrSLType),
1676 GrGLShaderVar("y", kFloat_GrSLType),
1677 GrGLShaderVar("scale", kFloat_GrSLType),
1678 };
1679 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001680 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001681 "pointToNormal",
1682 SK_ARRAY_COUNT(gPointToNormalArgs),
1683 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001684 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001685 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001686
1687 static const GrGLShaderVar gInteriorNormalArgs[] = {
1688 GrGLShaderVar("m", kFloat_GrSLType, 9),
1689 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1690 };
senorblancod0d37ca2015-04-02 04:54:56 -07001691 SkString normalBody = emitNormalFunc(fBoundaryMode,
1692 pointToNormalName.c_str(),
1693 sobelFuncName.c_str());
1694 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001695 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001696 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001697 SK_ARRAY_COUNT(gInteriorNormalArgs),
1698 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001699 normalBody.c_str(),
1700 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001701
joshualitt30ba4362014-08-21 20:18:45 -07001702 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1703 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001704
1705 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1706 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1707
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001708 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001709 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001710 for (int dx = -1; dx <= 1; dx++) {
1711 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001712 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001713 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1714 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1715 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001716 }
1717 }
joshualitt30ba4362014-08-21 20:18:45 -07001718 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001719 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001720 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001721 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001722 fsBuilder->codeAppend(";\n");
1723 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
senorblancod0d37ca2015-04-02 04:54:56 -07001724 outputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001725 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001726 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001727 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001728 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001729 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001730}
1731
joshualittb0a8a372014-09-23 09:50:21 -07001732void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001733 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001734 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1735 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001736}
1737
kkinnunen7510b222014-07-30 00:04:16 -07001738void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001739 const GrProcessor& proc) {
1740 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001741 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001742 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001743 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1744 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001745 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001746 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001747}
1748
1749///////////////////////////////////////////////////////////////////////////////
1750
1751///////////////////////////////////////////////////////////////////////////////
1752
joshualitteb2a6762014-12-04 11:35:33 -08001753GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1754 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001755}
1756
joshualitt15988992014-10-09 15:04:05 -07001757void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001758 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001759 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001760 kFloat_GrSLType, kDefault_GrSLPrecision,
1761 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001762
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001763 static const GrGLShaderVar gLightArgs[] = {
1764 GrGLShaderVar("normal", kVec3f_GrSLType),
1765 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1766 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1767 };
1768 SkString lightBody;
1769 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1770 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001771 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1772 "light",
1773 SK_ARRAY_COUNT(gLightArgs),
1774 gLightArgs,
1775 lightBody.c_str(),
1776 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001777}
1778
kkinnunen7510b222014-07-30 00:04:16 -07001779void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001780 const GrProcessor& proc) {
1781 INHERITED::setData(pdman, proc);
1782 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001783 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001784}
1785
1786///////////////////////////////////////////////////////////////////////////////
1787
joshualitt5f10b5c2015-07-09 10:24:35 -07001788GrSpecularLightingEffect::GrSpecularLightingEffect(GrProcessorDataManager* procDataManager,
1789 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001790 const SkLight* light,
1791 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001792 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001793 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001794 SkScalar shininess,
1795 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001796 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001797 fKS(ks),
1798 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001799 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001800}
1801
bsalomon0e08fc12014-10-15 08:19:04 -07001802bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001803 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001804 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001805 this->ks() == s.ks() &&
1806 this->shininess() == s.shininess();
1807}
1808
jvanverthcfc18862015-04-28 08:48:20 -07001809void GrSpecularLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001810 GrProcessorKeyBuilder* b) const {
1811 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1812}
1813
1814GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1815 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1816}
1817
joshualittb0a8a372014-09-23 09:50:21 -07001818GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001819
joshualitt0067ff52015-07-08 14:26:19 -07001820GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
1821 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1822 SkScalar ks = d->fRandom->nextUScalar1();
1823 SkScalar shininess = d->fRandom->nextUScalar1();
1824 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001825 SkMatrix matrix;
1826 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001827 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001828 }
joshualitt0067ff52015-07-08 14:26:19 -07001829 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001830 return GrSpecularLightingEffect::Create(d->fProcDataManager,
1831 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001832 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001833}
1834
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001835///////////////////////////////////////////////////////////////////////////////
1836
joshualitteb2a6762014-12-04 11:35:33 -08001837GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1838 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001839}
1840
joshualitt15988992014-10-09 15:04:05 -07001841void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001842 const char* ks;
1843 const char* shininess;
1844
joshualitt30ba4362014-08-21 20:18:45 -07001845 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001846 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001847 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001848 kFloat_GrSLType,
1849 kDefault_GrSLPrecision,
1850 "Shininess",
1851 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001852
1853 static const GrGLShaderVar gLightArgs[] = {
1854 GrGLShaderVar("normal", kVec3f_GrSLType),
1855 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1856 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1857 };
1858 SkString lightBody;
1859 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1860 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001861 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1862 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001863 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1864 "light",
1865 SK_ARRAY_COUNT(gLightArgs),
1866 gLightArgs,
1867 lightBody.c_str(),
1868 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001869}
1870
kkinnunen7510b222014-07-30 00:04:16 -07001871void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001872 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001873 INHERITED::setData(pdman, effect);
1874 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001875 pdman.set1f(fKSUni, spec.ks());
1876 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001877}
1878
1879///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001880void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001881 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001882 kVec3f_GrSLType, kDefault_GrSLPrecision,
1883 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001884}
1885
joshualitt15988992014-10-09 15:04:05 -07001886void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001887 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001888 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001889}
1890
kkinnunen7510b222014-07-30 00:04:16 -07001891void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001892 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001893 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001894}
1895
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001896///////////////////////////////////////////////////////////////////////////////
1897
kkinnunen7510b222014-07-30 00:04:16 -07001898void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001899 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001900 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001901 SkASSERT(light->type() == SkLight::kDistant_LightType);
1902 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001903 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001904}
1905
joshualitt15988992014-10-09 15:04:05 -07001906void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001907 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001908 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1909 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001910 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001911 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001912}
1913
1914///////////////////////////////////////////////////////////////////////////////
1915
kkinnunen7510b222014-07-30 00:04:16 -07001916void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001917 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001918 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001919 SkASSERT(light->type() == SkLight::kPoint_LightType);
1920 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001921 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001922}
1923
joshualitt15988992014-10-09 15:04:05 -07001924void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001925 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001926 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1927 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001928 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001929 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001930 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1931 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001932}
1933
1934///////////////////////////////////////////////////////////////////////////////
1935
kkinnunen7510b222014-07-30 00:04:16 -07001936void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001937 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001938 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001939 SkASSERT(light->type() == SkLight::kSpot_LightType);
1940 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001941 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1942 pdman.set1f(fExponentUni, spotLight->specularExponent());
1943 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1944 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1945 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1946 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001947}
1948
joshualitt15988992014-10-09 15:04:05 -07001949void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001950 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001951 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001952 kVec3f_GrSLType, kDefault_GrSLPrecision,
1953 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001954
egdaniel29bee0f2015-04-29 11:54:42 -07001955 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001956 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1957 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001958}
1959
joshualitt15988992014-10-09 15:04:05 -07001960void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001961 const char *surfaceToLight) {
1962
1963 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1964
1965 const char* exponent;
1966 const char* cosInner;
1967 const char* cosOuter;
1968 const char* coneScale;
1969 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001970 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001971 kFloat_GrSLType, kDefault_GrSLPrecision,
1972 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001973 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001974 kFloat_GrSLType, kDefault_GrSLPrecision,
1975 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001976 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001977 kFloat_GrSLType, kDefault_GrSLPrecision,
1978 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001979 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001980 kFloat_GrSLType, kDefault_GrSLPrecision,
1981 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001982 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001983 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001984
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001985 static const GrGLShaderVar gLightColorArgs[] = {
1986 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1987 };
1988 SkString lightColorBody;
1989 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1990 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1991 lightColorBody.appendf("\t\treturn vec3(0);\n");
1992 lightColorBody.appendf("\t}\n");
1993 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1994 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1995 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1996 color, cosOuter, coneScale);
1997 lightColorBody.appendf("\t}\n");
1998 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07001999 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002000 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002001 "lightColor",
2002 SK_ARRAY_COUNT(gLightColorArgs),
2003 gLightColorArgs,
2004 lightColorBody.c_str(),
2005 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002006
joshualitt30ba4362014-08-21 20:18:45 -07002007 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002008}
2009
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002010#endif
2011
djsollen@google.com08337772012-06-26 14:33:13 +00002012SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2013 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2014 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002015SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END