blob: 9d7ce95b07af4d966cb27d3e6e3ff657201eacb7 [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
robertphillipsea461502015-05-26 11:38:03 -070018#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080019#include "GrFragmentProcessor.h"
20#include "GrInvariantOutput.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000021#include "effects/GrSingleTextureEffect.h"
joshualittb0a8a372014-09-23 09:50:21 -070022#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070023#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000024
25class GrGLDiffuseLightingEffect;
26class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000027
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000028// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070029typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000030#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000031
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000032namespace {
33
reed80ea19c2015-05-12 10:37:34 -070034const SkScalar gOneThird = SkIntToScalar(1) / 3;
35const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000036const SkScalar gOneHalf = 0.5f;
37const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000038
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000039#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070040void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
41 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000042 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070043 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000044}
45
joshualittb0a8a372014-09-23 09:50:21 -070046void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
47 const SkPoint3& point) {
kkinnunen7510b222014-07-30 00:04:16 -070048 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000049}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000050#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000051
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000052// Shift matrix components to the left, as we advance pixels to the right.
53inline void shiftMatrixLeft(int m[9]) {
54 m[0] = m[1];
55 m[3] = m[4];
56 m[6] = m[7];
57 m[1] = m[2];
58 m[4] = m[5];
59 m[7] = m[8];
60}
61
62class DiffuseLightingType {
63public:
64 DiffuseLightingType(SkScalar kd)
65 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070066 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
67 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000068 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
69 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
70 SkPoint3 color(lightColor * colorScale);
71 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000072 SkClampMax(SkScalarRoundToInt(color.fX), 255),
73 SkClampMax(SkScalarRoundToInt(color.fY), 255),
74 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000075 }
76private:
77 SkScalar fKD;
78};
79
80class SpecularLightingType {
81public:
82 SpecularLightingType(SkScalar ks, SkScalar shininess)
83 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070084 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
85 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000086 SkPoint3 halfDir(surfaceTolight);
87 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
88 halfDir.normalize();
89 SkScalar colorScale = SkScalarMul(fKS,
90 SkScalarPow(normal.dot(halfDir), fShininess));
91 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
92 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000093 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
94 SkClampMax(SkScalarRoundToInt(color.fX), 255),
95 SkClampMax(SkScalarRoundToInt(color.fY), 255),
96 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000097 }
98private:
99 SkScalar fKS;
100 SkScalar fShininess;
101};
102
103inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
104 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
105}
106
107inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
108 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
109 SkScalarMul(-y, surfaceScale),
110 SK_Scalar1);
111 vector.normalize();
112 return vector;
113}
114
115inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
116 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
117 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
118 surfaceScale);
119}
120
121inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
122 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
123 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
124 surfaceScale);
125}
126
127inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
128 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
129 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
130 surfaceScale);
131}
132
133inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
134 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
135 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
136 surfaceScale);
137}
138
139
140inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
141 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
142 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
143 surfaceScale);
144}
145
146inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
147 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
148 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
149 surfaceScale);
150}
151
152inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
153 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
154 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
155 surfaceScale);
156}
157
158inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
160 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
161 surfaceScale);
162}
163
164inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
165 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
166 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
167 surfaceScale);
168}
169
joshualittb0a8a372014-09-23 09:50:21 -0700170template <class LightingType, class LightType> void lightBitmap(
171 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
172 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000173 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000174 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000175 int left = bounds.left(), right = bounds.right();
176 int bottom = bounds.bottom();
177 int y = bounds.top();
178 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000179 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000180 int x = left;
181 const SkPMColor* row1 = src.getAddr32(x, y);
182 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000183 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000184 m[4] = SkGetPackedA32(*row1++);
185 m[5] = SkGetPackedA32(*row1++);
186 m[7] = SkGetPackedA32(*row2++);
187 m[8] = SkGetPackedA32(*row2++);
188 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700189 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
190 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000191 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000192 {
193 shiftMatrixLeft(m);
194 m[5] = SkGetPackedA32(*row1++);
195 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000196 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700197 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
198 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000199 }
200 shiftMatrixLeft(m);
201 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700202 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
203 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 }
205
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000206 for (++y; y < bottom - 1; ++y) {
207 int x = left;
208 const SkPMColor* row0 = src.getAddr32(x, y - 1);
209 const SkPMColor* row1 = src.getAddr32(x, y);
210 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000211 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000212 m[1] = SkGetPackedA32(*row0++);
213 m[2] = SkGetPackedA32(*row0++);
214 m[4] = SkGetPackedA32(*row1++);
215 m[5] = SkGetPackedA32(*row1++);
216 m[7] = SkGetPackedA32(*row2++);
217 m[8] = SkGetPackedA32(*row2++);
218 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700219 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
220 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000221 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000222 shiftMatrixLeft(m);
223 m[2] = SkGetPackedA32(*row0++);
224 m[5] = SkGetPackedA32(*row1++);
225 m[8] = SkGetPackedA32(*row2++);
226 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700227 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
228 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000229 }
230 shiftMatrixLeft(m);
231 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700232 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
233 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000234 }
235
236 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000237 int x = left;
238 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
239 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000240 int m[9];
241 m[1] = SkGetPackedA32(*row0++);
242 m[2] = SkGetPackedA32(*row0++);
243 m[4] = SkGetPackedA32(*row1++);
244 m[5] = SkGetPackedA32(*row1++);
245 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700246 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
247 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000248 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000249 {
250 shiftMatrixLeft(m);
251 m[2] = SkGetPackedA32(*row0++);
252 m[5] = SkGetPackedA32(*row1++);
253 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700254 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
255 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000256 }
257 shiftMatrixLeft(m);
258 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700259 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
260 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000261 }
262}
263
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000264SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000265 SkPoint3 point;
266 point.fX = buffer.readScalar();
267 point.fY = buffer.readScalar();
268 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000269 buffer.validate(SkScalarIsFinite(point.fX) &&
270 SkScalarIsFinite(point.fY) &&
271 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000272 return point;
273};
274
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000275void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000276 buffer.writeScalar(point.fX);
277 buffer.writeScalar(point.fY);
278 buffer.writeScalar(point.fZ);
279};
280
senorblancod0d37ca2015-04-02 04:54:56 -0700281enum BoundaryMode {
282 kTopLeft_BoundaryMode,
283 kTop_BoundaryMode,
284 kTopRight_BoundaryMode,
285 kLeft_BoundaryMode,
286 kInterior_BoundaryMode,
287 kRight_BoundaryMode,
288 kBottomLeft_BoundaryMode,
289 kBottom_BoundaryMode,
290 kBottomRight_BoundaryMode,
291
292 kBoundaryModeCount,
293};
294
295class SkLightingImageFilterInternal : public SkLightingImageFilter {
296protected:
297 SkLightingImageFilterInternal(SkLight* light,
298 SkScalar surfaceScale,
299 SkImageFilter* input,
300 const CropRect* cropRect)
301 : INHERITED(light, surfaceScale, input, cropRect) {}
302
303#if SK_SUPPORT_GPU
304 bool canFilterImageGPU() const override { return true; }
305 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
306 SkBitmap* result, SkIPoint* offset) const override;
307 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
308 const SkMatrix&,
309 const SkIRect& bounds,
310 BoundaryMode boundaryMode) const = 0;
311#endif
312private:
313#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700314 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700315 GrTexture* src,
316 GrTexture* dst,
317 const SkMatrix& matrix,
318 const GrClip& clip,
319 const SkRect& dstRect,
320 BoundaryMode boundaryMode,
321 const SkIRect& bounds) const;
322#endif
323 typedef SkLightingImageFilter INHERITED;
324};
325
326#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700327void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700328 GrTexture* src,
329 GrTexture* dst,
330 const SkMatrix& matrix,
331 const GrClip& clip,
332 const SkRect& dstRect,
333 BoundaryMode boundaryMode,
334 const SkIRect& bounds) const {
335 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
336 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
337 GrPaint paint;
338 paint.addColorProcessor(fp)->unref();
robertphillipsea461502015-05-26 11:38:03 -0700339 drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
340 dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700341}
342
343bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
344 const SkBitmap& src,
345 const Context& ctx,
346 SkBitmap* result,
347 SkIPoint* offset) const {
348 SkBitmap input = src;
349 SkIPoint srcOffset = SkIPoint::Make(0, 0);
350 if (this->getInput(0) &&
351 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
352 return false;
353 }
354 SkIRect bounds;
355 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
356 return false;
357 }
358 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
359 SkIntToScalar(bounds.height()));
360 GrTexture* srcTexture = input.getTexture();
361 GrContext* context = srcTexture->getContext();
362
363 GrSurfaceDesc desc;
364 desc.fFlags = kRenderTarget_GrSurfaceFlag,
365 desc.fWidth = bounds.width();
366 desc.fHeight = bounds.height();
367 desc.fConfig = kRGBA_8888_GrPixelConfig;
368
bsalomond309e7a2015-04-30 14:18:54 -0700369 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(desc,
370 GrTextureProvider::kApprox_ScratchTexMatch));
senorblancod0d37ca2015-04-02 04:54:56 -0700371 if (!dst) {
372 return false;
373 }
374
375 // setup new clip
376 GrClip clip(dstRect);
377
378 offset->fX = bounds.left();
379 offset->fY = bounds.top();
380 SkMatrix matrix(ctx.ctm());
381 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
382 bounds.offset(-srcOffset);
383 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
384 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
385 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
386 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
387 SkRect interior = dstRect.makeInset(1, 1);
388 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
389 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
390 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
391 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700392
393 GrDrawContext* drawContext = context->drawContext();
394 if (!drawContext) {
395 return false;
396 }
397
398 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700399 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700400 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
401 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700402 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700403 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
404 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700405 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700406 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
407 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700408 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700409 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
410 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
411 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700412 WrapTexture(dst, bounds.width(), bounds.height(), result);
413 return true;
414}
415#endif
416
417class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000418public:
reed9fa60da2014-08-21 07:59:51 -0700419 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700420 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700421
robertphillipsf3f5bad2014-12-19 13:49:15 -0800422 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000423 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000424 SkScalar kd() const { return fKD; }
425
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000426protected:
reed9fa60da2014-08-21 07:59:51 -0700427 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700428 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700429 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700430 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
431 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000432#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -0700433 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&,
434 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000435#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000436
437private:
reed9fa60da2014-08-21 07:59:51 -0700438 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700439 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000440 SkScalar fKD;
441};
442
senorblancod0d37ca2015-04-02 04:54:56 -0700443class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000444public:
reed9fa60da2014-08-21 07:59:51 -0700445 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700446 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700447
robertphillipsf3f5bad2014-12-19 13:49:15 -0800448 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000449 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
450
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000451 SkScalar ks() const { return fKS; }
452 SkScalar shininess() const { return fShininess; }
453
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000454protected:
reed9fa60da2014-08-21 07:59:51 -0700455 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700456 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700457 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700458 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
459 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000460#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -0700461 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&,
462 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000463#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000464
465private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000466 SkScalar fKS;
467 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700468 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700469 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000470};
471
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000472#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000473
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000474class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000475public:
senorblancod0d37ca2015-04-02 04:54:56 -0700476 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale,
477 const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000478 virtual ~GrLightingEffect();
479
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000480 const SkLight* light() const { return fLight; }
481 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000482 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700483 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000484
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000485protected:
mtklein36352bf2015-03-25 18:17:31 -0700486 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000487
mtklein36352bf2015-03-25 18:17:31 -0700488 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700489 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800490 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700491 }
492
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000494 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000495 const SkLight* fLight;
496 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000497 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700498 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000499};
500
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000501class GrDiffuseLightingEffect : public GrLightingEffect {
502public:
joshualittb0a8a372014-09-23 09:50:21 -0700503 static GrFragmentProcessor* Create(GrTexture* texture,
504 const SkLight* light,
505 SkScalar surfaceScale,
506 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700507 SkScalar kd,
508 BoundaryMode boundaryMode) {
bsalomon55fad7a2014-07-08 07:34:20 -0700509 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
510 light,
511 surfaceScale,
512 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700513 kd,
514 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000515 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000516
mtklein36352bf2015-03-25 18:17:31 -0700517 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000518
jvanverthcfc18862015-04-28 08:48:20 -0700519 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000520
mtklein36352bf2015-03-25 18:17:31 -0700521 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800522
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000523 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000524
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000525private:
mtklein36352bf2015-03-25 18:17:31 -0700526 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000527
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000528 GrDiffuseLightingEffect(GrTexture* texture,
529 const SkLight* light,
530 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000531 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700532 SkScalar kd,
533 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000534
joshualittb0a8a372014-09-23 09:50:21 -0700535 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536 typedef GrLightingEffect INHERITED;
537 SkScalar fKD;
538};
539
540class GrSpecularLightingEffect : public GrLightingEffect {
541public:
joshualittb0a8a372014-09-23 09:50:21 -0700542 static GrFragmentProcessor* Create(GrTexture* texture,
543 const SkLight* light,
544 SkScalar surfaceScale,
545 const SkMatrix& matrix,
546 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700547 SkScalar shininess,
548 BoundaryMode boundaryMode) {
bsalomon55fad7a2014-07-08 07:34:20 -0700549 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
550 light,
551 surfaceScale,
552 matrix,
553 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700554 shininess,
555 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000556 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000557
mtklein36352bf2015-03-25 18:17:31 -0700558 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000559
jvanverthcfc18862015-04-28 08:48:20 -0700560 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800561
mtklein36352bf2015-03-25 18:17:31 -0700562 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800563
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000564 SkScalar ks() const { return fKS; }
565 SkScalar shininess() const { return fShininess; }
566
567private:
mtklein36352bf2015-03-25 18:17:31 -0700568 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000569
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000570 GrSpecularLightingEffect(GrTexture* texture,
571 const SkLight* light,
572 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000573 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000574 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700575 SkScalar shininess,
576 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000577
joshualittb0a8a372014-09-23 09:50:21 -0700578 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000579 typedef GrLightingEffect INHERITED;
580 SkScalar fKS;
581 SkScalar fShininess;
582};
583
584///////////////////////////////////////////////////////////////////////////////
585
586class GrGLLight {
587public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000588 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000589
590 /**
591 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
592 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
593 */
joshualitt15988992014-10-09 15:04:05 -0700594 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000595
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000596 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000597 * These two functions are called from GrGLLightingEffect's emitCode() function.
598 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
599 * the light. The expression will be used in the FS. emitLightColor writes an expression into
600 * the FS that is the color of the light. Either function may add functions and/or uniforms to
601 * the FS. The default of emitLightColor appends the name of the constant light color uniform
602 * and so this function only needs to be overridden if the light color varies spatially.
603 */
joshualitt15988992014-10-09 15:04:05 -0700604 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
605 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000606
607 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
608 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700609 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000610 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000611
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000612protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000613 /**
614 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
615 * function.
616 */
617 UniformHandle lightColorUni() const { return fColorUni; }
618
619private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000620 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000621
622 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000623};
624
625///////////////////////////////////////////////////////////////////////////////
626
627class GrGLDistantLight : public GrGLLight {
628public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000629 virtual ~GrGLDistantLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700630 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700631 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000632
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633private:
634 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000635 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000636};
637
638///////////////////////////////////////////////////////////////////////////////
639
640class GrGLPointLight : public GrGLLight {
641public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000642 virtual ~GrGLPointLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700643 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700644 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000645
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000646private:
647 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000648 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000649};
650
651///////////////////////////////////////////////////////////////////////////////
652
653class GrGLSpotLight : public GrGLLight {
654public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000655 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700656 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700657 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
658 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000659
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000660private:
661 typedef GrGLLight INHERITED;
662
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000663 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000664 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000665 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000666 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000667 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000668 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000669 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000670};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000671#else
672
673class GrGLLight;
674
675#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000676
677};
678
679///////////////////////////////////////////////////////////////////////////////
680
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000681class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000682public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000683 SK_DECLARE_INST_COUNT(SkLight)
684
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000685 enum LightType {
686 kDistant_LightType,
687 kPoint_LightType,
688 kSpot_LightType,
689 };
690 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000691 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000692 virtual GrGLLight* createGLLight() const = 0;
693 virtual bool isEqual(const SkLight& other) const {
694 return fColor == other.fColor;
695 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000696 // Called to know whether the generated GrGLLight will require access to the fragment position.
697 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000698 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000699
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000700 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000701 void flattenLight(SkWriteBuffer& buffer) const;
702 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000703
djsollen@google.com08337772012-06-26 14:33:13 +0000704protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000705 SkLight(SkColor color)
706 : fColor(SkIntToScalar(SkColorGetR(color)),
707 SkIntToScalar(SkColorGetG(color)),
708 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000709 SkLight(const SkPoint3& color)
710 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000711 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000712 fColor = readPoint3(buffer);
713 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000714
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000715 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000716
djsollen@google.com08337772012-06-26 14:33:13 +0000717
718private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000719 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000720 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000721};
722
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000723///////////////////////////////////////////////////////////////////////////////
724
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000725class SkDistantLight : public SkLight {
726public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000727 SkDistantLight(const SkPoint3& direction, SkColor color)
728 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000729 }
djsollen@google.com08337772012-06-26 14:33:13 +0000730
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000731 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
732 return fDirection;
733 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700735 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000736 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700737 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000738#if SK_SUPPORT_GPU
739 return SkNEW(GrGLDistantLight);
740#else
741 SkDEBUGFAIL("Should not call in GPU-less build");
742 return NULL;
743#endif
744 }
mtklein36352bf2015-03-25 18:17:31 -0700745 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000746
mtklein36352bf2015-03-25 18:17:31 -0700747 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000748 if (other.type() != kDistant_LightType) {
749 return false;
750 }
751
752 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
753 return INHERITED::isEqual(other) &&
754 fDirection == o.fDirection;
755 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000756
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000757 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000758 fDirection = readPoint3(buffer);
759 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000760
djsollen@google.com08337772012-06-26 14:33:13 +0000761protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000762 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
763 : INHERITED(color), fDirection(direction) {
764 }
mtklein36352bf2015-03-25 18:17:31 -0700765 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000766 return new SkDistantLight(direction(), color());
767 }
mtklein36352bf2015-03-25 18:17:31 -0700768 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000769 writePoint3(fDirection, buffer);
770 }
771
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000772private:
djsollen@google.com08337772012-06-26 14:33:13 +0000773 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774 SkPoint3 fDirection;
775};
776
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000777///////////////////////////////////////////////////////////////////////////////
778
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779class SkPointLight : public SkLight {
780public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000781 SkPointLight(const SkPoint3& location, SkColor color)
782 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000783
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000784 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
785 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
786 fLocation.fY - SkIntToScalar(y),
787 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
788 direction.normalize();
789 return direction;
790 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000791 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700792 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000793 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700794 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000795#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000796 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000797#else
798 SkDEBUGFAIL("Should not call in GPU-less build");
799 return NULL;
800#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000801 }
mtklein36352bf2015-03-25 18:17:31 -0700802 bool requiresFragmentPosition() const override { return true; }
803 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000804 if (other.type() != kPoint_LightType) {
805 return false;
806 }
807 const SkPointLight& o = static_cast<const SkPointLight&>(other);
808 return INHERITED::isEqual(other) &&
809 fLocation == o.fLocation;
810 }
mtklein36352bf2015-03-25 18:17:31 -0700811 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000812 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
813 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000814 // Use X scale and Y scale on Z and average the result
815 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
816 matrix.mapVectors(&locationZ, 1);
817 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000818 return new SkPointLight(location, color());
819 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000820
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000821 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000822 fLocation = readPoint3(buffer);
823 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000824
825protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000826 SkPointLight(const SkPoint3& location, const SkPoint3& color)
827 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700828 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000829 writePoint3(fLocation, buffer);
830 }
831
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000832private:
djsollen@google.com08337772012-06-26 14:33:13 +0000833 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000834 SkPoint3 fLocation;
835};
836
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000837///////////////////////////////////////////////////////////////////////////////
838
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000839class SkSpotLight : public SkLight {
840public:
senorblancod0d37ca2015-04-02 04:54:56 -0700841 SkSpotLight(const SkPoint3& location,
842 const SkPoint3& target,
843 SkScalar specularExponent,
844 SkScalar cutoffAngle,
845 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000846 : INHERITED(color),
847 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000848 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000849 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850 {
851 fS = target - location;
852 fS.normalize();
853 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000854 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000855 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
856 fConeScale = SkScalarInvert(antiAliasThreshold);
857 }
djsollen@google.com08337772012-06-26 14:33:13 +0000858
mtklein36352bf2015-03-25 18:17:31 -0700859 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000860 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
861 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000862 // Use X scale and Y scale on Z and average the result
863 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
864 matrix.mapVectors(&locationZ, 1);
865 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000866 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
867 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000868 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
869 matrix.mapVectors(&targetZ, 1);
870 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
871 SkPoint3 s = target - location;
872 s.normalize();
senorblancod0d37ca2015-04-02 04:54:56 -0700873 return new SkSpotLight(location,
874 target,
875 fSpecularExponent,
876 fCosOuterConeAngle,
877 fCosInnerConeAngle,
878 fConeScale,
879 s,
880 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000881 }
882
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000883 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
884 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
885 fLocation.fY - SkIntToScalar(y),
886 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
887 direction.normalize();
888 return direction;
889 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000890 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000891 SkScalar cosAngle = -surfaceToLight.dot(fS);
892 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000893 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000894 }
895 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
896 if (cosAngle < fCosInnerConeAngle) {
897 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000898 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000899 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000900 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000901 }
mtklein36352bf2015-03-25 18:17:31 -0700902 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000903#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000904 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000905#else
906 SkDEBUGFAIL("Should not call in GPU-less build");
907 return NULL;
908#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000909 }
mtklein36352bf2015-03-25 18:17:31 -0700910 bool requiresFragmentPosition() const override { return true; }
911 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000912 const SkPoint3& location() const { return fLocation; }
913 const SkPoint3& target() const { return fTarget; }
914 SkScalar specularExponent() const { return fSpecularExponent; }
915 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
916 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
917 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000918 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000919
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000920 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000921 fLocation = readPoint3(buffer);
922 fTarget = readPoint3(buffer);
923 fSpecularExponent = buffer.readScalar();
924 fCosOuterConeAngle = buffer.readScalar();
925 fCosInnerConeAngle = buffer.readScalar();
926 fConeScale = buffer.readScalar();
927 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000928 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
929 SkScalarIsFinite(fCosOuterConeAngle) &&
930 SkScalarIsFinite(fCosInnerConeAngle) &&
931 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000932 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000933protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700934 SkSpotLight(const SkPoint3& location,
935 const SkPoint3& target,
936 SkScalar specularExponent,
937 SkScalar cosOuterConeAngle,
938 SkScalar cosInnerConeAngle,
939 SkScalar coneScale,
940 const SkPoint3& s,
941 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000942 : INHERITED(color),
943 fLocation(location),
944 fTarget(target),
945 fSpecularExponent(specularExponent),
946 fCosOuterConeAngle(cosOuterConeAngle),
947 fCosInnerConeAngle(cosInnerConeAngle),
948 fConeScale(coneScale),
949 fS(s)
950 {
951 }
mtklein36352bf2015-03-25 18:17:31 -0700952 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000953 writePoint3(fLocation, buffer);
954 writePoint3(fTarget, buffer);
955 buffer.writeScalar(fSpecularExponent);
956 buffer.writeScalar(fCosOuterConeAngle);
957 buffer.writeScalar(fCosInnerConeAngle);
958 buffer.writeScalar(fConeScale);
959 writePoint3(fS, buffer);
960 }
961
mtklein36352bf2015-03-25 18:17:31 -0700962 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000963 if (other.type() != kSpot_LightType) {
964 return false;
965 }
966
967 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
968 return INHERITED::isEqual(other) &&
969 fLocation == o.fLocation &&
970 fTarget == o.fTarget &&
971 fSpecularExponent == o.fSpecularExponent &&
972 fCosOuterConeAngle == o.fCosOuterConeAngle;
973 }
974
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000975private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000976 static const SkScalar kSpecularExponentMin;
977 static const SkScalar kSpecularExponentMax;
978
djsollen@google.com08337772012-06-26 14:33:13 +0000979 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000980 SkPoint3 fLocation;
981 SkPoint3 fTarget;
982 SkScalar fSpecularExponent;
983 SkScalar fCosOuterConeAngle;
984 SkScalar fCosInnerConeAngle;
985 SkScalar fConeScale;
986 SkPoint3 fS;
987};
988
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000989// According to the spec, the specular term should be in the range [1, 128] :
990// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000991const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
992const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000993
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000994///////////////////////////////////////////////////////////////////////////////
995
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000996void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000997 // Write type first, then baseclass, then subclass.
998 buffer.writeInt(this->type());
999 writePoint3(fColor, buffer);
1000 this->onFlattenLight(buffer);
1001}
1002
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001003/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001004 // Read type first.
1005 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
1006 switch (type) {
1007 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1008 // then subclass, same order as flattenLight.
1009 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1010 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1011 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1012 default:
1013 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001014 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001015 return NULL;
1016 }
1017}
1018///////////////////////////////////////////////////////////////////////////////
1019
senorblanco9ea3d572014-07-08 09:16:22 -07001020SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001021 SkImageFilter* input, const CropRect* cropRect)
1022 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001023 , fLight(SkRef(light))
1024 , fSurfaceScale(surfaceScale / 255)
1025{}
1026
1027SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1028 SkColor lightColor,
1029 SkScalar surfaceScale,
1030 SkScalar kd,
1031 SkImageFilter* input,
1032 const CropRect* cropRect) {
1033 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1034 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001035}
1036
reed9fa60da2014-08-21 07:59:51 -07001037SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1038 SkColor lightColor,
1039 SkScalar surfaceScale,
1040 SkScalar kd,
1041 SkImageFilter* input,
1042 const CropRect* cropRect) {
1043 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, 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::CreateSpotLitDiffuse(const SkPoint3& location,
1048 const SkPoint3& target,
1049 SkScalar specularExponent,
1050 SkScalar cutoffAngle,
1051 SkColor lightColor,
1052 SkScalar surfaceScale,
1053 SkScalar kd,
1054 SkImageFilter* input,
1055 const CropRect* cropRect) {
1056 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1057 cutoffAngle, lightColor)));
1058 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001059}
1060
reed9fa60da2014-08-21 07:59:51 -07001061SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1062 SkColor lightColor,
1063 SkScalar surfaceScale,
1064 SkScalar ks,
1065 SkScalar shine,
1066 SkImageFilter* input,
1067 const CropRect* cropRect) {
1068 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1069 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001070}
1071
reed9fa60da2014-08-21 07:59:51 -07001072SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1073 SkColor lightColor,
1074 SkScalar surfaceScale,
1075 SkScalar ks,
1076 SkScalar shine,
1077 SkImageFilter* input,
1078 const CropRect* cropRect) {
1079 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1080 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001081}
1082
reed9fa60da2014-08-21 07:59:51 -07001083SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1084 const SkPoint3& target,
1085 SkScalar specularExponent,
1086 SkScalar cutoffAngle,
1087 SkColor lightColor,
1088 SkScalar surfaceScale,
1089 SkScalar ks,
1090 SkScalar shine,
1091 SkImageFilter* input,
1092 const CropRect* cropRect) {
1093 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1094 cutoffAngle, lightColor)));
1095 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001096}
1097
reed9fa60da2014-08-21 07:59:51 -07001098SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001099
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001100void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001101 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001102 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001103 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001104}
1105
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001106///////////////////////////////////////////////////////////////////////////////
1107
reed9fa60da2014-08-21 07:59:51 -07001108SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001109 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001110 if (NULL == light) {
1111 return NULL;
1112 }
1113 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1114 return NULL;
1115 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001116 // According to the spec, kd can be any non-negative number :
1117 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001118 if (kd < 0) {
1119 return NULL;
1120 }
senorblanco24e06d52015-03-18 12:11:33 -07001121 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001122}
1123
senorblancod0d37ca2015-04-02 04:54:56 -07001124SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1125 SkScalar surfaceScale,
1126 SkScalar kd,
1127 SkImageFilter* input,
1128 const CropRect* cropRect)
1129 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001130 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001131{
1132}
1133
reed9fa60da2014-08-21 07:59:51 -07001134SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1135 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1136 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1137 SkScalar surfaceScale = buffer.readScalar();
1138 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001139 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001140}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001141
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001142void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001143 this->INHERITED::flatten(buffer);
1144 buffer.writeScalar(fKD);
1145}
1146
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001147bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1148 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001149 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001150 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001151 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001152 SkImageFilter* input = getInput(0);
1153 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001154 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001155 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001156 return false;
1157 }
1158
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001159 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001160 return false;
1161 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001162 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001163 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001164 return false;
1165 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001166
1167 if (bounds.width() < 2 || bounds.height() < 2) {
1168 return false;
1169 }
1170
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001171 SkAutoLockPixels alp(src);
1172 if (!src.getPixels()) {
1173 return false;
1174 }
1175
reed84825042014-09-02 12:50:45 -07001176 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001177 return false;
1178 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001179
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001180 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001181
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001182 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001183 offset->fX = bounds.left();
1184 offset->fY = bounds.top();
1185 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001186 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001187 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001188 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1189 transformedLight,
1190 src,
1191 dst,
1192 surfaceScale(),
1193 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001194 break;
1195 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001196 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1197 transformedLight,
1198 src,
1199 dst,
1200 surfaceScale(),
1201 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001202 break;
1203 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001204 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1205 transformedLight,
1206 src,
1207 dst,
1208 surfaceScale(),
1209 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001210 break;
1211 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001212
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001213 return true;
1214}
1215
robertphillipsf3f5bad2014-12-19 13:49:15 -08001216#ifndef SK_IGNORE_TO_STRING
1217void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1218 str->appendf("SkDiffuseLightingImageFilter: (");
1219 str->appendf("kD: %f\n", fKD);
1220 str->append(")");
1221}
1222#endif
1223
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001224#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001225GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualittb0a8a372014-09-23 09:50:21 -07001226 GrTexture* texture,
1227 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001228 const SkIRect&,
1229 BoundaryMode boundaryMode
1230) const {
1231 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1232 return GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001233}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001234#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001235
1236///////////////////////////////////////////////////////////////////////////////
1237
reed9fa60da2014-08-21 07:59:51 -07001238SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001239 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001240 if (NULL == light) {
1241 return NULL;
1242 }
1243 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1244 return NULL;
1245 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001246 // According to the spec, ks can be any non-negative number :
1247 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001248 if (ks < 0) {
1249 return NULL;
1250 }
1251 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001252 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001253}
1254
senorblancod0d37ca2015-04-02 04:54:56 -07001255SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1256 SkScalar surfaceScale,
1257 SkScalar ks,
1258 SkScalar shininess,
1259 SkImageFilter* input,
1260 const CropRect* cropRect)
1261 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001262 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001263 fShininess(shininess)
1264{
1265}
1266
reed9fa60da2014-08-21 07:59:51 -07001267SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1268 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1269 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1270 SkScalar surfaceScale = buffer.readScalar();
1271 SkScalar ks = buffer.readScalar();
1272 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001273 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001274}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001275
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001276void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001277 this->INHERITED::flatten(buffer);
1278 buffer.writeScalar(fKS);
1279 buffer.writeScalar(fShininess);
1280}
1281
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001282bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1283 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001284 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001285 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001286 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001287 SkImageFilter* input = getInput(0);
1288 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001289 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001290 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001291 return false;
1292 }
1293
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001294 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001295 return false;
1296 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001297
1298 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001299 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001300 return false;
1301 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001302
1303 if (bounds.width() < 2 || bounds.height() < 2) {
1304 return false;
1305 }
1306
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001307 SkAutoLockPixels alp(src);
1308 if (!src.getPixels()) {
1309 return false;
1310 }
1311
reed84825042014-09-02 12:50:45 -07001312 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001313 return false;
1314 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001315
1316 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001317 offset->fX = bounds.left();
1318 offset->fY = bounds.top();
1319 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001320 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001321 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001322 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001323 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1324 transformedLight,
1325 src,
1326 dst,
1327 surfaceScale(),
1328 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001329 break;
1330 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001331 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1332 transformedLight,
1333 src,
1334 dst,
1335 surfaceScale(),
1336 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001337 break;
1338 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001339 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1340 transformedLight,
1341 src,
1342 dst,
1343 surfaceScale(),
1344 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001345 break;
1346 }
1347 return true;
1348}
1349
robertphillipsf3f5bad2014-12-19 13:49:15 -08001350#ifndef SK_IGNORE_TO_STRING
1351void SkSpecularLightingImageFilter::toString(SkString* str) const {
1352 str->appendf("SkSpecularLightingImageFilter: (");
1353 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1354 str->append(")");
1355}
1356#endif
1357
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001358#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001359GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
1360 GrTexture* texture,
1361 const SkMatrix& matrix,
1362 const SkIRect&,
1363 BoundaryMode boundaryMode) const {
1364 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1365 return GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess(),
1366 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001367}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001368#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001369
1370///////////////////////////////////////////////////////////////////////////////
1371
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001372#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001373
1374namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001375SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001376 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1377 SkScalarToFloat(random->nextSScalar1()),
1378 SkScalarToFloat(random->nextSScalar1()));
1379}
1380
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001381SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001382 int type = random->nextULessThan(3);
1383 switch (type) {
1384 case 0: {
1385 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1386 }
1387 case 1: {
1388 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1389 }
1390 case 2: {
1391 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1392 random_point3(random),
1393 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001394 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001395 random->nextU()));
1396 }
1397 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001398 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001399 return NULL;
1400 }
1401}
1402
senorblancod0d37ca2015-04-02 04:54:56 -07001403SkString emitNormalFunc(BoundaryMode mode,
1404 const char* pointToNormalName,
1405 const char* sobelFuncName) {
1406 SkString result;
1407 switch (mode) {
1408 case kTopLeft_BoundaryMode:
1409 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1410 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1411 "\t surfaceScale);\n",
1412 pointToNormalName, sobelFuncName, gTwoThirds,
1413 sobelFuncName, gTwoThirds);
1414 break;
1415 case kTop_BoundaryMode:
1416 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1417 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1418 "\t surfaceScale);\n",
1419 pointToNormalName, sobelFuncName, gOneThird,
1420 sobelFuncName, gOneHalf);
1421 break;
1422 case kTopRight_BoundaryMode:
1423 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1424 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1425 "\t surfaceScale);\n",
1426 pointToNormalName, sobelFuncName, gTwoThirds,
1427 sobelFuncName, gTwoThirds);
1428 break;
1429 case kLeft_BoundaryMode:
1430 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1431 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1432 "\t surfaceScale);\n",
1433 pointToNormalName, sobelFuncName, gOneHalf,
1434 sobelFuncName, gOneThird);
1435 break;
1436 case kInterior_BoundaryMode:
1437 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1438 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1439 "\t surfaceScale);\n",
1440 pointToNormalName, sobelFuncName, gOneQuarter,
1441 sobelFuncName, gOneQuarter);
1442 break;
1443 case kRight_BoundaryMode:
1444 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1445 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1446 "\t surfaceScale);\n",
1447 pointToNormalName, sobelFuncName, gOneHalf,
1448 sobelFuncName, gOneThird);
1449 break;
1450 case kBottomLeft_BoundaryMode:
1451 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1452 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1453 "\t surfaceScale);\n",
1454 pointToNormalName, sobelFuncName, gTwoThirds,
1455 sobelFuncName, gTwoThirds);
1456 break;
1457 case kBottom_BoundaryMode:
1458 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1459 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1460 "\t surfaceScale);\n",
1461 pointToNormalName, sobelFuncName, gOneThird,
1462 sobelFuncName, gOneHalf);
1463 break;
1464 case kBottomRight_BoundaryMode:
1465 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1466 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1467 "\t surfaceScale);\n",
1468 pointToNormalName, sobelFuncName, gTwoThirds,
1469 sobelFuncName, gTwoThirds);
1470 break;
1471 default:
1472 SkASSERT(false);
1473 break;
1474 }
1475 return result;
1476}
1477
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001478}
1479
joshualittb0a8a372014-09-23 09:50:21 -07001480class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001481public:
joshualitteb2a6762014-12-04 11:35:33 -08001482 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001483 virtual ~GrGLLightingEffect();
1484
senorblancod0d37ca2015-04-02 04:54:56 -07001485 void emitCode(GrGLFPBuilder*,
1486 const GrFragmentProcessor&,
1487 const char* outputColor,
1488 const char* inputColor,
1489 const TransformedCoordsArray&,
1490 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001491
jvanverthcfc18862015-04-28 08:48:20 -07001492 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001493
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001494 /**
1495 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1496 */
mtklein36352bf2015-03-25 18:17:31 -07001497 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001498
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001499protected:
joshualitt15988992014-10-09 15:04:05 -07001500 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001501
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001502private:
joshualittb0a8a372014-09-23 09:50:21 -07001503 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001504
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001505 UniformHandle fImageIncrementUni;
1506 UniformHandle fSurfaceScaleUni;
1507 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001508 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001509};
1510
1511///////////////////////////////////////////////////////////////////////////////
1512
1513class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1514public:
joshualitteb2a6762014-12-04 11:35:33 -08001515 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001516 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1517 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001518
1519private:
1520 typedef GrGLLightingEffect INHERITED;
1521
bsalomon@google.com032b2212012-07-16 13:36:18 +00001522 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001523};
1524
1525///////////////////////////////////////////////////////////////////////////////
1526
1527class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1528public:
joshualitteb2a6762014-12-04 11:35:33 -08001529 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001530 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1531 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001532
1533private:
1534 typedef GrGLLightingEffect INHERITED;
1535
bsalomon@google.com032b2212012-07-16 13:36:18 +00001536 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001537 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001538};
1539
1540///////////////////////////////////////////////////////////////////////////////
1541
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001542GrLightingEffect::GrLightingEffect(GrTexture* texture,
1543 const SkLight* light,
1544 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001545 const SkMatrix& matrix,
1546 BoundaryMode boundaryMode)
bsalomon6267f812014-08-29 15:05:53 -07001547 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001548 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001549 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001550 , fFilterMatrix(matrix)
1551 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001552 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001553 if (light->requiresFragmentPosition()) {
1554 this->setWillReadFragmentPosition();
1555 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001556}
1557
1558GrLightingEffect::~GrLightingEffect() {
1559 fLight->unref();
1560}
1561
bsalomon0e08fc12014-10-15 08:19:04 -07001562bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001563 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001564 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001565 fSurfaceScale == s.fSurfaceScale &&
1566 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001567}
1568
1569///////////////////////////////////////////////////////////////////////////////
1570
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001571GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1572 const SkLight* light,
1573 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001574 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001575 SkScalar kd,
1576 BoundaryMode boundaryMode)
1577 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001578 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001579}
1580
bsalomon0e08fc12014-10-15 08:19:04 -07001581bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001582 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001583 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001584 this->kd() == s.kd();
1585}
1586
jvanverthcfc18862015-04-28 08:48:20 -07001587void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001588 GrProcessorKeyBuilder* b) const {
1589 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1590}
1591
1592GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1593 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1594}
1595
joshualittb0a8a372014-09-23 09:50:21 -07001596GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001597
joshualittb0a8a372014-09-23 09:50:21 -07001598GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001599 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -07001600 const GrCaps&,
bsalomon83d081a2014-07-08 09:56:10 -07001601 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001602 SkScalar surfaceScale = random->nextSScalar1();
1603 SkScalar kd = random->nextUScalar1();
1604 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001605 SkMatrix matrix;
1606 for (int i = 0; i < 9; i++) {
1607 matrix[i] = random->nextUScalar1();
1608 }
senorblancod0d37ca2015-04-02 04:54:56 -07001609 BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount);
joshualittb0a8a372014-09-23 09:50:21 -07001610 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001611 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001612}
1613
1614
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001615///////////////////////////////////////////////////////////////////////////////
1616
joshualitteb2a6762014-12-04 11:35:33 -08001617GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001618 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001619 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001620 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001621}
1622
1623GrGLLightingEffect::~GrGLLightingEffect() {
1624 delete fLight;
1625}
1626
joshualitt15988992014-10-09 15:04:05 -07001627void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001628 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001629 const char* outputColor,
1630 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001631 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001632 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001633 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001634 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001635 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001636 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001637 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001638 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001639 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001640 SkString lightFunc;
1641 this->emitLightFunc(builder, &lightFunc);
1642 static const GrGLShaderVar gSobelArgs[] = {
1643 GrGLShaderVar("a", kFloat_GrSLType),
1644 GrGLShaderVar("b", kFloat_GrSLType),
1645 GrGLShaderVar("c", kFloat_GrSLType),
1646 GrGLShaderVar("d", kFloat_GrSLType),
1647 GrGLShaderVar("e", kFloat_GrSLType),
1648 GrGLShaderVar("f", kFloat_GrSLType),
1649 GrGLShaderVar("scale", kFloat_GrSLType),
1650 };
1651 SkString sobelFuncName;
egdaniel29bee0f2015-04-29 11:54:42 -07001652 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001653 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1654
1655 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001656 "sobel",
1657 SK_ARRAY_COUNT(gSobelArgs),
1658 gSobelArgs,
1659 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1660 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001661 static const GrGLShaderVar gPointToNormalArgs[] = {
1662 GrGLShaderVar("x", kFloat_GrSLType),
1663 GrGLShaderVar("y", kFloat_GrSLType),
1664 GrGLShaderVar("scale", kFloat_GrSLType),
1665 };
1666 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001667 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001668 "pointToNormal",
1669 SK_ARRAY_COUNT(gPointToNormalArgs),
1670 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001671 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001672 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001673
1674 static const GrGLShaderVar gInteriorNormalArgs[] = {
1675 GrGLShaderVar("m", kFloat_GrSLType, 9),
1676 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1677 };
senorblancod0d37ca2015-04-02 04:54:56 -07001678 SkString normalBody = emitNormalFunc(fBoundaryMode,
1679 pointToNormalName.c_str(),
1680 sobelFuncName.c_str());
1681 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001682 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001683 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001684 SK_ARRAY_COUNT(gInteriorNormalArgs),
1685 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001686 normalBody.c_str(),
1687 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001688
joshualitt30ba4362014-08-21 20:18:45 -07001689 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1690 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001691
1692 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1693 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1694
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001695 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001696 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001697 for (int dx = -1; dx <= 1; dx++) {
1698 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001699 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001700 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1701 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1702 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001703 }
1704 }
joshualitt30ba4362014-08-21 20:18:45 -07001705 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001706 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001707 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001708 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001709 fsBuilder->codeAppend(";\n");
1710 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
senorblancod0d37ca2015-04-02 04:54:56 -07001711 outputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001712 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001713 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001714 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001715 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001716 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001717}
1718
joshualittb0a8a372014-09-23 09:50:21 -07001719void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001720 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001721 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1722 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001723}
1724
kkinnunen7510b222014-07-30 00:04:16 -07001725void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001726 const GrProcessor& proc) {
1727 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001728 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001729 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001730 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1731 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001732 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001733 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001734}
1735
1736///////////////////////////////////////////////////////////////////////////////
1737
1738///////////////////////////////////////////////////////////////////////////////
1739
joshualitteb2a6762014-12-04 11:35:33 -08001740GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1741 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001742}
1743
joshualitt15988992014-10-09 15:04:05 -07001744void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001745 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001746 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001747 kFloat_GrSLType, kDefault_GrSLPrecision,
1748 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001749
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001750 static const GrGLShaderVar gLightArgs[] = {
1751 GrGLShaderVar("normal", kVec3f_GrSLType),
1752 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1753 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1754 };
1755 SkString lightBody;
1756 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1757 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001758 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1759 "light",
1760 SK_ARRAY_COUNT(gLightArgs),
1761 gLightArgs,
1762 lightBody.c_str(),
1763 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001764}
1765
kkinnunen7510b222014-07-30 00:04:16 -07001766void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001767 const GrProcessor& proc) {
1768 INHERITED::setData(pdman, proc);
1769 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001770 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001771}
1772
1773///////////////////////////////////////////////////////////////////////////////
1774
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001775GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1776 const SkLight* light,
1777 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001778 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001779 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001780 SkScalar shininess,
1781 BoundaryMode boundaryMode)
1782 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001783 fKS(ks),
1784 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001785 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001786}
1787
bsalomon0e08fc12014-10-15 08:19:04 -07001788bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001789 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001790 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001791 this->ks() == s.ks() &&
1792 this->shininess() == s.shininess();
1793}
1794
jvanverthcfc18862015-04-28 08:48:20 -07001795void GrSpecularLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001796 GrProcessorKeyBuilder* b) const {
1797 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1798}
1799
1800GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1801 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1802}
1803
joshualittb0a8a372014-09-23 09:50:21 -07001804GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001805
joshualittb0a8a372014-09-23 09:50:21 -07001806GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1807 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -07001808 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001809 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001810 SkScalar surfaceScale = random->nextSScalar1();
1811 SkScalar ks = random->nextUScalar1();
1812 SkScalar shininess = random->nextUScalar1();
1813 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001814 SkMatrix matrix;
1815 for (int i = 0; i < 9; i++) {
1816 matrix[i] = random->nextUScalar1();
1817 }
senorblancod0d37ca2015-04-02 04:54:56 -07001818 BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount);
joshualittb0a8a372014-09-23 09:50:21 -07001819 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001820 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001821}
1822
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001823///////////////////////////////////////////////////////////////////////////////
1824
joshualitteb2a6762014-12-04 11:35:33 -08001825GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1826 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001827}
1828
joshualitt15988992014-10-09 15:04:05 -07001829void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001830 const char* ks;
1831 const char* shininess;
1832
joshualitt30ba4362014-08-21 20:18:45 -07001833 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001834 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001835 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001836 kFloat_GrSLType,
1837 kDefault_GrSLPrecision,
1838 "Shininess",
1839 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001840
1841 static const GrGLShaderVar gLightArgs[] = {
1842 GrGLShaderVar("normal", kVec3f_GrSLType),
1843 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1844 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1845 };
1846 SkString lightBody;
1847 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1848 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001849 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1850 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001851 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1852 "light",
1853 SK_ARRAY_COUNT(gLightArgs),
1854 gLightArgs,
1855 lightBody.c_str(),
1856 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001857}
1858
kkinnunen7510b222014-07-30 00:04:16 -07001859void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001860 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001861 INHERITED::setData(pdman, effect);
1862 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001863 pdman.set1f(fKSUni, spec.ks());
1864 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001865}
1866
1867///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001868void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001869 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001870 kVec3f_GrSLType, kDefault_GrSLPrecision,
1871 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001872}
1873
joshualitt15988992014-10-09 15:04:05 -07001874void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001875 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001876 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001877}
1878
kkinnunen7510b222014-07-30 00:04:16 -07001879void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001880 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001881 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001882}
1883
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001884///////////////////////////////////////////////////////////////////////////////
1885
kkinnunen7510b222014-07-30 00:04:16 -07001886void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001887 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001888 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001889 SkASSERT(light->type() == SkLight::kDistant_LightType);
1890 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001891 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001892}
1893
joshualitt15988992014-10-09 15:04:05 -07001894void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001895 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001896 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1897 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001898 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001899 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001900}
1901
1902///////////////////////////////////////////////////////////////////////////////
1903
kkinnunen7510b222014-07-30 00:04:16 -07001904void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001905 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001906 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001907 SkASSERT(light->type() == SkLight::kPoint_LightType);
1908 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001909 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001910}
1911
joshualitt15988992014-10-09 15:04:05 -07001912void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001913 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001914 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1915 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001916 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001917 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001918 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1919 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001920}
1921
1922///////////////////////////////////////////////////////////////////////////////
1923
kkinnunen7510b222014-07-30 00:04:16 -07001924void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001925 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001926 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001927 SkASSERT(light->type() == SkLight::kSpot_LightType);
1928 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001929 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1930 pdman.set1f(fExponentUni, spotLight->specularExponent());
1931 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1932 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1933 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1934 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001935}
1936
joshualitt15988992014-10-09 15:04:05 -07001937void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001938 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001939 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001940 kVec3f_GrSLType, kDefault_GrSLPrecision,
1941 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001942
egdaniel29bee0f2015-04-29 11:54:42 -07001943 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001944 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1945 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001946}
1947
joshualitt15988992014-10-09 15:04:05 -07001948void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001949 const char *surfaceToLight) {
1950
1951 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1952
1953 const char* exponent;
1954 const char* cosInner;
1955 const char* cosOuter;
1956 const char* coneScale;
1957 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001958 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001959 kFloat_GrSLType, kDefault_GrSLPrecision,
1960 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001961 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001962 kFloat_GrSLType, kDefault_GrSLPrecision,
1963 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001964 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001965 kFloat_GrSLType, kDefault_GrSLPrecision,
1966 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001967 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001968 kFloat_GrSLType, kDefault_GrSLPrecision,
1969 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001970 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001971 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001972
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001973 static const GrGLShaderVar gLightColorArgs[] = {
1974 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1975 };
1976 SkString lightColorBody;
1977 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1978 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1979 lightColorBody.appendf("\t\treturn vec3(0);\n");
1980 lightColorBody.appendf("\t}\n");
1981 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1982 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1983 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1984 color, cosOuter, coneScale);
1985 lightColorBody.appendf("\t}\n");
1986 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07001987 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001988 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001989 "lightColor",
1990 SK_ARRAY_COUNT(gLightColorArgs),
1991 gLightColorArgs,
1992 lightColorBody.c_str(),
1993 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001994
joshualitt30ba4362014-08-21 20:18:45 -07001995 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001996}
1997
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001998#endif
1999
djsollen@google.com08337772012-06-26 14:33:13 +00002000SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2001 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2002 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002003SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END