blob: ae49462b5e1397c6373e7610b7804d15cc3e7daf [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"
robertphillips3d32d762015-07-13 13:16:44 -070011#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000013#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070014#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000015
16#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070017#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070018#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080019#include "GrFragmentProcessor.h"
20#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070021#include "GrPaint.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000022#include "effects/GrSingleTextureEffect.h"
joshualittb0a8a372014-09-23 09:50:21 -070023#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070024#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000025
26class GrGLDiffuseLightingEffect;
27class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000028
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000029// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070030typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000031#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000032
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000033namespace {
34
reed80ea19c2015-05-12 10:37:34 -070035const SkScalar gOneThird = SkIntToScalar(1) / 3;
36const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000037const SkScalar gOneHalf = 0.5f;
38const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000039
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000040#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070041void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
42 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000043 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070044 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000045}
46
joshualittb0a8a372014-09-23 09:50:21 -070047void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
48 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070049 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000050}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000051#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000052
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000053// Shift matrix components to the left, as we advance pixels to the right.
54inline void shiftMatrixLeft(int m[9]) {
55 m[0] = m[1];
56 m[3] = m[4];
57 m[6] = m[7];
58 m[1] = m[2];
59 m[4] = m[5];
60 m[7] = m[8];
61}
62
63class DiffuseLightingType {
64public:
65 DiffuseLightingType(SkScalar kd)
66 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070067 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
68 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000069 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
70 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070071 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000072 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000073 SkClampMax(SkScalarRoundToInt(color.fX), 255),
74 SkClampMax(SkScalarRoundToInt(color.fY), 255),
75 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000076 }
77private:
78 SkScalar fKD;
79};
80
robertphillips3d32d762015-07-13 13:16:44 -070081static SkScalar max_component(const SkPoint3& p) {
82 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
83}
84
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085class SpecularLightingType {
86public:
87 SpecularLightingType(SkScalar ks, SkScalar shininess)
88 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070089 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
90 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000091 SkPoint3 halfDir(surfaceTolight);
92 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
93 halfDir.normalize();
94 SkScalar colorScale = SkScalarMul(fKS,
95 SkScalarPow(normal.dot(halfDir), fShininess));
96 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070097 SkPoint3 color = lightColor.makeScale(colorScale);
98 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000099 SkClampMax(SkScalarRoundToInt(color.fX), 255),
100 SkClampMax(SkScalarRoundToInt(color.fY), 255),
101 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000102 }
103private:
104 SkScalar fKS;
105 SkScalar fShininess;
106};
107
108inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
109 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
110}
111
112inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700113 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
114 SkScalarMul(-y, surfaceScale),
115 SK_Scalar1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000116 vector.normalize();
117 return vector;
118}
119
120inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
122 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
123 surfaceScale);
124}
125
126inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
128 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
129 surfaceScale);
130}
131
132inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
134 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
135 surfaceScale);
136}
137
138inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
139 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
140 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
141 surfaceScale);
142}
143
144
145inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
147 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
148 surfaceScale);
149}
150
151inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
153 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
159 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
160 surfaceScale);
161}
162
163inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
165 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
166 surfaceScale);
167}
168
169inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
170 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
171 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
172 surfaceScale);
173}
174
joshualittb0a8a372014-09-23 09:50:21 -0700175template <class LightingType, class LightType> void lightBitmap(
176 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
177 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000178 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000179 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000180 int left = bounds.left(), right = bounds.right();
181 int bottom = bounds.bottom();
182 int y = bounds.top();
183 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000184 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000185 int x = left;
186 const SkPMColor* row1 = src.getAddr32(x, y);
187 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000189 m[4] = SkGetPackedA32(*row1++);
190 m[5] = SkGetPackedA32(*row1++);
191 m[7] = SkGetPackedA32(*row2++);
192 m[8] = SkGetPackedA32(*row2++);
193 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700194 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
195 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000196 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000197 {
198 shiftMatrixLeft(m);
199 m[5] = SkGetPackedA32(*row1++);
200 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000201 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700202 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
203 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 }
205 shiftMatrixLeft(m);
206 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700207 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
208 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000209 }
210
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000211 for (++y; y < bottom - 1; ++y) {
212 int x = left;
213 const SkPMColor* row0 = src.getAddr32(x, y - 1);
214 const SkPMColor* row1 = src.getAddr32(x, y);
215 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000216 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000217 m[1] = SkGetPackedA32(*row0++);
218 m[2] = SkGetPackedA32(*row0++);
219 m[4] = SkGetPackedA32(*row1++);
220 m[5] = SkGetPackedA32(*row1++);
221 m[7] = SkGetPackedA32(*row2++);
222 m[8] = SkGetPackedA32(*row2++);
223 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700224 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
225 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000226 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000227 shiftMatrixLeft(m);
228 m[2] = SkGetPackedA32(*row0++);
229 m[5] = SkGetPackedA32(*row1++);
230 m[8] = SkGetPackedA32(*row2++);
231 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700232 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
233 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000234 }
235 shiftMatrixLeft(m);
236 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700237 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
238 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 }
240
241 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000242 int x = left;
243 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
244 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000245 int m[9];
246 m[1] = SkGetPackedA32(*row0++);
247 m[2] = SkGetPackedA32(*row0++);
248 m[4] = SkGetPackedA32(*row1++);
249 m[5] = SkGetPackedA32(*row1++);
250 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700251 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
252 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000253 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000254 {
255 shiftMatrixLeft(m);
256 m[2] = SkGetPackedA32(*row0++);
257 m[5] = SkGetPackedA32(*row1++);
258 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700259 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
260 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000261 }
262 shiftMatrixLeft(m);
263 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700264 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
265 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000266 }
267}
268
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000269SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270 SkPoint3 point;
271 point.fX = buffer.readScalar();
272 point.fY = buffer.readScalar();
273 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000274 buffer.validate(SkScalarIsFinite(point.fX) &&
275 SkScalarIsFinite(point.fY) &&
276 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000277 return point;
278};
279
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000280void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000281 buffer.writeScalar(point.fX);
282 buffer.writeScalar(point.fY);
283 buffer.writeScalar(point.fZ);
284};
285
senorblancod0d37ca2015-04-02 04:54:56 -0700286enum BoundaryMode {
287 kTopLeft_BoundaryMode,
288 kTop_BoundaryMode,
289 kTopRight_BoundaryMode,
290 kLeft_BoundaryMode,
291 kInterior_BoundaryMode,
292 kRight_BoundaryMode,
293 kBottomLeft_BoundaryMode,
294 kBottom_BoundaryMode,
295 kBottomRight_BoundaryMode,
296
297 kBoundaryModeCount,
298};
299
300class SkLightingImageFilterInternal : public SkLightingImageFilter {
301protected:
302 SkLightingImageFilterInternal(SkLight* light,
303 SkScalar surfaceScale,
304 SkImageFilter* input,
305 const CropRect* cropRect)
306 : INHERITED(light, surfaceScale, input, cropRect) {}
307
308#if SK_SUPPORT_GPU
309 bool canFilterImageGPU() const override { return true; }
310 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
311 SkBitmap* result, SkIPoint* offset) const override;
joshualitt5f10b5c2015-07-09 10:24:35 -0700312 virtual GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*,
313 GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700314 const SkMatrix&,
315 const SkIRect& bounds,
316 BoundaryMode boundaryMode) const = 0;
317#endif
318private:
319#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700320 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700321 GrTexture* src,
322 GrTexture* dst,
323 const SkMatrix& matrix,
324 const GrClip& clip,
325 const SkRect& dstRect,
326 BoundaryMode boundaryMode,
327 const SkIRect& bounds) const;
328#endif
329 typedef SkLightingImageFilter INHERITED;
330};
331
332#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700333void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700334 GrTexture* src,
335 GrTexture* dst,
336 const SkMatrix& matrix,
337 const GrClip& clip,
338 const SkRect& dstRect,
339 BoundaryMode boundaryMode,
340 const SkIRect& bounds) const {
341 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700342 GrPaint paint;
joshualitt5f10b5c2015-07-09 10:24:35 -0700343 GrFragmentProcessor* fp = this->getFragmentProcessor(paint.getProcessorDataManager(), src,
344 matrix, bounds, boundaryMode);
senorblancod0d37ca2015-04-02 04:54:56 -0700345 paint.addColorProcessor(fp)->unref();
robertphillipsea461502015-05-26 11:38:03 -0700346 drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
347 dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700348}
349
350bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
351 const SkBitmap& src,
352 const Context& ctx,
353 SkBitmap* result,
354 SkIPoint* offset) const {
355 SkBitmap input = src;
356 SkIPoint srcOffset = SkIPoint::Make(0, 0);
357 if (this->getInput(0) &&
358 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
359 return false;
360 }
361 SkIRect bounds;
362 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
363 return false;
364 }
365 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
366 SkIntToScalar(bounds.height()));
367 GrTexture* srcTexture = input.getTexture();
368 GrContext* context = srcTexture->getContext();
369
370 GrSurfaceDesc desc;
371 desc.fFlags = kRenderTarget_GrSurfaceFlag,
372 desc.fWidth = bounds.width();
373 desc.fHeight = bounds.height();
374 desc.fConfig = kRGBA_8888_GrPixelConfig;
375
bsalomond309e7a2015-04-30 14:18:54 -0700376 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(desc,
377 GrTextureProvider::kApprox_ScratchTexMatch));
senorblancod0d37ca2015-04-02 04:54:56 -0700378 if (!dst) {
379 return false;
380 }
381
382 // setup new clip
383 GrClip clip(dstRect);
384
385 offset->fX = bounds.left();
386 offset->fY = bounds.top();
387 SkMatrix matrix(ctx.ctm());
388 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
389 bounds.offset(-srcOffset);
390 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
391 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
392 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
393 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
394 SkRect interior = dstRect.makeInset(1, 1);
395 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
396 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
397 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
398 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700399
400 GrDrawContext* drawContext = context->drawContext();
401 if (!drawContext) {
402 return false;
403 }
404
405 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700406 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700407 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
408 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700409 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700410 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
411 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700412 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700413 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
414 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700415 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700416 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
417 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
418 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700419 WrapTexture(dst, bounds.width(), bounds.height(), result);
420 return true;
421}
422#endif
423
424class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000425public:
reed9fa60da2014-08-21 07:59:51 -0700426 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700427 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700428
robertphillipsf3f5bad2014-12-19 13:49:15 -0800429 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000430 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000431 SkScalar kd() const { return fKD; }
432
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000433protected:
reed9fa60da2014-08-21 07:59:51 -0700434 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700435 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700436 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700437 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
438 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000439#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700440 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700441 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000442#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000443
444private:
reed9fa60da2014-08-21 07:59:51 -0700445 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700446 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000447 SkScalar fKD;
448};
449
senorblancod0d37ca2015-04-02 04:54:56 -0700450class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000451public:
reed9fa60da2014-08-21 07:59:51 -0700452 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700453 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700454
robertphillipsf3f5bad2014-12-19 13:49:15 -0800455 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
457
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000458 SkScalar ks() const { return fKS; }
459 SkScalar shininess() const { return fShininess; }
460
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461protected:
reed9fa60da2014-08-21 07:59:51 -0700462 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700463 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700464 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700465 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
466 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000467#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700468 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700469 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000470#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471
472private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000473 SkScalar fKS;
474 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700475 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700476 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000477};
478
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000479#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000480
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000481class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000482public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700483 GrLightingEffect(GrProcessorDataManager*, GrTexture* texture, const SkLight* light,
484 SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000485 virtual ~GrLightingEffect();
486
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000487 const SkLight* light() const { return fLight; }
488 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000489 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700490 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000491
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000492protected:
mtklein36352bf2015-03-25 18:17:31 -0700493 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000494
mtklein36352bf2015-03-25 18:17:31 -0700495 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700496 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800497 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700498 }
499
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000500private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000501 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000502 const SkLight* fLight;
503 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000504 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700505 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000506};
507
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508class GrDiffuseLightingEffect : public GrLightingEffect {
509public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700510 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
511 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700512 const SkLight* light,
513 SkScalar surfaceScale,
514 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700515 SkScalar kd,
516 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700517 return SkNEW_ARGS(GrDiffuseLightingEffect, (procDataManager,
518 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700519 light,
520 surfaceScale,
521 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700522 kd,
523 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000524 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000525
mtklein36352bf2015-03-25 18:17:31 -0700526 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527
jvanverthcfc18862015-04-28 08:48:20 -0700528 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529
mtklein36352bf2015-03-25 18:17:31 -0700530 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800531
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000532 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534private:
mtklein36352bf2015-03-25 18:17:31 -0700535 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000536
joshualitt5f10b5c2015-07-09 10:24:35 -0700537 GrDiffuseLightingEffect(GrProcessorDataManager*,
538 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000539 const SkLight* light,
540 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000541 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700542 SkScalar kd,
543 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000544
joshualittb0a8a372014-09-23 09:50:21 -0700545 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000546 typedef GrLightingEffect INHERITED;
547 SkScalar fKD;
548};
549
550class GrSpecularLightingEffect : public GrLightingEffect {
551public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700552 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
553 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700554 const SkLight* light,
555 SkScalar surfaceScale,
556 const SkMatrix& matrix,
557 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700558 SkScalar shininess,
559 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700560 return SkNEW_ARGS(GrSpecularLightingEffect, (procDataManager,
561 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700562 light,
563 surfaceScale,
564 matrix,
565 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700566 shininess,
567 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000568 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000569
mtklein36352bf2015-03-25 18:17:31 -0700570 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000571
jvanverthcfc18862015-04-28 08:48:20 -0700572 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800573
mtklein36352bf2015-03-25 18:17:31 -0700574 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800575
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000576 SkScalar ks() const { return fKS; }
577 SkScalar shininess() const { return fShininess; }
578
579private:
mtklein36352bf2015-03-25 18:17:31 -0700580 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000581
joshualitt5f10b5c2015-07-09 10:24:35 -0700582 GrSpecularLightingEffect(GrProcessorDataManager*,
583 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000584 const SkLight* light,
585 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000586 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000587 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700588 SkScalar shininess,
589 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000590
joshualittb0a8a372014-09-23 09:50:21 -0700591 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000592 typedef GrLightingEffect INHERITED;
593 SkScalar fKS;
594 SkScalar fShininess;
595};
596
597///////////////////////////////////////////////////////////////////////////////
598
599class GrGLLight {
600public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000601 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000602
603 /**
604 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
605 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
606 */
joshualitt15988992014-10-09 15:04:05 -0700607 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000608
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000609 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000610 * These two functions are called from GrGLLightingEffect's emitCode() function.
611 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
612 * the light. The expression will be used in the FS. emitLightColor writes an expression into
613 * the FS that is the color of the light. Either function may add functions and/or uniforms to
614 * the FS. The default of emitLightColor appends the name of the constant light color uniform
615 * and so this function only needs to be overridden if the light color varies spatially.
616 */
joshualitt15988992014-10-09 15:04:05 -0700617 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
618 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000619
620 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
621 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700622 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000623 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000624
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000625protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000626 /**
627 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
628 * function.
629 */
630 UniformHandle lightColorUni() const { return fColorUni; }
631
632private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000633 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000634
635 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000636};
637
638///////////////////////////////////////////////////////////////////////////////
639
640class GrGLDistantLight : public GrGLLight {
641public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000642 virtual ~GrGLDistantLight() {}
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 fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000649};
650
651///////////////////////////////////////////////////////////////////////////////
652
653class GrGLPointLight : public GrGLLight {
654public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000655 virtual ~GrGLPointLight() {}
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;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000658
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000659private:
660 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000661 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000662};
663
664///////////////////////////////////////////////////////////////////////////////
665
666class GrGLSpotLight : public GrGLLight {
667public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000668 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700669 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700670 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
671 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000672
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000673private:
674 typedef GrGLLight INHERITED;
675
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000676 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000677 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000678 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000679 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000680 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000681 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000682 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000683};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000684#else
685
686class GrGLLight;
687
688#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000689
690};
691
692///////////////////////////////////////////////////////////////////////////////
693
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000694class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695public:
mtklein2766c002015-06-26 11:45:03 -0700696
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000697
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698 enum LightType {
699 kDistant_LightType,
700 kPoint_LightType,
701 kSpot_LightType,
702 };
703 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000704 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000705 virtual GrGLLight* createGLLight() const = 0;
706 virtual bool isEqual(const SkLight& other) const {
707 return fColor == other.fColor;
708 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000709 // Called to know whether the generated GrGLLight will require access to the fragment position.
710 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000711 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000713 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000714 void flattenLight(SkWriteBuffer& buffer) const;
715 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000716
djsollen@google.com08337772012-06-26 14:33:13 +0000717protected:
robertphillips3d32d762015-07-13 13:16:44 -0700718 SkLight(SkColor color) {
719 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
720 SkIntToScalar(SkColorGetG(color)),
721 SkIntToScalar(SkColorGetB(color)));
722 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000723 SkLight(const SkPoint3& color)
724 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000725 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000726 fColor = readPoint3(buffer);
727 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000728
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000729 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000730
djsollen@google.com08337772012-06-26 14:33:13 +0000731
732private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000733 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000735};
736
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000737///////////////////////////////////////////////////////////////////////////////
738
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000739class SkDistantLight : public SkLight {
740public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 SkDistantLight(const SkPoint3& direction, SkColor color)
742 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743 }
djsollen@google.com08337772012-06-26 14:33:13 +0000744
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000745 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
746 return fDirection;
747 };
robertphillips3d32d762015-07-13 13:16:44 -0700748 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700749 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000750 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700751 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000752#if SK_SUPPORT_GPU
753 return SkNEW(GrGLDistantLight);
754#else
755 SkDEBUGFAIL("Should not call in GPU-less build");
756 return NULL;
757#endif
758 }
mtklein36352bf2015-03-25 18:17:31 -0700759 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000760
mtklein36352bf2015-03-25 18:17:31 -0700761 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000762 if (other.type() != kDistant_LightType) {
763 return false;
764 }
765
766 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
767 return INHERITED::isEqual(other) &&
768 fDirection == o.fDirection;
769 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000770
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000771 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000772 fDirection = readPoint3(buffer);
773 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774
djsollen@google.com08337772012-06-26 14:33:13 +0000775protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000776 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
777 : INHERITED(color), fDirection(direction) {
778 }
mtklein36352bf2015-03-25 18:17:31 -0700779 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000780 return new SkDistantLight(direction(), color());
781 }
mtklein36352bf2015-03-25 18:17:31 -0700782 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000783 writePoint3(fDirection, buffer);
784 }
785
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786private:
djsollen@google.com08337772012-06-26 14:33:13 +0000787 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000788 SkPoint3 fDirection;
789};
790
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000791///////////////////////////////////////////////////////////////////////////////
792
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000793class SkPointLight : public SkLight {
794public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000795 SkPointLight(const SkPoint3& location, SkColor color)
796 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000797
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000798 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700799 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
800 fLocation.fY - SkIntToScalar(y),
801 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
802 surfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000803 direction.normalize();
804 return direction;
805 };
robertphillips3d32d762015-07-13 13:16:44 -0700806 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700807 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000808 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700809 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000810#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000811 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000812#else
813 SkDEBUGFAIL("Should not call in GPU-less build");
814 return NULL;
815#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000816 }
mtklein36352bf2015-03-25 18:17:31 -0700817 bool requiresFragmentPosition() const override { return true; }
818 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000819 if (other.type() != kPoint_LightType) {
820 return false;
821 }
822 const SkPointLight& o = static_cast<const SkPointLight&>(other);
823 return INHERITED::isEqual(other) &&
824 fLocation == o.fLocation;
825 }
mtklein36352bf2015-03-25 18:17:31 -0700826 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000827 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
828 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000829 // Use X scale and Y scale on Z and average the result
830 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
831 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700832 SkPoint3 location = SkPoint3::Make(location2.fX,
833 location2.fY,
834 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000835 return new SkPointLight(location, color());
836 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000837
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000838 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000839 fLocation = readPoint3(buffer);
840 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000841
842protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000843 SkPointLight(const SkPoint3& location, const SkPoint3& color)
844 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700845 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000846 writePoint3(fLocation, buffer);
847 }
848
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000849private:
djsollen@google.com08337772012-06-26 14:33:13 +0000850 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000851 SkPoint3 fLocation;
852};
853
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000854///////////////////////////////////////////////////////////////////////////////
855
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000856class SkSpotLight : public SkLight {
857public:
senorblancod0d37ca2015-04-02 04:54:56 -0700858 SkSpotLight(const SkPoint3& location,
859 const SkPoint3& target,
860 SkScalar specularExponent,
861 SkScalar cutoffAngle,
862 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000863 : INHERITED(color),
864 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000865 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000866 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867 {
868 fS = target - location;
869 fS.normalize();
870 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000871 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000872 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
873 fConeScale = SkScalarInvert(antiAliasThreshold);
874 }
djsollen@google.com08337772012-06-26 14:33:13 +0000875
mtklein36352bf2015-03-25 18:17:31 -0700876 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000877 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
878 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000879 // Use X scale and Y scale on Z and average the result
880 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
881 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700882 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
883 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000884 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
885 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000886 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
887 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700888 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
889 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000890 SkPoint3 s = target - location;
891 s.normalize();
senorblancod0d37ca2015-04-02 04:54:56 -0700892 return new SkSpotLight(location,
893 target,
894 fSpecularExponent,
895 fCosOuterConeAngle,
896 fCosInnerConeAngle,
897 fConeScale,
898 s,
899 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000900 }
901
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000902 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700903 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
904 fLocation.fY - SkIntToScalar(y),
905 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
906 surfaceScale));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000907 direction.normalize();
908 return direction;
909 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000910 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700912 SkScalar scale = 0;
913 if (cosAngle >= fCosOuterConeAngle) {
914 scale = SkScalarPow(cosAngle, fSpecularExponent);
915 if (cosAngle < fCosInnerConeAngle) {
916 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
917 scale *= fConeScale;
918 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000919 }
robertphillips3d32d762015-07-13 13:16:44 -0700920 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000921 }
mtklein36352bf2015-03-25 18:17:31 -0700922 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000923#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000924 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000925#else
926 SkDEBUGFAIL("Should not call in GPU-less build");
927 return NULL;
928#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000929 }
mtklein36352bf2015-03-25 18:17:31 -0700930 bool requiresFragmentPosition() const override { return true; }
931 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000932 const SkPoint3& location() const { return fLocation; }
933 const SkPoint3& target() const { return fTarget; }
934 SkScalar specularExponent() const { return fSpecularExponent; }
935 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
936 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
937 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000938 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000939
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000940 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000941 fLocation = readPoint3(buffer);
942 fTarget = readPoint3(buffer);
943 fSpecularExponent = buffer.readScalar();
944 fCosOuterConeAngle = buffer.readScalar();
945 fCosInnerConeAngle = buffer.readScalar();
946 fConeScale = buffer.readScalar();
947 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000948 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
949 SkScalarIsFinite(fCosOuterConeAngle) &&
950 SkScalarIsFinite(fCosInnerConeAngle) &&
951 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000952 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000953protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700954 SkSpotLight(const SkPoint3& location,
955 const SkPoint3& target,
956 SkScalar specularExponent,
957 SkScalar cosOuterConeAngle,
958 SkScalar cosInnerConeAngle,
959 SkScalar coneScale,
960 const SkPoint3& s,
961 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000962 : INHERITED(color),
963 fLocation(location),
964 fTarget(target),
965 fSpecularExponent(specularExponent),
966 fCosOuterConeAngle(cosOuterConeAngle),
967 fCosInnerConeAngle(cosInnerConeAngle),
968 fConeScale(coneScale),
969 fS(s)
970 {
971 }
mtklein36352bf2015-03-25 18:17:31 -0700972 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000973 writePoint3(fLocation, buffer);
974 writePoint3(fTarget, buffer);
975 buffer.writeScalar(fSpecularExponent);
976 buffer.writeScalar(fCosOuterConeAngle);
977 buffer.writeScalar(fCosInnerConeAngle);
978 buffer.writeScalar(fConeScale);
979 writePoint3(fS, buffer);
980 }
981
mtklein36352bf2015-03-25 18:17:31 -0700982 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000983 if (other.type() != kSpot_LightType) {
984 return false;
985 }
986
987 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
988 return INHERITED::isEqual(other) &&
989 fLocation == o.fLocation &&
990 fTarget == o.fTarget &&
991 fSpecularExponent == o.fSpecularExponent &&
992 fCosOuterConeAngle == o.fCosOuterConeAngle;
993 }
994
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000995private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000996 static const SkScalar kSpecularExponentMin;
997 static const SkScalar kSpecularExponentMax;
998
djsollen@google.com08337772012-06-26 14:33:13 +0000999 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001000 SkPoint3 fLocation;
1001 SkPoint3 fTarget;
1002 SkScalar fSpecularExponent;
1003 SkScalar fCosOuterConeAngle;
1004 SkScalar fCosInnerConeAngle;
1005 SkScalar fConeScale;
1006 SkPoint3 fS;
1007};
1008
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001009// According to the spec, the specular term should be in the range [1, 128] :
1010// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001011const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1012const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001013
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001014///////////////////////////////////////////////////////////////////////////////
1015
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001016void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001017 // Write type first, then baseclass, then subclass.
1018 buffer.writeInt(this->type());
1019 writePoint3(fColor, buffer);
1020 this->onFlattenLight(buffer);
1021}
1022
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001023/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001024 // Read type first.
1025 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
1026 switch (type) {
1027 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1028 // then subclass, same order as flattenLight.
1029 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1030 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1031 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1032 default:
1033 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001034 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001035 return NULL;
1036 }
1037}
1038///////////////////////////////////////////////////////////////////////////////
1039
senorblanco9ea3d572014-07-08 09:16:22 -07001040SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001041 SkImageFilter* input, const CropRect* cropRect)
1042 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001043 , fLight(SkRef(light))
1044 , fSurfaceScale(surfaceScale / 255)
1045{}
1046
1047SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1048 SkColor lightColor,
1049 SkScalar surfaceScale,
1050 SkScalar kd,
1051 SkImageFilter* input,
1052 const CropRect* cropRect) {
1053 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1054 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001055}
1056
reed9fa60da2014-08-21 07:59:51 -07001057SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1058 SkColor lightColor,
1059 SkScalar surfaceScale,
1060 SkScalar kd,
1061 SkImageFilter* input,
1062 const CropRect* cropRect) {
1063 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1064 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001065}
1066
reed9fa60da2014-08-21 07:59:51 -07001067SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1068 const SkPoint3& target,
1069 SkScalar specularExponent,
1070 SkScalar cutoffAngle,
1071 SkColor lightColor,
1072 SkScalar surfaceScale,
1073 SkScalar kd,
1074 SkImageFilter* input,
1075 const CropRect* cropRect) {
1076 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1077 cutoffAngle, lightColor)));
1078 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001079}
1080
reed9fa60da2014-08-21 07:59:51 -07001081SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1082 SkColor lightColor,
1083 SkScalar surfaceScale,
1084 SkScalar ks,
1085 SkScalar shine,
1086 SkImageFilter* input,
1087 const CropRect* cropRect) {
1088 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1089 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001090}
1091
reed9fa60da2014-08-21 07:59:51 -07001092SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1093 SkColor lightColor,
1094 SkScalar surfaceScale,
1095 SkScalar ks,
1096 SkScalar shine,
1097 SkImageFilter* input,
1098 const CropRect* cropRect) {
1099 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1100 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001101}
1102
reed9fa60da2014-08-21 07:59:51 -07001103SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1104 const SkPoint3& target,
1105 SkScalar specularExponent,
1106 SkScalar cutoffAngle,
1107 SkColor lightColor,
1108 SkScalar surfaceScale,
1109 SkScalar ks,
1110 SkScalar shine,
1111 SkImageFilter* input,
1112 const CropRect* cropRect) {
1113 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1114 cutoffAngle, lightColor)));
1115 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001116}
1117
reed9fa60da2014-08-21 07:59:51 -07001118SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001119
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001120void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001121 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001122 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001123 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001124}
1125
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001126///////////////////////////////////////////////////////////////////////////////
1127
reed9fa60da2014-08-21 07:59:51 -07001128SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001129 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001130 if (NULL == light) {
1131 return NULL;
1132 }
1133 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1134 return NULL;
1135 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001136 // According to the spec, kd can be any non-negative number :
1137 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001138 if (kd < 0) {
1139 return NULL;
1140 }
senorblanco24e06d52015-03-18 12:11:33 -07001141 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001142}
1143
senorblancod0d37ca2015-04-02 04:54:56 -07001144SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1145 SkScalar surfaceScale,
1146 SkScalar kd,
1147 SkImageFilter* input,
1148 const CropRect* cropRect)
1149 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001150 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001151{
1152}
1153
reed9fa60da2014-08-21 07:59:51 -07001154SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1155 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1156 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1157 SkScalar surfaceScale = buffer.readScalar();
1158 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001159 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001160}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001161
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001162void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001163 this->INHERITED::flatten(buffer);
1164 buffer.writeScalar(fKD);
1165}
1166
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001167bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1168 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001169 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001171 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001172 SkImageFilter* input = getInput(0);
1173 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001174 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001175 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001176 return false;
1177 }
1178
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001179 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001180 return false;
1181 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001182 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001183 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001184 return false;
1185 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001186
1187 if (bounds.width() < 2 || bounds.height() < 2) {
1188 return false;
1189 }
1190
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001191 SkAutoLockPixels alp(src);
1192 if (!src.getPixels()) {
1193 return false;
1194 }
1195
reed84825042014-09-02 12:50:45 -07001196 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001197 return false;
1198 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001199
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001200 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001201
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001202 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001203 offset->fX = bounds.left();
1204 offset->fY = bounds.top();
1205 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001206 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001207 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001208 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1209 transformedLight,
1210 src,
1211 dst,
1212 surfaceScale(),
1213 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001214 break;
1215 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001216 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1217 transformedLight,
1218 src,
1219 dst,
1220 surfaceScale(),
1221 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001222 break;
1223 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001224 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1225 transformedLight,
1226 src,
1227 dst,
1228 surfaceScale(),
1229 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001230 break;
1231 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001232
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001233 return true;
1234}
1235
robertphillipsf3f5bad2014-12-19 13:49:15 -08001236#ifndef SK_IGNORE_TO_STRING
1237void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1238 str->appendf("SkDiffuseLightingImageFilter: (");
1239 str->appendf("kD: %f\n", fKD);
1240 str->append(")");
1241}
1242#endif
1243
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001244#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001245GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001246 GrProcessorDataManager* procDataManager,
1247 GrTexture* texture,
1248 const SkMatrix& matrix,
1249 const SkIRect&,
1250 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001251) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001252 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1253 return GrDiffuseLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1254 this->kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001255}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001256#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001257
1258///////////////////////////////////////////////////////////////////////////////
1259
reed9fa60da2014-08-21 07:59:51 -07001260SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001261 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001262 if (NULL == light) {
1263 return NULL;
1264 }
1265 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1266 return NULL;
1267 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001268 // According to the spec, ks can be any non-negative number :
1269 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001270 if (ks < 0) {
1271 return NULL;
1272 }
1273 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001274 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001275}
1276
senorblancod0d37ca2015-04-02 04:54:56 -07001277SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1278 SkScalar surfaceScale,
1279 SkScalar ks,
1280 SkScalar shininess,
1281 SkImageFilter* input,
1282 const CropRect* cropRect)
1283 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001284 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001285 fShininess(shininess)
1286{
1287}
1288
reed9fa60da2014-08-21 07:59:51 -07001289SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1290 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1291 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1292 SkScalar surfaceScale = buffer.readScalar();
1293 SkScalar ks = buffer.readScalar();
1294 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001295 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001296}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001297
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001298void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001299 this->INHERITED::flatten(buffer);
1300 buffer.writeScalar(fKS);
1301 buffer.writeScalar(fShininess);
1302}
1303
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001304bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1305 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001306 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001307 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001308 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001309 SkImageFilter* input = getInput(0);
1310 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001311 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001312 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001313 return false;
1314 }
1315
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001316 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001317 return false;
1318 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001319
1320 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001321 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001322 return false;
1323 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001324
1325 if (bounds.width() < 2 || bounds.height() < 2) {
1326 return false;
1327 }
1328
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001329 SkAutoLockPixels alp(src);
1330 if (!src.getPixels()) {
1331 return false;
1332 }
1333
reed84825042014-09-02 12:50:45 -07001334 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001335 return false;
1336 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001337
1338 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001339 offset->fX = bounds.left();
1340 offset->fY = bounds.top();
1341 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001342 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001343 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001344 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001345 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1346 transformedLight,
1347 src,
1348 dst,
1349 surfaceScale(),
1350 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001351 break;
1352 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001353 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1354 transformedLight,
1355 src,
1356 dst,
1357 surfaceScale(),
1358 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001359 break;
1360 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001361 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1362 transformedLight,
1363 src,
1364 dst,
1365 surfaceScale(),
1366 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001367 break;
1368 }
1369 return true;
1370}
1371
robertphillipsf3f5bad2014-12-19 13:49:15 -08001372#ifndef SK_IGNORE_TO_STRING
1373void SkSpecularLightingImageFilter::toString(SkString* str) const {
1374 str->appendf("SkSpecularLightingImageFilter: (");
1375 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1376 str->append(")");
1377}
1378#endif
1379
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001380#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001381GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001382 GrProcessorDataManager* procDataManager,
1383 GrTexture* texture,
1384 const SkMatrix& matrix,
1385 const SkIRect&,
1386 BoundaryMode boundaryMode) const {
1387 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1388 return GrSpecularLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1389 this->ks(), this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001390}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001391#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001392
1393///////////////////////////////////////////////////////////////////////////////
1394
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001395#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001396
1397namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001398SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001399 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1400 SkScalarToFloat(random->nextSScalar1()),
1401 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001402}
1403
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001404SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001405 int type = random->nextULessThan(3);
1406 switch (type) {
1407 case 0: {
1408 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1409 }
1410 case 1: {
1411 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1412 }
1413 case 2: {
1414 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1415 random_point3(random),
1416 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001417 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001418 random->nextU()));
1419 }
1420 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001421 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001422 return NULL;
1423 }
1424}
1425
senorblancod0d37ca2015-04-02 04:54:56 -07001426SkString emitNormalFunc(BoundaryMode mode,
1427 const char* pointToNormalName,
1428 const char* sobelFuncName) {
1429 SkString result;
1430 switch (mode) {
1431 case kTopLeft_BoundaryMode:
1432 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1433 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1434 "\t surfaceScale);\n",
1435 pointToNormalName, sobelFuncName, gTwoThirds,
1436 sobelFuncName, gTwoThirds);
1437 break;
1438 case kTop_BoundaryMode:
1439 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1440 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1441 "\t surfaceScale);\n",
1442 pointToNormalName, sobelFuncName, gOneThird,
1443 sobelFuncName, gOneHalf);
1444 break;
1445 case kTopRight_BoundaryMode:
1446 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1447 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1448 "\t surfaceScale);\n",
1449 pointToNormalName, sobelFuncName, gTwoThirds,
1450 sobelFuncName, gTwoThirds);
1451 break;
1452 case kLeft_BoundaryMode:
1453 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1454 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1455 "\t surfaceScale);\n",
1456 pointToNormalName, sobelFuncName, gOneHalf,
1457 sobelFuncName, gOneThird);
1458 break;
1459 case kInterior_BoundaryMode:
1460 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1461 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1462 "\t surfaceScale);\n",
1463 pointToNormalName, sobelFuncName, gOneQuarter,
1464 sobelFuncName, gOneQuarter);
1465 break;
1466 case kRight_BoundaryMode:
1467 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1468 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1469 "\t surfaceScale);\n",
1470 pointToNormalName, sobelFuncName, gOneHalf,
1471 sobelFuncName, gOneThird);
1472 break;
1473 case kBottomLeft_BoundaryMode:
1474 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1475 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1476 "\t surfaceScale);\n",
1477 pointToNormalName, sobelFuncName, gTwoThirds,
1478 sobelFuncName, gTwoThirds);
1479 break;
1480 case kBottom_BoundaryMode:
1481 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1482 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1483 "\t surfaceScale);\n",
1484 pointToNormalName, sobelFuncName, gOneThird,
1485 sobelFuncName, gOneHalf);
1486 break;
1487 case kBottomRight_BoundaryMode:
1488 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1489 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1490 "\t surfaceScale);\n",
1491 pointToNormalName, sobelFuncName, gTwoThirds,
1492 sobelFuncName, gTwoThirds);
1493 break;
1494 default:
1495 SkASSERT(false);
1496 break;
1497 }
1498 return result;
1499}
1500
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001501}
1502
joshualittb0a8a372014-09-23 09:50:21 -07001503class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001504public:
joshualitteb2a6762014-12-04 11:35:33 -08001505 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001506 virtual ~GrGLLightingEffect();
1507
senorblancod0d37ca2015-04-02 04:54:56 -07001508 void emitCode(GrGLFPBuilder*,
1509 const GrFragmentProcessor&,
1510 const char* outputColor,
1511 const char* inputColor,
1512 const TransformedCoordsArray&,
1513 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001514
jvanverthcfc18862015-04-28 08:48:20 -07001515 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001516
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001517 /**
1518 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1519 */
mtklein36352bf2015-03-25 18:17:31 -07001520 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001521
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001522protected:
joshualitt15988992014-10-09 15:04:05 -07001523 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001524
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525private:
joshualittb0a8a372014-09-23 09:50:21 -07001526 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001527
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001528 UniformHandle fImageIncrementUni;
1529 UniformHandle fSurfaceScaleUni;
1530 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001531 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001532};
1533
1534///////////////////////////////////////////////////////////////////////////////
1535
1536class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1537public:
joshualitteb2a6762014-12-04 11:35:33 -08001538 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001539 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1540 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001541
1542private:
1543 typedef GrGLLightingEffect INHERITED;
1544
bsalomon@google.com032b2212012-07-16 13:36:18 +00001545 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001546};
1547
1548///////////////////////////////////////////////////////////////////////////////
1549
1550class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1551public:
joshualitteb2a6762014-12-04 11:35:33 -08001552 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001553 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1554 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001555
1556private:
1557 typedef GrGLLightingEffect INHERITED;
1558
bsalomon@google.com032b2212012-07-16 13:36:18 +00001559 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001560 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001561};
1562
1563///////////////////////////////////////////////////////////////////////////////
1564
joshualitt5f10b5c2015-07-09 10:24:35 -07001565GrLightingEffect::GrLightingEffect(GrProcessorDataManager* procDataManager,
1566 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001567 const SkLight* light,
1568 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001569 const SkMatrix& matrix,
1570 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001571 : INHERITED(procDataManager, texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001572 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001573 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001574 , fFilterMatrix(matrix)
1575 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001576 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001577 if (light->requiresFragmentPosition()) {
1578 this->setWillReadFragmentPosition();
1579 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001580}
1581
1582GrLightingEffect::~GrLightingEffect() {
1583 fLight->unref();
1584}
1585
bsalomon0e08fc12014-10-15 08:19:04 -07001586bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001587 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001588 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001589 fSurfaceScale == s.fSurfaceScale &&
1590 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001591}
1592
1593///////////////////////////////////////////////////////////////////////////////
1594
joshualitt5f10b5c2015-07-09 10:24:35 -07001595GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrProcessorDataManager* procDataManager,
1596 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001597 const SkLight* light,
1598 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001599 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001600 SkScalar kd,
1601 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001602 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001603 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001604}
1605
bsalomon0e08fc12014-10-15 08:19:04 -07001606bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001607 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001608 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001609 this->kd() == s.kd();
1610}
1611
jvanverthcfc18862015-04-28 08:48:20 -07001612void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001613 GrProcessorKeyBuilder* b) const {
1614 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1615}
1616
1617GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1618 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1619}
1620
joshualittb0a8a372014-09-23 09:50:21 -07001621GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001622
joshualitt0067ff52015-07-08 14:26:19 -07001623GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
1624 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1625 SkScalar kd = d->fRandom->nextUScalar1();
1626 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001627 SkMatrix matrix;
1628 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001629 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001630 }
joshualitt0067ff52015-07-08 14:26:19 -07001631 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001632 return GrDiffuseLightingEffect::Create(d->fProcDataManager,
1633 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001634 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001635}
1636
1637
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638///////////////////////////////////////////////////////////////////////////////
1639
joshualitteb2a6762014-12-04 11:35:33 -08001640GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001641 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001642 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001643 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001644}
1645
1646GrGLLightingEffect::~GrGLLightingEffect() {
1647 delete fLight;
1648}
1649
joshualitt15988992014-10-09 15:04:05 -07001650void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001651 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001652 const char* outputColor,
1653 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001654 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001655 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001656 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001657 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001658 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001659 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001660 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001661 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001662 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001663 SkString lightFunc;
1664 this->emitLightFunc(builder, &lightFunc);
1665 static const GrGLShaderVar gSobelArgs[] = {
1666 GrGLShaderVar("a", kFloat_GrSLType),
1667 GrGLShaderVar("b", kFloat_GrSLType),
1668 GrGLShaderVar("c", kFloat_GrSLType),
1669 GrGLShaderVar("d", kFloat_GrSLType),
1670 GrGLShaderVar("e", kFloat_GrSLType),
1671 GrGLShaderVar("f", kFloat_GrSLType),
1672 GrGLShaderVar("scale", kFloat_GrSLType),
1673 };
1674 SkString sobelFuncName;
egdaniel29bee0f2015-04-29 11:54:42 -07001675 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001676 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1677
1678 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001679 "sobel",
1680 SK_ARRAY_COUNT(gSobelArgs),
1681 gSobelArgs,
1682 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1683 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001684 static const GrGLShaderVar gPointToNormalArgs[] = {
1685 GrGLShaderVar("x", kFloat_GrSLType),
1686 GrGLShaderVar("y", kFloat_GrSLType),
1687 GrGLShaderVar("scale", kFloat_GrSLType),
1688 };
1689 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001690 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001691 "pointToNormal",
1692 SK_ARRAY_COUNT(gPointToNormalArgs),
1693 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001694 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001695 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001696
1697 static const GrGLShaderVar gInteriorNormalArgs[] = {
1698 GrGLShaderVar("m", kFloat_GrSLType, 9),
1699 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1700 };
senorblancod0d37ca2015-04-02 04:54:56 -07001701 SkString normalBody = emitNormalFunc(fBoundaryMode,
1702 pointToNormalName.c_str(),
1703 sobelFuncName.c_str());
1704 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001705 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001706 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001707 SK_ARRAY_COUNT(gInteriorNormalArgs),
1708 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001709 normalBody.c_str(),
1710 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001711
joshualitt30ba4362014-08-21 20:18:45 -07001712 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1713 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001714
1715 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1716 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1717
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001718 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001719 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001720 for (int dx = -1; dx <= 1; dx++) {
1721 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001722 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001723 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1724 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1725 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001726 }
1727 }
joshualitt30ba4362014-08-21 20:18:45 -07001728 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001729 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001730 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001731 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001732 fsBuilder->codeAppend(";\n");
1733 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
senorblancod0d37ca2015-04-02 04:54:56 -07001734 outputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001735 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001736 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001737 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001738 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001739 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001740}
1741
joshualittb0a8a372014-09-23 09:50:21 -07001742void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001743 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001744 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1745 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001746}
1747
kkinnunen7510b222014-07-30 00:04:16 -07001748void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001749 const GrProcessor& proc) {
1750 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001751 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001752 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001753 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1754 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001755 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001756 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001757}
1758
1759///////////////////////////////////////////////////////////////////////////////
1760
1761///////////////////////////////////////////////////////////////////////////////
1762
joshualitteb2a6762014-12-04 11:35:33 -08001763GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1764 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001765}
1766
joshualitt15988992014-10-09 15:04:05 -07001767void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001768 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001769 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001770 kFloat_GrSLType, kDefault_GrSLPrecision,
1771 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001772
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001773 static const GrGLShaderVar gLightArgs[] = {
1774 GrGLShaderVar("normal", kVec3f_GrSLType),
1775 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1776 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1777 };
1778 SkString lightBody;
1779 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1780 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001781 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1782 "light",
1783 SK_ARRAY_COUNT(gLightArgs),
1784 gLightArgs,
1785 lightBody.c_str(),
1786 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001787}
1788
kkinnunen7510b222014-07-30 00:04:16 -07001789void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001790 const GrProcessor& proc) {
1791 INHERITED::setData(pdman, proc);
1792 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001793 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001794}
1795
1796///////////////////////////////////////////////////////////////////////////////
1797
joshualitt5f10b5c2015-07-09 10:24:35 -07001798GrSpecularLightingEffect::GrSpecularLightingEffect(GrProcessorDataManager* procDataManager,
1799 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001800 const SkLight* light,
1801 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001802 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001803 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001804 SkScalar shininess,
1805 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001806 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001807 fKS(ks),
1808 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001809 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001810}
1811
bsalomon0e08fc12014-10-15 08:19:04 -07001812bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001813 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001814 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001815 this->ks() == s.ks() &&
1816 this->shininess() == s.shininess();
1817}
1818
jvanverthcfc18862015-04-28 08:48:20 -07001819void GrSpecularLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001820 GrProcessorKeyBuilder* b) const {
1821 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1822}
1823
1824GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1825 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1826}
1827
joshualittb0a8a372014-09-23 09:50:21 -07001828GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001829
joshualitt0067ff52015-07-08 14:26:19 -07001830GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
1831 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1832 SkScalar ks = d->fRandom->nextUScalar1();
1833 SkScalar shininess = d->fRandom->nextUScalar1();
1834 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001835 SkMatrix matrix;
1836 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001837 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001838 }
joshualitt0067ff52015-07-08 14:26:19 -07001839 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001840 return GrSpecularLightingEffect::Create(d->fProcDataManager,
1841 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001842 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001843}
1844
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001845///////////////////////////////////////////////////////////////////////////////
1846
joshualitteb2a6762014-12-04 11:35:33 -08001847GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1848 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001849}
1850
joshualitt15988992014-10-09 15:04:05 -07001851void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001852 const char* ks;
1853 const char* shininess;
1854
joshualitt30ba4362014-08-21 20:18:45 -07001855 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001856 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001857 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001858 kFloat_GrSLType,
1859 kDefault_GrSLPrecision,
1860 "Shininess",
1861 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001862
1863 static const GrGLShaderVar gLightArgs[] = {
1864 GrGLShaderVar("normal", kVec3f_GrSLType),
1865 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1866 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1867 };
1868 SkString lightBody;
1869 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1870 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001871 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1872 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001873 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1874 "light",
1875 SK_ARRAY_COUNT(gLightArgs),
1876 gLightArgs,
1877 lightBody.c_str(),
1878 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001879}
1880
kkinnunen7510b222014-07-30 00:04:16 -07001881void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001882 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001883 INHERITED::setData(pdman, effect);
1884 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001885 pdman.set1f(fKSUni, spec.ks());
1886 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001887}
1888
1889///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001890void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001891 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001892 kVec3f_GrSLType, kDefault_GrSLPrecision,
1893 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001894}
1895
robertphillips3d32d762015-07-13 13:16:44 -07001896void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001897 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001898}
1899
robertphillips3d32d762015-07-13 13:16:44 -07001900void GrGLLight::setData(const GrGLProgramDataManager& pdman, const SkLight* light) const {
1901 setUniformPoint3(pdman, fColorUni,
1902 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001903}
1904
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001905///////////////////////////////////////////////////////////////////////////////
1906
kkinnunen7510b222014-07-30 00:04:16 -07001907void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001908 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001909 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001910 SkASSERT(light->type() == SkLight::kDistant_LightType);
1911 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001912 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001913}
1914
joshualitt15988992014-10-09 15:04:05 -07001915void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001916 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001917 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1918 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001919 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001920 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001921}
1922
1923///////////////////////////////////////////////////////////////////////////////
1924
kkinnunen7510b222014-07-30 00:04:16 -07001925void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001926 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001927 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001928 SkASSERT(light->type() == SkLight::kPoint_LightType);
1929 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001930 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001931}
1932
joshualitt15988992014-10-09 15:04:05 -07001933void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001934 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001935 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1936 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001937 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001938 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001939 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1940 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001941}
1942
1943///////////////////////////////////////////////////////////////////////////////
1944
kkinnunen7510b222014-07-30 00:04:16 -07001945void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001946 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001947 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001948 SkASSERT(light->type() == SkLight::kSpot_LightType);
1949 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001950 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1951 pdman.set1f(fExponentUni, spotLight->specularExponent());
1952 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1953 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1954 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1955 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001956}
1957
joshualitt15988992014-10-09 15:04:05 -07001958void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001959 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001960 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001961 kVec3f_GrSLType, kDefault_GrSLPrecision,
1962 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001963
egdaniel29bee0f2015-04-29 11:54:42 -07001964 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001965 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1966 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001967}
1968
joshualitt15988992014-10-09 15:04:05 -07001969void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001970 const char *surfaceToLight) {
1971
1972 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1973
1974 const char* exponent;
1975 const char* cosInner;
1976 const char* cosOuter;
1977 const char* coneScale;
1978 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001979 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001980 kFloat_GrSLType, kDefault_GrSLPrecision,
1981 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001982 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001983 kFloat_GrSLType, kDefault_GrSLPrecision,
1984 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001985 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001986 kFloat_GrSLType, kDefault_GrSLPrecision,
1987 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001988 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001989 kFloat_GrSLType, kDefault_GrSLPrecision,
1990 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001991 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001992 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001993
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001994 static const GrGLShaderVar gLightColorArgs[] = {
1995 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1996 };
1997 SkString lightColorBody;
1998 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1999 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2000 lightColorBody.appendf("\t\treturn vec3(0);\n");
2001 lightColorBody.appendf("\t}\n");
2002 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2003 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2004 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2005 color, cosOuter, coneScale);
2006 lightColorBody.appendf("\t}\n");
2007 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07002008 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002009 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002010 "lightColor",
2011 SK_ARRAY_COUNT(gLightColorArgs),
2012 gLightColorArgs,
2013 lightColorBody.c_str(),
2014 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002015
joshualitt30ba4362014-08-21 20:18:45 -07002016 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002017}
2018
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002019#endif
2020
djsollen@google.com08337772012-06-26 14:33:13 +00002021SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2022 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2023 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002024SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END