blob: b82f6ad916e032dcbacd04e4634c4d26aca09819 [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
jvanverth992c7612015-07-17 07:22:30 -070063static inline void fast_normalize(SkPoint3* vector) {
64 // add a tiny bit so we don't have to worry about divide-by-zero
65 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
66 SkScalar scale = sk_float_rsqrt(magSq);
67 vector->fX *= scale;
68 vector->fY *= scale;
69 vector->fZ *= scale;
70}
71
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000072class DiffuseLightingType {
73public:
74 DiffuseLightingType(SkScalar kd)
75 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070076 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
77 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000078 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
79 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070080 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000081 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000082 SkClampMax(SkScalarRoundToInt(color.fX), 255),
83 SkClampMax(SkScalarRoundToInt(color.fY), 255),
84 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 }
86private:
87 SkScalar fKD;
88};
89
robertphillips3d32d762015-07-13 13:16:44 -070090static SkScalar max_component(const SkPoint3& p) {
91 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
92}
93
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000094class SpecularLightingType {
95public:
96 SpecularLightingType(SkScalar ks, SkScalar shininess)
97 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070098 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
99 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000100 SkPoint3 halfDir(surfaceTolight);
101 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700102 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000103 SkScalar colorScale = SkScalarMul(fKS,
104 SkScalarPow(normal.dot(halfDir), fShininess));
105 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700106 SkPoint3 color = lightColor.makeScale(colorScale);
107 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000108 SkClampMax(SkScalarRoundToInt(color.fX), 255),
109 SkClampMax(SkScalarRoundToInt(color.fY), 255),
110 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000111 }
112private:
113 SkScalar fKS;
114 SkScalar fShininess;
115};
116
117inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
118 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
119}
120
121inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700122 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
123 SkScalarMul(-y, surfaceScale),
124 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700125 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000126 return vector;
127}
128
129inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
130 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
131 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
132 surfaceScale);
133}
134
135inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
137 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
138 surfaceScale);
139}
140
141inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
142 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
143 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
144 surfaceScale);
145}
146
147inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
148 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
149 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
150 surfaceScale);
151}
152
153
154inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
155 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
156 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
157 surfaceScale);
158}
159
160inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
161 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
162 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
163 surfaceScale);
164}
165
166inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
167 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
168 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
169 surfaceScale);
170}
171
172inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
173 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
174 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
175 surfaceScale);
176}
177
178inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
179 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
180 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
181 surfaceScale);
182}
183
joshualittb0a8a372014-09-23 09:50:21 -0700184template <class LightingType, class LightType> void lightBitmap(
185 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
186 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000187 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000188 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000189 int left = bounds.left(), right = bounds.right();
190 int bottom = bounds.bottom();
191 int y = bounds.top();
192 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000193 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000194 int x = left;
195 const SkPMColor* row1 = src.getAddr32(x, y);
196 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000197 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000198 m[4] = SkGetPackedA32(*row1++);
199 m[5] = SkGetPackedA32(*row1++);
200 m[7] = SkGetPackedA32(*row2++);
201 m[8] = SkGetPackedA32(*row2++);
202 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700203 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
204 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000205 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000206 {
207 shiftMatrixLeft(m);
208 m[5] = SkGetPackedA32(*row1++);
209 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000210 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700211 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
212 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000213 }
214 shiftMatrixLeft(m);
215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700216 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
217 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000218 }
219
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000220 for (++y; y < bottom - 1; ++y) {
221 int x = left;
222 const SkPMColor* row0 = src.getAddr32(x, y - 1);
223 const SkPMColor* row1 = src.getAddr32(x, y);
224 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000225 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000226 m[1] = SkGetPackedA32(*row0++);
227 m[2] = SkGetPackedA32(*row0++);
228 m[4] = SkGetPackedA32(*row1++);
229 m[5] = SkGetPackedA32(*row1++);
230 m[7] = SkGetPackedA32(*row2++);
231 m[8] = SkGetPackedA32(*row2++);
232 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700233 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
234 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000235 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000236 shiftMatrixLeft(m);
237 m[2] = SkGetPackedA32(*row0++);
238 m[5] = SkGetPackedA32(*row1++);
239 m[8] = SkGetPackedA32(*row2++);
240 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700241 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
242 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000243 }
244 shiftMatrixLeft(m);
245 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700246 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
247 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 }
249
250 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000251 int x = left;
252 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
253 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000254 int m[9];
255 m[1] = SkGetPackedA32(*row0++);
256 m[2] = SkGetPackedA32(*row0++);
257 m[4] = SkGetPackedA32(*row1++);
258 m[5] = SkGetPackedA32(*row1++);
259 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700260 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
261 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000262 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000263 {
264 shiftMatrixLeft(m);
265 m[2] = SkGetPackedA32(*row0++);
266 m[5] = SkGetPackedA32(*row1++);
267 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700268 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
269 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270 }
271 shiftMatrixLeft(m);
272 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700273 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
274 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000275 }
276}
277
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000278SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000279 SkPoint3 point;
280 point.fX = buffer.readScalar();
281 point.fY = buffer.readScalar();
282 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000283 buffer.validate(SkScalarIsFinite(point.fX) &&
284 SkScalarIsFinite(point.fY) &&
285 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 return point;
287};
288
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000289void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000290 buffer.writeScalar(point.fX);
291 buffer.writeScalar(point.fY);
292 buffer.writeScalar(point.fZ);
293};
294
senorblancod0d37ca2015-04-02 04:54:56 -0700295enum BoundaryMode {
296 kTopLeft_BoundaryMode,
297 kTop_BoundaryMode,
298 kTopRight_BoundaryMode,
299 kLeft_BoundaryMode,
300 kInterior_BoundaryMode,
301 kRight_BoundaryMode,
302 kBottomLeft_BoundaryMode,
303 kBottom_BoundaryMode,
304 kBottomRight_BoundaryMode,
305
306 kBoundaryModeCount,
307};
308
309class SkLightingImageFilterInternal : public SkLightingImageFilter {
310protected:
311 SkLightingImageFilterInternal(SkLight* light,
312 SkScalar surfaceScale,
313 SkImageFilter* input,
314 const CropRect* cropRect)
315 : INHERITED(light, surfaceScale, input, cropRect) {}
316
317#if SK_SUPPORT_GPU
318 bool canFilterImageGPU() const override { return true; }
319 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
320 SkBitmap* result, SkIPoint* offset) const override;
joshualitt5f10b5c2015-07-09 10:24:35 -0700321 virtual GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*,
322 GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700323 const SkMatrix&,
324 const SkIRect& bounds,
325 BoundaryMode boundaryMode) const = 0;
326#endif
327private:
328#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700329 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700330 GrTexture* src,
331 GrTexture* dst,
332 const SkMatrix& matrix,
333 const GrClip& clip,
334 const SkRect& dstRect,
335 BoundaryMode boundaryMode,
336 const SkIRect& bounds) const;
337#endif
338 typedef SkLightingImageFilter INHERITED;
339};
340
341#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700342void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700343 GrTexture* src,
344 GrTexture* dst,
345 const SkMatrix& matrix,
346 const GrClip& clip,
347 const SkRect& dstRect,
348 BoundaryMode boundaryMode,
349 const SkIRect& bounds) const {
350 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700351 GrPaint paint;
joshualitt5f10b5c2015-07-09 10:24:35 -0700352 GrFragmentProcessor* fp = this->getFragmentProcessor(paint.getProcessorDataManager(), src,
353 matrix, bounds, boundaryMode);
senorblancod0d37ca2015-04-02 04:54:56 -0700354 paint.addColorProcessor(fp)->unref();
robertphillipsea461502015-05-26 11:38:03 -0700355 drawContext->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(),
356 dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700357}
358
359bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
360 const SkBitmap& src,
361 const Context& ctx,
362 SkBitmap* result,
363 SkIPoint* offset) const {
364 SkBitmap input = src;
365 SkIPoint srcOffset = SkIPoint::Make(0, 0);
366 if (this->getInput(0) &&
367 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
368 return false;
369 }
370 SkIRect bounds;
371 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
372 return false;
373 }
374 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
375 SkIntToScalar(bounds.height()));
376 GrTexture* srcTexture = input.getTexture();
377 GrContext* context = srcTexture->getContext();
378
379 GrSurfaceDesc desc;
380 desc.fFlags = kRenderTarget_GrSurfaceFlag,
381 desc.fWidth = bounds.width();
382 desc.fHeight = bounds.height();
383 desc.fConfig = kRGBA_8888_GrPixelConfig;
384
bsalomond309e7a2015-04-30 14:18:54 -0700385 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(desc,
386 GrTextureProvider::kApprox_ScratchTexMatch));
senorblancod0d37ca2015-04-02 04:54:56 -0700387 if (!dst) {
388 return false;
389 }
390
391 // setup new clip
392 GrClip clip(dstRect);
393
394 offset->fX = bounds.left();
395 offset->fY = bounds.top();
396 SkMatrix matrix(ctx.ctm());
397 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
398 bounds.offset(-srcOffset);
399 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
400 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
401 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
402 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
403 SkRect interior = dstRect.makeInset(1, 1);
404 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
405 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
406 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
407 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700408
409 GrDrawContext* drawContext = context->drawContext();
410 if (!drawContext) {
411 return false;
412 }
413
414 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700415 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700416 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
417 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700418 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700419 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
420 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700421 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700422 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
423 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700424 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700425 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
426 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
427 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700428 WrapTexture(dst, bounds.width(), bounds.height(), result);
429 return true;
430}
431#endif
432
433class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000434public:
reed9fa60da2014-08-21 07:59:51 -0700435 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700436 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700437
robertphillipsf3f5bad2014-12-19 13:49:15 -0800438 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000439 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000440 SkScalar kd() const { return fKD; }
441
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000442protected:
reed9fa60da2014-08-21 07:59:51 -0700443 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700444 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700445 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700446 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
447 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000448#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700449 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700450 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000451#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000452
453private:
reed9fa60da2014-08-21 07:59:51 -0700454 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700455 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000456 SkScalar fKD;
457};
458
senorblancod0d37ca2015-04-02 04:54:56 -0700459class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000460public:
reed9fa60da2014-08-21 07:59:51 -0700461 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700462 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700463
robertphillipsf3f5bad2014-12-19 13:49:15 -0800464 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000465 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
466
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000467 SkScalar ks() const { return fKS; }
468 SkScalar shininess() const { return fShininess; }
469
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000470protected:
reed9fa60da2014-08-21 07:59:51 -0700471 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700472 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700473 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700474 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
475 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000476#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700477 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700478 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000479#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000480
481private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000482 SkScalar fKS;
483 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700484 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700485 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000486};
487
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000488#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000489
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000490class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700492 GrLightingEffect(GrProcessorDataManager*, GrTexture* texture, const SkLight* light,
493 SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000494 virtual ~GrLightingEffect();
495
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496 const SkLight* light() const { return fLight; }
497 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000498 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700499 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000500
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000501protected:
mtklein36352bf2015-03-25 18:17:31 -0700502 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000503
mtklein36352bf2015-03-25 18:17:31 -0700504 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700505 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800506 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700507 }
508
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000509private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000510 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000511 const SkLight* fLight;
512 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000513 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700514 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000515};
516
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000517class GrDiffuseLightingEffect : public GrLightingEffect {
518public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700519 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
520 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700521 const SkLight* light,
522 SkScalar surfaceScale,
523 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700524 SkScalar kd,
525 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700526 return SkNEW_ARGS(GrDiffuseLightingEffect, (procDataManager,
527 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700528 light,
529 surfaceScale,
530 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700531 kd,
532 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000533 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534
mtklein36352bf2015-03-25 18:17:31 -0700535 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536
jvanverthcfc18862015-04-28 08:48:20 -0700537 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000538
mtklein36352bf2015-03-25 18:17:31 -0700539 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800540
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000541 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000542
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000543private:
mtklein36352bf2015-03-25 18:17:31 -0700544 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000545
joshualitt5f10b5c2015-07-09 10:24:35 -0700546 GrDiffuseLightingEffect(GrProcessorDataManager*,
547 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000548 const SkLight* light,
549 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000550 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700551 SkScalar kd,
552 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000553
joshualittb0a8a372014-09-23 09:50:21 -0700554 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000555 typedef GrLightingEffect INHERITED;
556 SkScalar fKD;
557};
558
559class GrSpecularLightingEffect : public GrLightingEffect {
560public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700561 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
562 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700563 const SkLight* light,
564 SkScalar surfaceScale,
565 const SkMatrix& matrix,
566 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700567 SkScalar shininess,
568 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700569 return SkNEW_ARGS(GrSpecularLightingEffect, (procDataManager,
570 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700571 light,
572 surfaceScale,
573 matrix,
574 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700575 shininess,
576 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000577 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000578
mtklein36352bf2015-03-25 18:17:31 -0700579 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000580
jvanverthcfc18862015-04-28 08:48:20 -0700581 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800582
mtklein36352bf2015-03-25 18:17:31 -0700583 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800584
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000585 SkScalar ks() const { return fKS; }
586 SkScalar shininess() const { return fShininess; }
587
588private:
mtklein36352bf2015-03-25 18:17:31 -0700589 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000590
joshualitt5f10b5c2015-07-09 10:24:35 -0700591 GrSpecularLightingEffect(GrProcessorDataManager*,
592 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000593 const SkLight* light,
594 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000595 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000596 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700597 SkScalar shininess,
598 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000599
joshualittb0a8a372014-09-23 09:50:21 -0700600 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000601 typedef GrLightingEffect INHERITED;
602 SkScalar fKS;
603 SkScalar fShininess;
604};
605
606///////////////////////////////////////////////////////////////////////////////
607
608class GrGLLight {
609public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000610 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000611
612 /**
613 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
614 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
615 */
joshualitt15988992014-10-09 15:04:05 -0700616 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000617
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000618 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000619 * These two functions are called from GrGLLightingEffect's emitCode() function.
620 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
621 * the light. The expression will be used in the FS. emitLightColor writes an expression into
622 * the FS that is the color of the light. Either function may add functions and/or uniforms to
623 * the FS. The default of emitLightColor appends the name of the constant light color uniform
624 * and so this function only needs to be overridden if the light color varies spatially.
625 */
joshualitt15988992014-10-09 15:04:05 -0700626 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
627 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000628
629 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
630 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700631 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000632 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000634protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000635 /**
636 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
637 * function.
638 */
639 UniformHandle lightColorUni() const { return fColorUni; }
640
641private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000642 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000643
644 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000645};
646
647///////////////////////////////////////////////////////////////////////////////
648
649class GrGLDistantLight : public GrGLLight {
650public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000651 virtual ~GrGLDistantLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700652 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700653 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000654
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000655private:
656 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000657 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000658};
659
660///////////////////////////////////////////////////////////////////////////////
661
662class GrGLPointLight : public GrGLLight {
663public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000664 virtual ~GrGLPointLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700665 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700666 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000667
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000668private:
669 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000670 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000671};
672
673///////////////////////////////////////////////////////////////////////////////
674
675class GrGLSpotLight : public GrGLLight {
676public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000677 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700678 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700679 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
680 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000681
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000682private:
683 typedef GrGLLight INHERITED;
684
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000685 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000686 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000687 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000688 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000689 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000690 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000691 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000692};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000693#else
694
695class GrGLLight;
696
697#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000698
699};
700
701///////////////////////////////////////////////////////////////////////////////
702
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000703class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000704public:
mtklein2766c002015-06-26 11:45:03 -0700705
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000706
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000707 enum LightType {
708 kDistant_LightType,
709 kPoint_LightType,
710 kSpot_LightType,
711 };
712 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000713 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000714 virtual GrGLLight* createGLLight() const = 0;
715 virtual bool isEqual(const SkLight& other) const {
716 return fColor == other.fColor;
717 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000718 // Called to know whether the generated GrGLLight will require access to the fragment position.
719 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000720 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000721
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000722 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000723 void flattenLight(SkWriteBuffer& buffer) const;
724 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000725
djsollen@google.com08337772012-06-26 14:33:13 +0000726protected:
robertphillips3d32d762015-07-13 13:16:44 -0700727 SkLight(SkColor color) {
728 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
729 SkIntToScalar(SkColorGetG(color)),
730 SkIntToScalar(SkColorGetB(color)));
731 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000732 SkLight(const SkPoint3& color)
733 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000734 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000735 fColor = readPoint3(buffer);
736 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000737
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000738 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000739
djsollen@google.com08337772012-06-26 14:33:13 +0000740
741private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000742 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000743 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000744};
745
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000746///////////////////////////////////////////////////////////////////////////////
747
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000748class SkDistantLight : public SkLight {
749public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000750 SkDistantLight(const SkPoint3& direction, SkColor color)
751 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000752 }
djsollen@google.com08337772012-06-26 14:33:13 +0000753
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000754 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
755 return fDirection;
756 };
robertphillips3d32d762015-07-13 13:16:44 -0700757 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700758 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000759 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700760 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000761#if SK_SUPPORT_GPU
762 return SkNEW(GrGLDistantLight);
763#else
764 SkDEBUGFAIL("Should not call in GPU-less build");
765 return NULL;
766#endif
767 }
mtklein36352bf2015-03-25 18:17:31 -0700768 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000769
mtklein36352bf2015-03-25 18:17:31 -0700770 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000771 if (other.type() != kDistant_LightType) {
772 return false;
773 }
774
775 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
776 return INHERITED::isEqual(other) &&
777 fDirection == o.fDirection;
778 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000779
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000780 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000781 fDirection = readPoint3(buffer);
782 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000783
djsollen@google.com08337772012-06-26 14:33:13 +0000784protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000785 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
786 : INHERITED(color), fDirection(direction) {
787 }
mtklein36352bf2015-03-25 18:17:31 -0700788 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000789 return new SkDistantLight(direction(), color());
790 }
mtklein36352bf2015-03-25 18:17:31 -0700791 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000792 writePoint3(fDirection, buffer);
793 }
794
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000795private:
djsollen@google.com08337772012-06-26 14:33:13 +0000796 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000797 SkPoint3 fDirection;
798};
799
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000800///////////////////////////////////////////////////////////////////////////////
801
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000802class SkPointLight : public SkLight {
803public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000804 SkPointLight(const SkPoint3& location, SkColor color)
805 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000806
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000807 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700808 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
809 fLocation.fY - SkIntToScalar(y),
810 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
811 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700812 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000813 return direction;
814 };
robertphillips3d32d762015-07-13 13:16:44 -0700815 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700816 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000817 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700818 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000819#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000820 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000821#else
822 SkDEBUGFAIL("Should not call in GPU-less build");
823 return NULL;
824#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000825 }
mtklein36352bf2015-03-25 18:17:31 -0700826 bool requiresFragmentPosition() const override { return true; }
827 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000828 if (other.type() != kPoint_LightType) {
829 return false;
830 }
831 const SkPointLight& o = static_cast<const SkPointLight&>(other);
832 return INHERITED::isEqual(other) &&
833 fLocation == o.fLocation;
834 }
mtklein36352bf2015-03-25 18:17:31 -0700835 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000836 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
837 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000838 // Use X scale and Y scale on Z and average the result
839 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
840 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700841 SkPoint3 location = SkPoint3::Make(location2.fX,
842 location2.fY,
843 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000844 return new SkPointLight(location, color());
845 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000846
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000847 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000848 fLocation = readPoint3(buffer);
849 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000850
851protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000852 SkPointLight(const SkPoint3& location, const SkPoint3& color)
853 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700854 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000855 writePoint3(fLocation, buffer);
856 }
857
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000858private:
djsollen@google.com08337772012-06-26 14:33:13 +0000859 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000860 SkPoint3 fLocation;
861};
862
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000863///////////////////////////////////////////////////////////////////////////////
864
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000865class SkSpotLight : public SkLight {
866public:
senorblancod0d37ca2015-04-02 04:54:56 -0700867 SkSpotLight(const SkPoint3& location,
868 const SkPoint3& target,
869 SkScalar specularExponent,
870 SkScalar cutoffAngle,
871 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000872 : INHERITED(color),
873 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000874 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000875 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000876 {
877 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700878 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000879 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000880 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000881 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
882 fConeScale = SkScalarInvert(antiAliasThreshold);
883 }
djsollen@google.com08337772012-06-26 14:33:13 +0000884
mtklein36352bf2015-03-25 18:17:31 -0700885 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000886 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
887 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000888 // Use X scale and Y scale on Z and average the result
889 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
890 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700891 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
892 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000893 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
894 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000895 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
896 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700897 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
898 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000899 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700900 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700901 return new SkSpotLight(location,
902 target,
903 fSpecularExponent,
904 fCosOuterConeAngle,
905 fCosInnerConeAngle,
906 fConeScale,
907 s,
908 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000909 }
910
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000911 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700912 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
913 fLocation.fY - SkIntToScalar(y),
914 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
915 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700916 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000917 return direction;
918 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000919 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000920 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700921 SkScalar scale = 0;
922 if (cosAngle >= fCosOuterConeAngle) {
923 scale = SkScalarPow(cosAngle, fSpecularExponent);
924 if (cosAngle < fCosInnerConeAngle) {
925 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
926 scale *= fConeScale;
927 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000928 }
robertphillips3d32d762015-07-13 13:16:44 -0700929 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000930 }
mtklein36352bf2015-03-25 18:17:31 -0700931 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000932#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000933 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000934#else
935 SkDEBUGFAIL("Should not call in GPU-less build");
936 return NULL;
937#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000938 }
mtklein36352bf2015-03-25 18:17:31 -0700939 bool requiresFragmentPosition() const override { return true; }
940 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000941 const SkPoint3& location() const { return fLocation; }
942 const SkPoint3& target() const { return fTarget; }
943 SkScalar specularExponent() const { return fSpecularExponent; }
944 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
945 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
946 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000947 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000948
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000949 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000950 fLocation = readPoint3(buffer);
951 fTarget = readPoint3(buffer);
952 fSpecularExponent = buffer.readScalar();
953 fCosOuterConeAngle = buffer.readScalar();
954 fCosInnerConeAngle = buffer.readScalar();
955 fConeScale = buffer.readScalar();
956 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000957 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
958 SkScalarIsFinite(fCosOuterConeAngle) &&
959 SkScalarIsFinite(fCosInnerConeAngle) &&
960 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000961 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000962protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700963 SkSpotLight(const SkPoint3& location,
964 const SkPoint3& target,
965 SkScalar specularExponent,
966 SkScalar cosOuterConeAngle,
967 SkScalar cosInnerConeAngle,
968 SkScalar coneScale,
969 const SkPoint3& s,
970 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000971 : INHERITED(color),
972 fLocation(location),
973 fTarget(target),
974 fSpecularExponent(specularExponent),
975 fCosOuterConeAngle(cosOuterConeAngle),
976 fCosInnerConeAngle(cosInnerConeAngle),
977 fConeScale(coneScale),
978 fS(s)
979 {
980 }
mtklein36352bf2015-03-25 18:17:31 -0700981 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000982 writePoint3(fLocation, buffer);
983 writePoint3(fTarget, buffer);
984 buffer.writeScalar(fSpecularExponent);
985 buffer.writeScalar(fCosOuterConeAngle);
986 buffer.writeScalar(fCosInnerConeAngle);
987 buffer.writeScalar(fConeScale);
988 writePoint3(fS, buffer);
989 }
990
mtklein36352bf2015-03-25 18:17:31 -0700991 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000992 if (other.type() != kSpot_LightType) {
993 return false;
994 }
995
996 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
997 return INHERITED::isEqual(other) &&
998 fLocation == o.fLocation &&
999 fTarget == o.fTarget &&
1000 fSpecularExponent == o.fSpecularExponent &&
1001 fCosOuterConeAngle == o.fCosOuterConeAngle;
1002 }
1003
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001004private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001005 static const SkScalar kSpecularExponentMin;
1006 static const SkScalar kSpecularExponentMax;
1007
djsollen@google.com08337772012-06-26 14:33:13 +00001008 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001009 SkPoint3 fLocation;
1010 SkPoint3 fTarget;
1011 SkScalar fSpecularExponent;
1012 SkScalar fCosOuterConeAngle;
1013 SkScalar fCosInnerConeAngle;
1014 SkScalar fConeScale;
1015 SkPoint3 fS;
1016};
1017
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001018// According to the spec, the specular term should be in the range [1, 128] :
1019// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001020const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1021const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001022
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001023///////////////////////////////////////////////////////////////////////////////
1024
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001025void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001026 // Write type first, then baseclass, then subclass.
1027 buffer.writeInt(this->type());
1028 writePoint3(fColor, buffer);
1029 this->onFlattenLight(buffer);
1030}
1031
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001032/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001033 // Read type first.
1034 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
1035 switch (type) {
1036 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1037 // then subclass, same order as flattenLight.
1038 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1039 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1040 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1041 default:
1042 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001043 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001044 return NULL;
1045 }
1046}
1047///////////////////////////////////////////////////////////////////////////////
1048
senorblanco9ea3d572014-07-08 09:16:22 -07001049SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001050 SkImageFilter* input, const CropRect* cropRect)
1051 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001052 , fLight(SkRef(light))
1053 , fSurfaceScale(surfaceScale / 255)
1054{}
1055
1056SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1057 SkColor lightColor,
1058 SkScalar surfaceScale,
1059 SkScalar kd,
1060 SkImageFilter* input,
1061 const CropRect* cropRect) {
1062 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1063 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001064}
1065
reed9fa60da2014-08-21 07:59:51 -07001066SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1067 SkColor lightColor,
1068 SkScalar surfaceScale,
1069 SkScalar kd,
1070 SkImageFilter* input,
1071 const CropRect* cropRect) {
1072 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1073 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001074}
1075
reed9fa60da2014-08-21 07:59:51 -07001076SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1077 const SkPoint3& target,
1078 SkScalar specularExponent,
1079 SkScalar cutoffAngle,
1080 SkColor lightColor,
1081 SkScalar surfaceScale,
1082 SkScalar kd,
1083 SkImageFilter* input,
1084 const CropRect* cropRect) {
1085 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1086 cutoffAngle, lightColor)));
1087 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001088}
1089
reed9fa60da2014-08-21 07:59:51 -07001090SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1091 SkColor lightColor,
1092 SkScalar surfaceScale,
1093 SkScalar ks,
1094 SkScalar shine,
1095 SkImageFilter* input,
1096 const CropRect* cropRect) {
1097 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1098 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001099}
1100
reed9fa60da2014-08-21 07:59:51 -07001101SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1102 SkColor lightColor,
1103 SkScalar surfaceScale,
1104 SkScalar ks,
1105 SkScalar shine,
1106 SkImageFilter* input,
1107 const CropRect* cropRect) {
1108 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1109 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001110}
1111
reed9fa60da2014-08-21 07:59:51 -07001112SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1113 const SkPoint3& target,
1114 SkScalar specularExponent,
1115 SkScalar cutoffAngle,
1116 SkColor lightColor,
1117 SkScalar surfaceScale,
1118 SkScalar ks,
1119 SkScalar shine,
1120 SkImageFilter* input,
1121 const CropRect* cropRect) {
1122 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1123 cutoffAngle, lightColor)));
1124 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001125}
1126
reed9fa60da2014-08-21 07:59:51 -07001127SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001128
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001129void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001130 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001131 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001132 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001133}
1134
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001135///////////////////////////////////////////////////////////////////////////////
1136
reed9fa60da2014-08-21 07:59:51 -07001137SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001138 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001139 if (NULL == light) {
1140 return NULL;
1141 }
1142 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1143 return NULL;
1144 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001145 // According to the spec, kd can be any non-negative number :
1146 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001147 if (kd < 0) {
1148 return NULL;
1149 }
senorblanco24e06d52015-03-18 12:11:33 -07001150 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001151}
1152
senorblancod0d37ca2015-04-02 04:54:56 -07001153SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1154 SkScalar surfaceScale,
1155 SkScalar kd,
1156 SkImageFilter* input,
1157 const CropRect* cropRect)
1158 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001159 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001160{
1161}
1162
reed9fa60da2014-08-21 07:59:51 -07001163SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1164 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1165 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1166 SkScalar surfaceScale = buffer.readScalar();
1167 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001168 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001169}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001171void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001172 this->INHERITED::flatten(buffer);
1173 buffer.writeScalar(fKD);
1174}
1175
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001176bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1177 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001178 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001179 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001180 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001181 SkImageFilter* input = getInput(0);
1182 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001183 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001184 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001185 return false;
1186 }
1187
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001188 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001189 return false;
1190 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001191 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001192 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001193 return false;
1194 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001195
1196 if (bounds.width() < 2 || bounds.height() < 2) {
1197 return false;
1198 }
1199
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001200 SkAutoLockPixels alp(src);
1201 if (!src.getPixels()) {
1202 return false;
1203 }
1204
reed84825042014-09-02 12:50:45 -07001205 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001206 return false;
1207 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001208
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001209 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001210
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001211 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001212 offset->fX = bounds.left();
1213 offset->fY = bounds.top();
1214 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001215 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001216 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001217 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1218 transformedLight,
1219 src,
1220 dst,
1221 surfaceScale(),
1222 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001223 break;
1224 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001225 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1226 transformedLight,
1227 src,
1228 dst,
1229 surfaceScale(),
1230 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001231 break;
1232 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001233 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1234 transformedLight,
1235 src,
1236 dst,
1237 surfaceScale(),
1238 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001239 break;
1240 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001241
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001242 return true;
1243}
1244
robertphillipsf3f5bad2014-12-19 13:49:15 -08001245#ifndef SK_IGNORE_TO_STRING
1246void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1247 str->appendf("SkDiffuseLightingImageFilter: (");
1248 str->appendf("kD: %f\n", fKD);
1249 str->append(")");
1250}
1251#endif
1252
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001253#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001254GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001255 GrProcessorDataManager* procDataManager,
1256 GrTexture* texture,
1257 const SkMatrix& matrix,
1258 const SkIRect&,
1259 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001260) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001261 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1262 return GrDiffuseLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1263 this->kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001264}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001265#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001266
1267///////////////////////////////////////////////////////////////////////////////
1268
reed9fa60da2014-08-21 07:59:51 -07001269SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001270 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001271 if (NULL == light) {
1272 return NULL;
1273 }
1274 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1275 return NULL;
1276 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001277 // According to the spec, ks can be any non-negative number :
1278 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001279 if (ks < 0) {
1280 return NULL;
1281 }
1282 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001283 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001284}
1285
senorblancod0d37ca2015-04-02 04:54:56 -07001286SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1287 SkScalar surfaceScale,
1288 SkScalar ks,
1289 SkScalar shininess,
1290 SkImageFilter* input,
1291 const CropRect* cropRect)
1292 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001293 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001294 fShininess(shininess)
1295{
1296}
1297
reed9fa60da2014-08-21 07:59:51 -07001298SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1299 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1300 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1301 SkScalar surfaceScale = buffer.readScalar();
1302 SkScalar ks = buffer.readScalar();
1303 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001304 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001305}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001306
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001307void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001308 this->INHERITED::flatten(buffer);
1309 buffer.writeScalar(fKS);
1310 buffer.writeScalar(fShininess);
1311}
1312
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001313bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1314 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001315 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001316 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001317 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001318 SkImageFilter* input = getInput(0);
1319 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001320 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001321 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001322 return false;
1323 }
1324
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001325 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001326 return false;
1327 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001328
1329 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001330 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001331 return false;
1332 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001333
1334 if (bounds.width() < 2 || bounds.height() < 2) {
1335 return false;
1336 }
1337
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001338 SkAutoLockPixels alp(src);
1339 if (!src.getPixels()) {
1340 return false;
1341 }
1342
reed84825042014-09-02 12:50:45 -07001343 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001344 return false;
1345 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001346
1347 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001348 offset->fX = bounds.left();
1349 offset->fY = bounds.top();
1350 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001351 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001352 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001353 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001354 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1355 transformedLight,
1356 src,
1357 dst,
1358 surfaceScale(),
1359 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001360 break;
1361 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001362 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1363 transformedLight,
1364 src,
1365 dst,
1366 surfaceScale(),
1367 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001368 break;
1369 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001370 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1371 transformedLight,
1372 src,
1373 dst,
1374 surfaceScale(),
1375 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001376 break;
1377 }
1378 return true;
1379}
1380
robertphillipsf3f5bad2014-12-19 13:49:15 -08001381#ifndef SK_IGNORE_TO_STRING
1382void SkSpecularLightingImageFilter::toString(SkString* str) const {
1383 str->appendf("SkSpecularLightingImageFilter: (");
1384 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1385 str->append(")");
1386}
1387#endif
1388
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001389#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001390GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001391 GrProcessorDataManager* procDataManager,
1392 GrTexture* texture,
1393 const SkMatrix& matrix,
1394 const SkIRect&,
1395 BoundaryMode boundaryMode) const {
1396 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1397 return GrSpecularLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1398 this->ks(), this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001399}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001400#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001401
1402///////////////////////////////////////////////////////////////////////////////
1403
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001404#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001405
1406namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001407SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001408 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1409 SkScalarToFloat(random->nextSScalar1()),
1410 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001411}
1412
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001413SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001414 int type = random->nextULessThan(3);
1415 switch (type) {
1416 case 0: {
1417 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1418 }
1419 case 1: {
1420 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1421 }
1422 case 2: {
1423 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1424 random_point3(random),
1425 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001426 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001427 random->nextU()));
1428 }
1429 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001430 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001431 return NULL;
1432 }
1433}
1434
senorblancod0d37ca2015-04-02 04:54:56 -07001435SkString emitNormalFunc(BoundaryMode mode,
1436 const char* pointToNormalName,
1437 const char* sobelFuncName) {
1438 SkString result;
1439 switch (mode) {
1440 case kTopLeft_BoundaryMode:
1441 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1442 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1443 "\t surfaceScale);\n",
1444 pointToNormalName, sobelFuncName, gTwoThirds,
1445 sobelFuncName, gTwoThirds);
1446 break;
1447 case kTop_BoundaryMode:
1448 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1449 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1450 "\t surfaceScale);\n",
1451 pointToNormalName, sobelFuncName, gOneThird,
1452 sobelFuncName, gOneHalf);
1453 break;
1454 case kTopRight_BoundaryMode:
1455 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1456 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1457 "\t surfaceScale);\n",
1458 pointToNormalName, sobelFuncName, gTwoThirds,
1459 sobelFuncName, gTwoThirds);
1460 break;
1461 case kLeft_BoundaryMode:
1462 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1463 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1464 "\t surfaceScale);\n",
1465 pointToNormalName, sobelFuncName, gOneHalf,
1466 sobelFuncName, gOneThird);
1467 break;
1468 case kInterior_BoundaryMode:
1469 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1470 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1471 "\t surfaceScale);\n",
1472 pointToNormalName, sobelFuncName, gOneQuarter,
1473 sobelFuncName, gOneQuarter);
1474 break;
1475 case kRight_BoundaryMode:
1476 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1477 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1478 "\t surfaceScale);\n",
1479 pointToNormalName, sobelFuncName, gOneHalf,
1480 sobelFuncName, gOneThird);
1481 break;
1482 case kBottomLeft_BoundaryMode:
1483 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1484 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1485 "\t surfaceScale);\n",
1486 pointToNormalName, sobelFuncName, gTwoThirds,
1487 sobelFuncName, gTwoThirds);
1488 break;
1489 case kBottom_BoundaryMode:
1490 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1491 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1492 "\t surfaceScale);\n",
1493 pointToNormalName, sobelFuncName, gOneThird,
1494 sobelFuncName, gOneHalf);
1495 break;
1496 case kBottomRight_BoundaryMode:
1497 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1498 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1499 "\t surfaceScale);\n",
1500 pointToNormalName, sobelFuncName, gTwoThirds,
1501 sobelFuncName, gTwoThirds);
1502 break;
1503 default:
1504 SkASSERT(false);
1505 break;
1506 }
1507 return result;
1508}
1509
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001510}
1511
joshualittb0a8a372014-09-23 09:50:21 -07001512class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001513public:
joshualitteb2a6762014-12-04 11:35:33 -08001514 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001515 virtual ~GrGLLightingEffect();
1516
senorblancod0d37ca2015-04-02 04:54:56 -07001517 void emitCode(GrGLFPBuilder*,
1518 const GrFragmentProcessor&,
1519 const char* outputColor,
1520 const char* inputColor,
1521 const TransformedCoordsArray&,
1522 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001523
jvanverthcfc18862015-04-28 08:48:20 -07001524 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001525
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001526 /**
1527 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1528 */
mtklein36352bf2015-03-25 18:17:31 -07001529 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001530
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001531protected:
joshualitt15988992014-10-09 15:04:05 -07001532 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001534private:
joshualittb0a8a372014-09-23 09:50:21 -07001535 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001536
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001537 UniformHandle fImageIncrementUni;
1538 UniformHandle fSurfaceScaleUni;
1539 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001540 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001541};
1542
1543///////////////////////////////////////////////////////////////////////////////
1544
1545class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1546public:
joshualitteb2a6762014-12-04 11:35:33 -08001547 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001548 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1549 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001550
1551private:
1552 typedef GrGLLightingEffect INHERITED;
1553
bsalomon@google.com032b2212012-07-16 13:36:18 +00001554 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001555};
1556
1557///////////////////////////////////////////////////////////////////////////////
1558
1559class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1560public:
joshualitteb2a6762014-12-04 11:35:33 -08001561 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001562 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1563 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001564
1565private:
1566 typedef GrGLLightingEffect INHERITED;
1567
bsalomon@google.com032b2212012-07-16 13:36:18 +00001568 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001569 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001570};
1571
1572///////////////////////////////////////////////////////////////////////////////
1573
joshualitt5f10b5c2015-07-09 10:24:35 -07001574GrLightingEffect::GrLightingEffect(GrProcessorDataManager* procDataManager,
1575 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001576 const SkLight* light,
1577 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001578 const SkMatrix& matrix,
1579 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001580 : INHERITED(procDataManager, texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001581 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001582 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001583 , fFilterMatrix(matrix)
1584 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001585 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001586 if (light->requiresFragmentPosition()) {
1587 this->setWillReadFragmentPosition();
1588 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001589}
1590
1591GrLightingEffect::~GrLightingEffect() {
1592 fLight->unref();
1593}
1594
bsalomon0e08fc12014-10-15 08:19:04 -07001595bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001596 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001597 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001598 fSurfaceScale == s.fSurfaceScale &&
1599 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001600}
1601
1602///////////////////////////////////////////////////////////////////////////////
1603
joshualitt5f10b5c2015-07-09 10:24:35 -07001604GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrProcessorDataManager* procDataManager,
1605 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001606 const SkLight* light,
1607 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001608 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001609 SkScalar kd,
1610 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001611 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001612 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001613}
1614
bsalomon0e08fc12014-10-15 08:19:04 -07001615bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001616 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001617 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001618 this->kd() == s.kd();
1619}
1620
jvanverthcfc18862015-04-28 08:48:20 -07001621void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001622 GrProcessorKeyBuilder* b) const {
1623 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1624}
1625
1626GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1627 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1628}
1629
joshualittb0a8a372014-09-23 09:50:21 -07001630GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001631
joshualitt0067ff52015-07-08 14:26:19 -07001632GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
1633 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1634 SkScalar kd = d->fRandom->nextUScalar1();
1635 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001636 SkMatrix matrix;
1637 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001638 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001639 }
joshualitt0067ff52015-07-08 14:26:19 -07001640 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001641 return GrDiffuseLightingEffect::Create(d->fProcDataManager,
1642 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001643 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001644}
1645
1646
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001647///////////////////////////////////////////////////////////////////////////////
1648
joshualitteb2a6762014-12-04 11:35:33 -08001649GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001650 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001651 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001652 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001653}
1654
1655GrGLLightingEffect::~GrGLLightingEffect() {
1656 delete fLight;
1657}
1658
joshualitt15988992014-10-09 15:04:05 -07001659void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001660 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001661 const char* outputColor,
1662 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001663 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001664 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001665 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001666 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001667 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001668 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001669 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001670 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001671 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001672 SkString lightFunc;
1673 this->emitLightFunc(builder, &lightFunc);
1674 static const GrGLShaderVar gSobelArgs[] = {
1675 GrGLShaderVar("a", kFloat_GrSLType),
1676 GrGLShaderVar("b", kFloat_GrSLType),
1677 GrGLShaderVar("c", kFloat_GrSLType),
1678 GrGLShaderVar("d", kFloat_GrSLType),
1679 GrGLShaderVar("e", kFloat_GrSLType),
1680 GrGLShaderVar("f", kFloat_GrSLType),
1681 GrGLShaderVar("scale", kFloat_GrSLType),
1682 };
1683 SkString sobelFuncName;
egdaniel29bee0f2015-04-29 11:54:42 -07001684 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001685 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1686
1687 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001688 "sobel",
1689 SK_ARRAY_COUNT(gSobelArgs),
1690 gSobelArgs,
1691 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1692 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001693 static const GrGLShaderVar gPointToNormalArgs[] = {
1694 GrGLShaderVar("x", kFloat_GrSLType),
1695 GrGLShaderVar("y", kFloat_GrSLType),
1696 GrGLShaderVar("scale", kFloat_GrSLType),
1697 };
1698 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001699 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001700 "pointToNormal",
1701 SK_ARRAY_COUNT(gPointToNormalArgs),
1702 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001703 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001704 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001705
1706 static const GrGLShaderVar gInteriorNormalArgs[] = {
1707 GrGLShaderVar("m", kFloat_GrSLType, 9),
1708 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1709 };
senorblancod0d37ca2015-04-02 04:54:56 -07001710 SkString normalBody = emitNormalFunc(fBoundaryMode,
1711 pointToNormalName.c_str(),
1712 sobelFuncName.c_str());
1713 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001714 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001715 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001716 SK_ARRAY_COUNT(gInteriorNormalArgs),
1717 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001718 normalBody.c_str(),
1719 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001720
joshualitt30ba4362014-08-21 20:18:45 -07001721 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1722 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001723
1724 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1725 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1726
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001727 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001728 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001729 for (int dx = -1; dx <= 1; dx++) {
1730 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001731 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001732 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1733 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1734 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001735 }
1736 }
joshualitt30ba4362014-08-21 20:18:45 -07001737 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001738 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001739 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001740 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001741 fsBuilder->codeAppend(";\n");
1742 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
senorblancod0d37ca2015-04-02 04:54:56 -07001743 outputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001744 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001745 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001746 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001747 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001748 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001749}
1750
joshualittb0a8a372014-09-23 09:50:21 -07001751void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001752 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001753 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1754 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001755}
1756
kkinnunen7510b222014-07-30 00:04:16 -07001757void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001758 const GrProcessor& proc) {
1759 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001760 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001761 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001762 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1763 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001764 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001765 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001766}
1767
1768///////////////////////////////////////////////////////////////////////////////
1769
1770///////////////////////////////////////////////////////////////////////////////
1771
joshualitteb2a6762014-12-04 11:35:33 -08001772GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1773 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001774}
1775
joshualitt15988992014-10-09 15:04:05 -07001776void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001777 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001778 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001779 kFloat_GrSLType, kDefault_GrSLPrecision,
1780 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001781
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001782 static const GrGLShaderVar gLightArgs[] = {
1783 GrGLShaderVar("normal", kVec3f_GrSLType),
1784 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1785 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1786 };
1787 SkString lightBody;
1788 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1789 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001790 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1791 "light",
1792 SK_ARRAY_COUNT(gLightArgs),
1793 gLightArgs,
1794 lightBody.c_str(),
1795 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001796}
1797
kkinnunen7510b222014-07-30 00:04:16 -07001798void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001799 const GrProcessor& proc) {
1800 INHERITED::setData(pdman, proc);
1801 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001802 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001803}
1804
1805///////////////////////////////////////////////////////////////////////////////
1806
joshualitt5f10b5c2015-07-09 10:24:35 -07001807GrSpecularLightingEffect::GrSpecularLightingEffect(GrProcessorDataManager* procDataManager,
1808 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001809 const SkLight* light,
1810 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001811 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001812 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001813 SkScalar shininess,
1814 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001815 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001816 fKS(ks),
1817 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001818 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001819}
1820
bsalomon0e08fc12014-10-15 08:19:04 -07001821bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001822 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001823 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001824 this->ks() == s.ks() &&
1825 this->shininess() == s.shininess();
1826}
1827
jvanverthcfc18862015-04-28 08:48:20 -07001828void GrSpecularLightingEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001829 GrProcessorKeyBuilder* b) const {
1830 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1831}
1832
1833GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1834 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1835}
1836
joshualittb0a8a372014-09-23 09:50:21 -07001837GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001838
joshualitt0067ff52015-07-08 14:26:19 -07001839GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
1840 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1841 SkScalar ks = d->fRandom->nextUScalar1();
1842 SkScalar shininess = d->fRandom->nextUScalar1();
1843 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001844 SkMatrix matrix;
1845 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001846 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001847 }
joshualitt0067ff52015-07-08 14:26:19 -07001848 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001849 return GrSpecularLightingEffect::Create(d->fProcDataManager,
1850 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001851 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001852}
1853
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001854///////////////////////////////////////////////////////////////////////////////
1855
joshualitteb2a6762014-12-04 11:35:33 -08001856GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1857 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001858}
1859
joshualitt15988992014-10-09 15:04:05 -07001860void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001861 const char* ks;
1862 const char* shininess;
1863
joshualitt30ba4362014-08-21 20:18:45 -07001864 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001865 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001866 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001867 kFloat_GrSLType,
1868 kDefault_GrSLPrecision,
1869 "Shininess",
1870 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001871
1872 static const GrGLShaderVar gLightArgs[] = {
1873 GrGLShaderVar("normal", kVec3f_GrSLType),
1874 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1875 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1876 };
1877 SkString lightBody;
1878 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1879 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001880 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1881 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001882 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1883 "light",
1884 SK_ARRAY_COUNT(gLightArgs),
1885 gLightArgs,
1886 lightBody.c_str(),
1887 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001888}
1889
kkinnunen7510b222014-07-30 00:04:16 -07001890void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001891 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001892 INHERITED::setData(pdman, effect);
1893 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001894 pdman.set1f(fKSUni, spec.ks());
1895 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001896}
1897
1898///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001899void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001900 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001901 kVec3f_GrSLType, kDefault_GrSLPrecision,
1902 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001903}
1904
robertphillips3d32d762015-07-13 13:16:44 -07001905void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001906 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001907}
1908
robertphillips3d32d762015-07-13 13:16:44 -07001909void GrGLLight::setData(const GrGLProgramDataManager& pdman, const SkLight* light) const {
1910 setUniformPoint3(pdman, fColorUni,
1911 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001912}
1913
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001914///////////////////////////////////////////////////////////////////////////////
1915
kkinnunen7510b222014-07-30 00:04:16 -07001916void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001917 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001918 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001919 SkASSERT(light->type() == SkLight::kDistant_LightType);
1920 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001921 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001922}
1923
joshualitt15988992014-10-09 15:04:05 -07001924void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001925 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001926 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1927 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001928 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001929 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001930}
1931
1932///////////////////////////////////////////////////////////////////////////////
1933
kkinnunen7510b222014-07-30 00:04:16 -07001934void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001935 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001936 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001937 SkASSERT(light->type() == SkLight::kPoint_LightType);
1938 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001939 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001940}
1941
joshualitt15988992014-10-09 15:04:05 -07001942void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001943 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001944 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1945 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001946 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001947 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001948 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1949 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001950}
1951
1952///////////////////////////////////////////////////////////////////////////////
1953
kkinnunen7510b222014-07-30 00:04:16 -07001954void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001955 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001956 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001957 SkASSERT(light->type() == SkLight::kSpot_LightType);
1958 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001959 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1960 pdman.set1f(fExponentUni, spotLight->specularExponent());
1961 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1962 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1963 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1964 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001965}
1966
joshualitt15988992014-10-09 15:04:05 -07001967void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001968 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001969 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001970 kVec3f_GrSLType, kDefault_GrSLPrecision,
1971 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001972
egdaniel29bee0f2015-04-29 11:54:42 -07001973 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001974 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1975 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001976}
1977
joshualitt15988992014-10-09 15:04:05 -07001978void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001979 const char *surfaceToLight) {
1980
1981 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1982
1983 const char* exponent;
1984 const char* cosInner;
1985 const char* cosOuter;
1986 const char* coneScale;
1987 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001988 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001989 kFloat_GrSLType, kDefault_GrSLPrecision,
1990 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001991 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001992 kFloat_GrSLType, kDefault_GrSLPrecision,
1993 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001994 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001995 kFloat_GrSLType, kDefault_GrSLPrecision,
1996 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001997 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001998 kFloat_GrSLType, kDefault_GrSLPrecision,
1999 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07002000 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08002001 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002002
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002003 static const GrGLShaderVar gLightColorArgs[] = {
2004 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
2005 };
2006 SkString lightColorBody;
2007 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2008 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2009 lightColorBody.appendf("\t\treturn vec3(0);\n");
2010 lightColorBody.appendf("\t}\n");
2011 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2012 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2013 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2014 color, cosOuter, coneScale);
2015 lightColorBody.appendf("\t}\n");
2016 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07002017 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002018 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002019 "lightColor",
2020 SK_ARRAY_COUNT(gLightColorArgs),
2021 gLightColorArgs,
2022 lightColorBody.c_str(),
2023 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002024
joshualitt30ba4362014-08-21 20:18:45 -07002025 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002026}
2027
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002028#endif
2029
djsollen@google.com08337772012-06-26 14:33:13 +00002030SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2031 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2032 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002033SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END