blob: 60904c7f9911625762cdb46f49b8a957c33fa0c0 [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"
wangyix6af0c932015-07-22 10:21:17 -070023#include "gl/GrGLFragmentProcessor.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
bsalomoneae62002015-07-31 13:59:30 -0700385 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700386 if (!dst) {
387 return false;
388 }
389
390 // setup new clip
391 GrClip clip(dstRect);
392
393 offset->fX = bounds.left();
394 offset->fY = bounds.top();
395 SkMatrix matrix(ctx.ctm());
396 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
397 bounds.offset(-srcOffset);
398 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
399 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
400 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
401 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
402 SkRect interior = dstRect.makeInset(1, 1);
403 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
404 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
405 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
406 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700407
408 GrDrawContext* drawContext = context->drawContext();
409 if (!drawContext) {
410 return false;
411 }
412
413 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700414 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700415 this->drawRect(drawContext, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds);
416 this->drawRect(drawContext, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700417 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700418 this->drawRect(drawContext, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds);
419 this->drawRect(drawContext, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700420 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700421 this->drawRect(drawContext, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds);
422 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700423 bounds);
robertphillipsea461502015-05-26 11:38:03 -0700424 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
425 this->drawRect(drawContext, srcTexture, dst, matrix, clip, bottomRight,
426 kBottomRight_BoundaryMode, bounds);
senorblancod0d37ca2015-04-02 04:54:56 -0700427 WrapTexture(dst, bounds.width(), bounds.height(), result);
428 return true;
429}
430#endif
431
432class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000433public:
reed9fa60da2014-08-21 07:59:51 -0700434 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700435 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700436
robertphillipsf3f5bad2014-12-19 13:49:15 -0800437 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000438 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000439 SkScalar kd() const { return fKD; }
440
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000441protected:
reed9fa60da2014-08-21 07:59:51 -0700442 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700443 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700444 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700445 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
446 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000447#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700448 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700449 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000450#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000451
452private:
reed9fa60da2014-08-21 07:59:51 -0700453 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700454 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000455 SkScalar fKD;
456};
457
senorblancod0d37ca2015-04-02 04:54:56 -0700458class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000459public:
reed9fa60da2014-08-21 07:59:51 -0700460 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700461 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700462
robertphillipsf3f5bad2014-12-19 13:49:15 -0800463 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000464 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
465
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000466 SkScalar ks() const { return fKS; }
467 SkScalar shininess() const { return fShininess; }
468
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000469protected:
reed9fa60da2014-08-21 07:59:51 -0700470 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700471 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700472 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700473 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
474 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000475#if SK_SUPPORT_GPU
joshualitt5f10b5c2015-07-09 10:24:35 -0700476 GrFragmentProcessor* getFragmentProcessor(GrProcessorDataManager*, GrTexture*, const SkMatrix&,
senorblancod0d37ca2015-04-02 04:54:56 -0700477 const SkIRect& bounds, BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000478#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000479
480private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481 SkScalar fKS;
482 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700483 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700484 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000485};
486
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000487#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000488
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000489class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700491 GrLightingEffect(GrProcessorDataManager*, GrTexture* texture, const SkLight* light,
492 SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000493 virtual ~GrLightingEffect();
494
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000495 const SkLight* light() const { return fLight; }
496 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000497 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700498 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000499
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000500protected:
mtklein36352bf2015-03-25 18:17:31 -0700501 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000502
mtklein36352bf2015-03-25 18:17:31 -0700503 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700504 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800505 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700506 }
507
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000508private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000509 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510 const SkLight* fLight;
511 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000512 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700513 BoundaryMode fBoundaryMode;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000514};
515
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000516class GrDiffuseLightingEffect : public GrLightingEffect {
517public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700518 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
519 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700520 const SkLight* light,
521 SkScalar surfaceScale,
522 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700523 SkScalar kd,
524 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700525 return SkNEW_ARGS(GrDiffuseLightingEffect, (procDataManager,
526 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700527 light,
528 surfaceScale,
529 matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700530 kd,
531 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000532 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000533
mtklein36352bf2015-03-25 18:17:31 -0700534 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000535
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000536 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000537
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000538private:
wangyixb1daa862015-08-18 11:29:31 -0700539 GrGLFragmentProcessor* onCreateGLInstance() const override;
540
wangyix4b3050b2015-08-04 07:59:37 -0700541 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
542
mtklein36352bf2015-03-25 18:17:31 -0700543 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000544
joshualitt5f10b5c2015-07-09 10:24:35 -0700545 GrDiffuseLightingEffect(GrProcessorDataManager*,
546 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000547 const SkLight* light,
548 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000549 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700550 SkScalar kd,
551 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000552
joshualittb0a8a372014-09-23 09:50:21 -0700553 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000554 typedef GrLightingEffect INHERITED;
555 SkScalar fKD;
556};
557
558class GrSpecularLightingEffect : public GrLightingEffect {
559public:
joshualitt5f10b5c2015-07-09 10:24:35 -0700560 static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
561 GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700562 const SkLight* light,
563 SkScalar surfaceScale,
564 const SkMatrix& matrix,
565 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700566 SkScalar shininess,
567 BoundaryMode boundaryMode) {
joshualitt5f10b5c2015-07-09 10:24:35 -0700568 return SkNEW_ARGS(GrSpecularLightingEffect, (procDataManager,
569 texture,
bsalomon55fad7a2014-07-08 07:34:20 -0700570 light,
571 surfaceScale,
572 matrix,
573 ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700574 shininess,
575 boundaryMode));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000576 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000577
mtklein36352bf2015-03-25 18:17:31 -0700578 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000579
wangyixb1daa862015-08-18 11:29:31 -0700580 GrGLFragmentProcessor* onCreateGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800581
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000582 SkScalar ks() const { return fKS; }
583 SkScalar shininess() const { return fShininess; }
584
585private:
wangyix4b3050b2015-08-04 07:59:37 -0700586 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
587
mtklein36352bf2015-03-25 18:17:31 -0700588 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000589
joshualitt5f10b5c2015-07-09 10:24:35 -0700590 GrSpecularLightingEffect(GrProcessorDataManager*,
591 GrTexture* texture,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000592 const SkLight* light,
593 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000594 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000595 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700596 SkScalar shininess,
597 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000598
joshualittb0a8a372014-09-23 09:50:21 -0700599 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000600 typedef GrLightingEffect INHERITED;
601 SkScalar fKS;
602 SkScalar fShininess;
603};
604
605///////////////////////////////////////////////////////////////////////////////
606
607class GrGLLight {
608public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000609 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000610
611 /**
612 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
613 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
614 */
joshualitt15988992014-10-09 15:04:05 -0700615 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000616
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000617 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000618 * These two functions are called from GrGLLightingEffect's emitCode() function.
619 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
620 * the light. The expression will be used in the FS. emitLightColor writes an expression into
621 * the FS that is the color of the light. Either function may add functions and/or uniforms to
622 * the FS. The default of emitLightColor appends the name of the constant light color uniform
623 * and so this function only needs to be overridden if the light color varies spatially.
624 */
joshualitt15988992014-10-09 15:04:05 -0700625 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
626 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000627
628 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
629 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700630 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000631 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000632
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000633protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000634 /**
635 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
636 * function.
637 */
638 UniformHandle lightColorUni() const { return fColorUni; }
639
640private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000641 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000642
643 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000644};
645
646///////////////////////////////////////////////////////////////////////////////
647
648class GrGLDistantLight : public GrGLLight {
649public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000650 virtual ~GrGLDistantLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700651 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700652 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000653
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000654private:
655 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000656 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000657};
658
659///////////////////////////////////////////////////////////////////////////////
660
661class GrGLPointLight : public GrGLLight {
662public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000663 virtual ~GrGLPointLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700664 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700665 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000666
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000667private:
668 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000669 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000670};
671
672///////////////////////////////////////////////////////////////////////////////
673
674class GrGLSpotLight : public GrGLLight {
675public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000676 virtual ~GrGLSpotLight() {}
senorblancod0d37ca2015-04-02 04:54:56 -0700677 void setData(const GrGLProgramDataManager&, const SkLight* light) const override;
mtklein36352bf2015-03-25 18:17:31 -0700678 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
679 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000680
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000681private:
682 typedef GrGLLight INHERITED;
683
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000684 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000685 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000686 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000687 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000688 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000689 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000690 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000691};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000692#else
693
694class GrGLLight;
695
696#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000697
698};
699
700///////////////////////////////////////////////////////////////////////////////
701
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000702class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703public:
mtklein2766c002015-06-26 11:45:03 -0700704
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000705
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000706 enum LightType {
707 kDistant_LightType,
708 kPoint_LightType,
709 kSpot_LightType,
710 };
711 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000712 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000713 virtual GrGLLight* createGLLight() const = 0;
714 virtual bool isEqual(const SkLight& other) const {
715 return fColor == other.fColor;
716 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000717 // Called to know whether the generated GrGLLight will require access to the fragment position.
718 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000719 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000720
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000721 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000722 void flattenLight(SkWriteBuffer& buffer) const;
723 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000724
djsollen@google.com08337772012-06-26 14:33:13 +0000725protected:
robertphillips3d32d762015-07-13 13:16:44 -0700726 SkLight(SkColor color) {
727 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
728 SkIntToScalar(SkColorGetG(color)),
729 SkIntToScalar(SkColorGetB(color)));
730 }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000731 SkLight(const SkPoint3& color)
732 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000733 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 fColor = readPoint3(buffer);
735 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000736
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000737 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000738
djsollen@google.com08337772012-06-26 14:33:13 +0000739
740private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000741 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000742 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743};
744
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000745///////////////////////////////////////////////////////////////////////////////
746
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000747class SkDistantLight : public SkLight {
748public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000749 SkDistantLight(const SkPoint3& direction, SkColor color)
750 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000751 }
djsollen@google.com08337772012-06-26 14:33:13 +0000752
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000753 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
754 return fDirection;
755 };
robertphillips3d32d762015-07-13 13:16:44 -0700756 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700757 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000758 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700759 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000760#if SK_SUPPORT_GPU
761 return SkNEW(GrGLDistantLight);
762#else
763 SkDEBUGFAIL("Should not call in GPU-less build");
764 return NULL;
765#endif
766 }
mtklein36352bf2015-03-25 18:17:31 -0700767 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000768
mtklein36352bf2015-03-25 18:17:31 -0700769 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000770 if (other.type() != kDistant_LightType) {
771 return false;
772 }
773
774 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
775 return INHERITED::isEqual(other) &&
776 fDirection == o.fDirection;
777 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000778
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000779 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000780 fDirection = readPoint3(buffer);
781 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000782
djsollen@google.com08337772012-06-26 14:33:13 +0000783protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000784 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
785 : INHERITED(color), fDirection(direction) {
786 }
mtklein36352bf2015-03-25 18:17:31 -0700787 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000788 return new SkDistantLight(direction(), color());
789 }
mtklein36352bf2015-03-25 18:17:31 -0700790 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000791 writePoint3(fDirection, buffer);
792 }
793
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000794private:
djsollen@google.com08337772012-06-26 14:33:13 +0000795 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000796 SkPoint3 fDirection;
797};
798
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000799///////////////////////////////////////////////////////////////////////////////
800
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000801class SkPointLight : public SkLight {
802public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000803 SkPointLight(const SkPoint3& location, SkColor color)
804 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000805
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000806 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700807 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
808 fLocation.fY - SkIntToScalar(y),
809 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
810 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700811 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000812 return direction;
813 };
robertphillips3d32d762015-07-13 13:16:44 -0700814 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700815 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000816 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700817 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000818#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000819 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000820#else
821 SkDEBUGFAIL("Should not call in GPU-less build");
822 return NULL;
823#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000824 }
mtklein36352bf2015-03-25 18:17:31 -0700825 bool requiresFragmentPosition() const override { return true; }
826 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000827 if (other.type() != kPoint_LightType) {
828 return false;
829 }
830 const SkPointLight& o = static_cast<const SkPointLight&>(other);
831 return INHERITED::isEqual(other) &&
832 fLocation == o.fLocation;
833 }
mtklein36352bf2015-03-25 18:17:31 -0700834 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000835 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
836 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000837 // Use X scale and Y scale on Z and average the result
838 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
839 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700840 SkPoint3 location = SkPoint3::Make(location2.fX,
841 location2.fY,
842 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000843 return new SkPointLight(location, color());
844 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000845
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000846 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000847 fLocation = readPoint3(buffer);
848 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000849
850protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000851 SkPointLight(const SkPoint3& location, const SkPoint3& color)
852 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700853 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000854 writePoint3(fLocation, buffer);
855 }
856
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000857private:
djsollen@google.com08337772012-06-26 14:33:13 +0000858 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000859 SkPoint3 fLocation;
860};
861
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000862///////////////////////////////////////////////////////////////////////////////
863
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000864class SkSpotLight : public SkLight {
865public:
senorblancod0d37ca2015-04-02 04:54:56 -0700866 SkSpotLight(const SkPoint3& location,
867 const SkPoint3& target,
868 SkScalar specularExponent,
869 SkScalar cutoffAngle,
870 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000871 : INHERITED(color),
872 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000873 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000874 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000875 {
876 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700877 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000878 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000879 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000880 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
881 fConeScale = SkScalarInvert(antiAliasThreshold);
882 }
djsollen@google.com08337772012-06-26 14:33:13 +0000883
mtklein36352bf2015-03-25 18:17:31 -0700884 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000885 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
886 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000887 // Use X scale and Y scale on Z and average the result
888 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
889 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700890 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
891 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000892 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
893 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000894 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
895 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700896 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
897 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000898 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700899 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700900 return new SkSpotLight(location,
901 target,
902 fSpecularExponent,
903 fCosOuterConeAngle,
904 fCosInnerConeAngle,
905 fConeScale,
906 s,
907 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000908 }
909
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700911 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
912 fLocation.fY - SkIntToScalar(y),
913 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
914 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700915 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000916 return direction;
917 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000918 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000919 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700920 SkScalar scale = 0;
921 if (cosAngle >= fCosOuterConeAngle) {
922 scale = SkScalarPow(cosAngle, fSpecularExponent);
923 if (cosAngle < fCosInnerConeAngle) {
924 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
925 scale *= fConeScale;
926 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000927 }
robertphillips3d32d762015-07-13 13:16:44 -0700928 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000929 }
mtklein36352bf2015-03-25 18:17:31 -0700930 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000931#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000932 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000933#else
934 SkDEBUGFAIL("Should not call in GPU-less build");
935 return NULL;
936#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000937 }
mtklein36352bf2015-03-25 18:17:31 -0700938 bool requiresFragmentPosition() const override { return true; }
939 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000940 const SkPoint3& location() const { return fLocation; }
941 const SkPoint3& target() const { return fTarget; }
942 SkScalar specularExponent() const { return fSpecularExponent; }
943 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
944 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
945 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000946 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000947
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000948 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000949 fLocation = readPoint3(buffer);
950 fTarget = readPoint3(buffer);
951 fSpecularExponent = buffer.readScalar();
952 fCosOuterConeAngle = buffer.readScalar();
953 fCosInnerConeAngle = buffer.readScalar();
954 fConeScale = buffer.readScalar();
955 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000956 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
957 SkScalarIsFinite(fCosOuterConeAngle) &&
958 SkScalarIsFinite(fCosInnerConeAngle) &&
959 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000960 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000961protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700962 SkSpotLight(const SkPoint3& location,
963 const SkPoint3& target,
964 SkScalar specularExponent,
965 SkScalar cosOuterConeAngle,
966 SkScalar cosInnerConeAngle,
967 SkScalar coneScale,
968 const SkPoint3& s,
969 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000970 : INHERITED(color),
971 fLocation(location),
972 fTarget(target),
973 fSpecularExponent(specularExponent),
974 fCosOuterConeAngle(cosOuterConeAngle),
975 fCosInnerConeAngle(cosInnerConeAngle),
976 fConeScale(coneScale),
977 fS(s)
978 {
979 }
mtklein36352bf2015-03-25 18:17:31 -0700980 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000981 writePoint3(fLocation, buffer);
982 writePoint3(fTarget, buffer);
983 buffer.writeScalar(fSpecularExponent);
984 buffer.writeScalar(fCosOuterConeAngle);
985 buffer.writeScalar(fCosInnerConeAngle);
986 buffer.writeScalar(fConeScale);
987 writePoint3(fS, buffer);
988 }
989
mtklein36352bf2015-03-25 18:17:31 -0700990 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000991 if (other.type() != kSpot_LightType) {
992 return false;
993 }
994
995 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
996 return INHERITED::isEqual(other) &&
997 fLocation == o.fLocation &&
998 fTarget == o.fTarget &&
999 fSpecularExponent == o.fSpecularExponent &&
1000 fCosOuterConeAngle == o.fCosOuterConeAngle;
1001 }
1002
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001003private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001004 static const SkScalar kSpecularExponentMin;
1005 static const SkScalar kSpecularExponentMax;
1006
djsollen@google.com08337772012-06-26 14:33:13 +00001007 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001008 SkPoint3 fLocation;
1009 SkPoint3 fTarget;
1010 SkScalar fSpecularExponent;
1011 SkScalar fCosOuterConeAngle;
1012 SkScalar fCosInnerConeAngle;
1013 SkScalar fConeScale;
1014 SkPoint3 fS;
1015};
1016
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001017// According to the spec, the specular term should be in the range [1, 128] :
1018// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001019const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1020const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00001021
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001022///////////////////////////////////////////////////////////////////////////////
1023
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001024void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001025 // Write type first, then baseclass, then subclass.
1026 buffer.writeInt(this->type());
1027 writePoint3(fColor, buffer);
1028 this->onFlattenLight(buffer);
1029}
1030
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001031/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001032 // Read type first.
1033 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
1034 switch (type) {
1035 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1036 // then subclass, same order as flattenLight.
1037 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
1038 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
1039 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
1040 default:
1041 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001042 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001043 return NULL;
1044 }
1045}
1046///////////////////////////////////////////////////////////////////////////////
1047
senorblanco9ea3d572014-07-08 09:16:22 -07001048SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001049 SkImageFilter* input, const CropRect* cropRect)
1050 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001051 , fLight(SkRef(light))
1052 , fSurfaceScale(surfaceScale / 255)
1053{}
1054
1055SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1056 SkColor lightColor,
1057 SkScalar surfaceScale,
1058 SkScalar kd,
1059 SkImageFilter* input,
1060 const CropRect* cropRect) {
1061 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1062 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001063}
1064
reed9fa60da2014-08-21 07:59:51 -07001065SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1066 SkColor lightColor,
1067 SkScalar surfaceScale,
1068 SkScalar kd,
1069 SkImageFilter* input,
1070 const CropRect* cropRect) {
1071 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1072 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001073}
1074
reed9fa60da2014-08-21 07:59:51 -07001075SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1076 const SkPoint3& target,
1077 SkScalar specularExponent,
1078 SkScalar cutoffAngle,
1079 SkColor lightColor,
1080 SkScalar surfaceScale,
1081 SkScalar kd,
1082 SkImageFilter* input,
1083 const CropRect* cropRect) {
1084 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1085 cutoffAngle, lightColor)));
1086 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001087}
1088
reed9fa60da2014-08-21 07:59:51 -07001089SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1090 SkColor lightColor,
1091 SkScalar surfaceScale,
1092 SkScalar ks,
1093 SkScalar shine,
1094 SkImageFilter* input,
1095 const CropRect* cropRect) {
1096 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
1097 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001098}
1099
reed9fa60da2014-08-21 07:59:51 -07001100SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1101 SkColor lightColor,
1102 SkScalar surfaceScale,
1103 SkScalar ks,
1104 SkScalar shine,
1105 SkImageFilter* input,
1106 const CropRect* cropRect) {
1107 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
1108 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001109}
1110
reed9fa60da2014-08-21 07:59:51 -07001111SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1112 const SkPoint3& target,
1113 SkScalar specularExponent,
1114 SkScalar cutoffAngle,
1115 SkColor lightColor,
1116 SkScalar surfaceScale,
1117 SkScalar ks,
1118 SkScalar shine,
1119 SkImageFilter* input,
1120 const CropRect* cropRect) {
1121 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
1122 cutoffAngle, lightColor)));
1123 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001124}
1125
reed9fa60da2014-08-21 07:59:51 -07001126SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001127
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001128void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001129 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001130 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001131 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001132}
1133
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001134///////////////////////////////////////////////////////////////////////////////
1135
reed9fa60da2014-08-21 07:59:51 -07001136SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001137 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001138 if (NULL == light) {
1139 return NULL;
1140 }
1141 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1142 return NULL;
1143 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001144 // According to the spec, kd can be any non-negative number :
1145 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001146 if (kd < 0) {
1147 return NULL;
1148 }
senorblanco24e06d52015-03-18 12:11:33 -07001149 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001150}
1151
senorblancod0d37ca2015-04-02 04:54:56 -07001152SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light,
1153 SkScalar surfaceScale,
1154 SkScalar kd,
1155 SkImageFilter* input,
1156 const CropRect* cropRect)
1157 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001158 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001159{
1160}
1161
reed9fa60da2014-08-21 07:59:51 -07001162SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1163 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1164 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1165 SkScalar surfaceScale = buffer.readScalar();
1166 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001167 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001168}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001169
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001170void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001171 this->INHERITED::flatten(buffer);
1172 buffer.writeScalar(fKD);
1173}
1174
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001175bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1176 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001177 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001178 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001179 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001180 SkImageFilter* input = getInput(0);
1181 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001182 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001183 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001184 return false;
1185 }
1186
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001187 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001188 return false;
1189 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001190 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001191 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001192 return false;
1193 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001194
1195 if (bounds.width() < 2 || bounds.height() < 2) {
1196 return false;
1197 }
1198
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001199 SkAutoLockPixels alp(src);
1200 if (!src.getPixels()) {
1201 return false;
1202 }
1203
reed84825042014-09-02 12:50:45 -07001204 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001205 return false;
1206 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001207
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001208 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001209
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001210 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001211 offset->fX = bounds.left();
1212 offset->fY = bounds.top();
1213 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001214 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001215 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001216 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1217 transformedLight,
1218 src,
1219 dst,
1220 surfaceScale(),
1221 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001222 break;
1223 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001224 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1225 transformedLight,
1226 src,
1227 dst,
1228 surfaceScale(),
1229 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001230 break;
1231 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001232 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1233 transformedLight,
1234 src,
1235 dst,
1236 surfaceScale(),
1237 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001238 break;
1239 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001240
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001241 return true;
1242}
1243
robertphillipsf3f5bad2014-12-19 13:49:15 -08001244#ifndef SK_IGNORE_TO_STRING
1245void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1246 str->appendf("SkDiffuseLightingImageFilter: (");
1247 str->appendf("kD: %f\n", fKD);
1248 str->append(")");
1249}
1250#endif
1251
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001252#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001253GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001254 GrProcessorDataManager* procDataManager,
1255 GrTexture* texture,
1256 const SkMatrix& matrix,
1257 const SkIRect&,
1258 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001259) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001260 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1261 return GrDiffuseLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1262 this->kd(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001263}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001264#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001265
1266///////////////////////////////////////////////////////////////////////////////
1267
reed9fa60da2014-08-21 07:59:51 -07001268SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001269 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001270 if (NULL == light) {
1271 return NULL;
1272 }
1273 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1274 return NULL;
1275 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001276 // According to the spec, ks can be any non-negative number :
1277 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001278 if (ks < 0) {
1279 return NULL;
1280 }
1281 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001282 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001283}
1284
senorblancod0d37ca2015-04-02 04:54:56 -07001285SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light,
1286 SkScalar surfaceScale,
1287 SkScalar ks,
1288 SkScalar shininess,
1289 SkImageFilter* input,
1290 const CropRect* cropRect)
1291 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001292 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001293 fShininess(shininess)
1294{
1295}
1296
reed9fa60da2014-08-21 07:59:51 -07001297SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1298 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1299 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1300 SkScalar surfaceScale = buffer.readScalar();
1301 SkScalar ks = buffer.readScalar();
1302 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001303 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001304}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001305
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001306void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001307 this->INHERITED::flatten(buffer);
1308 buffer.writeScalar(fKS);
1309 buffer.writeScalar(fShininess);
1310}
1311
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001312bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1313 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001314 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001315 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001316 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001317 SkImageFilter* input = getInput(0);
1318 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001319 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001320 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001321 return false;
1322 }
1323
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001324 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001325 return false;
1326 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001327
1328 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001329 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001330 return false;
1331 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001332
1333 if (bounds.width() < 2 || bounds.height() < 2) {
1334 return false;
1335 }
1336
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001337 SkAutoLockPixels alp(src);
1338 if (!src.getPixels()) {
1339 return false;
1340 }
1341
reed84825042014-09-02 12:50:45 -07001342 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001343 return false;
1344 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001345
1346 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001347 offset->fX = bounds.left();
1348 offset->fY = bounds.top();
1349 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001350 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001351 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001352 case SkLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001353 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1354 transformedLight,
1355 src,
1356 dst,
1357 surfaceScale(),
1358 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001359 break;
1360 case SkLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001361 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1362 transformedLight,
1363 src,
1364 dst,
1365 surfaceScale(),
1366 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001367 break;
1368 case SkLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001369 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1370 transformedLight,
1371 src,
1372 dst,
1373 surfaceScale(),
1374 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001375 break;
1376 }
1377 return true;
1378}
1379
robertphillipsf3f5bad2014-12-19 13:49:15 -08001380#ifndef SK_IGNORE_TO_STRING
1381void SkSpecularLightingImageFilter::toString(SkString* str) const {
1382 str->appendf("SkSpecularLightingImageFilter: (");
1383 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1384 str->append(")");
1385}
1386#endif
1387
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001388#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001389GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001390 GrProcessorDataManager* procDataManager,
1391 GrTexture* texture,
1392 const SkMatrix& matrix,
1393 const SkIRect&,
1394 BoundaryMode boundaryMode) const {
1395 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
1396 return GrSpecularLightingEffect::Create(procDataManager, texture, this->light(), scale, matrix,
1397 this->ks(), this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001398}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001399#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001400
1401///////////////////////////////////////////////////////////////////////////////
1402
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001403#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001404
1405namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001406SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001407 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1408 SkScalarToFloat(random->nextSScalar1()),
1409 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001410}
1411
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001412SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001413 int type = random->nextULessThan(3);
1414 switch (type) {
1415 case 0: {
1416 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1417 }
1418 case 1: {
1419 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1420 }
1421 case 2: {
1422 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1423 random_point3(random),
1424 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001425 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001426 random->nextU()));
1427 }
1428 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001429 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001430 return NULL;
1431 }
1432}
1433
senorblancod0d37ca2015-04-02 04:54:56 -07001434SkString emitNormalFunc(BoundaryMode mode,
1435 const char* pointToNormalName,
1436 const char* sobelFuncName) {
1437 SkString result;
1438 switch (mode) {
1439 case kTopLeft_BoundaryMode:
1440 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n"
1441 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1442 "\t surfaceScale);\n",
1443 pointToNormalName, sobelFuncName, gTwoThirds,
1444 sobelFuncName, gTwoThirds);
1445 break;
1446 case kTop_BoundaryMode:
1447 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1448 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1449 "\t surfaceScale);\n",
1450 pointToNormalName, sobelFuncName, gOneThird,
1451 sobelFuncName, gOneHalf);
1452 break;
1453 case kTopRight_BoundaryMode:
1454 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1455 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1456 "\t surfaceScale);\n",
1457 pointToNormalName, sobelFuncName, gTwoThirds,
1458 sobelFuncName, gTwoThirds);
1459 break;
1460 case kLeft_BoundaryMode:
1461 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1462 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1463 "\t surfaceScale);\n",
1464 pointToNormalName, sobelFuncName, gOneHalf,
1465 sobelFuncName, gOneThird);
1466 break;
1467 case kInterior_BoundaryMode:
1468 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1469 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1470 "\t surfaceScale);\n",
1471 pointToNormalName, sobelFuncName, gOneQuarter,
1472 sobelFuncName, gOneQuarter);
1473 break;
1474 case kRight_BoundaryMode:
1475 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1476 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1477 "\t surfaceScale);\n",
1478 pointToNormalName, sobelFuncName, gOneHalf,
1479 sobelFuncName, gOneThird);
1480 break;
1481 case kBottomLeft_BoundaryMode:
1482 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1483 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1484 "\t surfaceScale);\n",
1485 pointToNormalName, sobelFuncName, gTwoThirds,
1486 sobelFuncName, gTwoThirds);
1487 break;
1488 case kBottom_BoundaryMode:
1489 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1490 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1491 "\t surfaceScale);\n",
1492 pointToNormalName, sobelFuncName, gOneThird,
1493 sobelFuncName, gOneHalf);
1494 break;
1495 case kBottomRight_BoundaryMode:
1496 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1497 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1498 "\t surfaceScale);\n",
1499 pointToNormalName, sobelFuncName, gTwoThirds,
1500 sobelFuncName, gTwoThirds);
1501 break;
1502 default:
1503 SkASSERT(false);
1504 break;
1505 }
1506 return result;
1507}
1508
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001509}
1510
joshualittb0a8a372014-09-23 09:50:21 -07001511class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001512public:
joshualitteb2a6762014-12-04 11:35:33 -08001513 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001514 virtual ~GrGLLightingEffect();
1515
wangyix7c157a92015-07-22 15:08:53 -07001516 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001517
jvanverthcfc18862015-04-28 08:48:20 -07001518 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001519
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001520protected:
wangyixb1daa862015-08-18 11:29:31 -07001521 /**
1522 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1523 */
1524 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1525
joshualitt15988992014-10-09 15:04:05 -07001526 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001527
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001528private:
joshualittb0a8a372014-09-23 09:50:21 -07001529 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001530
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001531 UniformHandle fImageIncrementUni;
1532 UniformHandle fSurfaceScaleUni;
1533 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001534 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001535};
1536
1537///////////////////////////////////////////////////////////////////////////////
1538
1539class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1540public:
joshualitteb2a6762014-12-04 11:35:33 -08001541 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001542 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001543
1544protected:
1545 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001546
1547private:
1548 typedef GrGLLightingEffect INHERITED;
1549
bsalomon@google.com032b2212012-07-16 13:36:18 +00001550 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001551};
1552
1553///////////////////////////////////////////////////////////////////////////////
1554
1555class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1556public:
joshualitteb2a6762014-12-04 11:35:33 -08001557 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001558 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001559
1560protected:
1561 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001562
1563private:
1564 typedef GrGLLightingEffect INHERITED;
1565
bsalomon@google.com032b2212012-07-16 13:36:18 +00001566 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001567 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001568};
1569
1570///////////////////////////////////////////////////////////////////////////////
1571
joshualitt5f10b5c2015-07-09 10:24:35 -07001572GrLightingEffect::GrLightingEffect(GrProcessorDataManager* procDataManager,
1573 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001574 const SkLight* light,
1575 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001576 const SkMatrix& matrix,
1577 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001578 : INHERITED(procDataManager, texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001579 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001580 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001581 , fFilterMatrix(matrix)
1582 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001583 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001584 if (light->requiresFragmentPosition()) {
1585 this->setWillReadFragmentPosition();
1586 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001587}
1588
1589GrLightingEffect::~GrLightingEffect() {
1590 fLight->unref();
1591}
1592
bsalomon0e08fc12014-10-15 08:19:04 -07001593bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001594 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001595 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001596 fSurfaceScale == s.fSurfaceScale &&
1597 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001598}
1599
1600///////////////////////////////////////////////////////////////////////////////
1601
joshualitt5f10b5c2015-07-09 10:24:35 -07001602GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrProcessorDataManager* procDataManager,
1603 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001604 const SkLight* light,
1605 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001606 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001607 SkScalar kd,
1608 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001609 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001610 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001611}
1612
bsalomon0e08fc12014-10-15 08:19:04 -07001613bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001614 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001615 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001616 this->kd() == s.kd();
1617}
1618
wangyix4b3050b2015-08-04 07:59:37 -07001619void GrDiffuseLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001620 GrProcessorKeyBuilder* b) const {
1621 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1622}
1623
wangyixb1daa862015-08-18 11:29:31 -07001624GrGLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -08001625 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1626}
1627
joshualittb0a8a372014-09-23 09:50:21 -07001628GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001629
joshualitt0067ff52015-07-08 14:26:19 -07001630GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
1631 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1632 SkScalar kd = d->fRandom->nextUScalar1();
1633 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001634 SkMatrix matrix;
1635 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001636 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001637 }
joshualitt0067ff52015-07-08 14:26:19 -07001638 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001639 return GrDiffuseLightingEffect::Create(d->fProcDataManager,
1640 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001641 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001642}
1643
1644
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001645///////////////////////////////////////////////////////////////////////////////
1646
joshualitteb2a6762014-12-04 11:35:33 -08001647GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001648 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001649 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001650 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001651}
1652
1653GrGLLightingEffect::~GrGLLightingEffect() {
1654 delete fLight;
1655}
1656
wangyix7c157a92015-07-22 15:08:53 -07001657void GrGLLightingEffect::emitCode(EmitArgs& args) {
1658 fImageIncrementUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001659 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001660 "ImageIncrement");
wangyix7c157a92015-07-22 15:08:53 -07001661 fSurfaceScaleUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001662 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001663 "SurfaceScale");
wangyix7c157a92015-07-22 15:08:53 -07001664 fLight->emitLightColorUniform(args.fBuilder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001665 SkString lightFunc;
wangyix7c157a92015-07-22 15:08:53 -07001666 this->emitLightFunc(args.fBuilder, &lightFunc);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001667 static const GrGLShaderVar gSobelArgs[] = {
1668 GrGLShaderVar("a", kFloat_GrSLType),
1669 GrGLShaderVar("b", kFloat_GrSLType),
1670 GrGLShaderVar("c", kFloat_GrSLType),
1671 GrGLShaderVar("d", kFloat_GrSLType),
1672 GrGLShaderVar("e", kFloat_GrSLType),
1673 GrGLShaderVar("f", kFloat_GrSLType),
1674 GrGLShaderVar("scale", kFloat_GrSLType),
1675 };
1676 SkString sobelFuncName;
wangyix7c157a92015-07-22 15:08:53 -07001677 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1678 SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001679
1680 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001681 "sobel",
1682 SK_ARRAY_COUNT(gSobelArgs),
1683 gSobelArgs,
1684 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1685 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001686 static const GrGLShaderVar gPointToNormalArgs[] = {
1687 GrGLShaderVar("x", kFloat_GrSLType),
1688 GrGLShaderVar("y", kFloat_GrSLType),
1689 GrGLShaderVar("scale", kFloat_GrSLType),
1690 };
1691 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001692 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001693 "pointToNormal",
1694 SK_ARRAY_COUNT(gPointToNormalArgs),
1695 gPointToNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001696 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001697 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001698
1699 static const GrGLShaderVar gInteriorNormalArgs[] = {
1700 GrGLShaderVar("m", kFloat_GrSLType, 9),
1701 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1702 };
senorblancod0d37ca2015-04-02 04:54:56 -07001703 SkString normalBody = emitNormalFunc(fBoundaryMode,
1704 pointToNormalName.c_str(),
1705 sobelFuncName.c_str());
1706 SkString normalName;
joshualitt30ba4362014-08-21 20:18:45 -07001707 fsBuilder->emitFunction(kVec3f_GrSLType,
senorblancod0d37ca2015-04-02 04:54:56 -07001708 "normal",
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001709 SK_ARRAY_COUNT(gInteriorNormalArgs),
1710 gInteriorNormalArgs,
senorblancod0d37ca2015-04-02 04:54:56 -07001711 normalBody.c_str(),
1712 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001713
joshualitt30ba4362014-08-21 20:18:45 -07001714 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1715 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001716
wangyix7c157a92015-07-22 15:08:53 -07001717 const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni);
1718 const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001719
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001720 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001721 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001722 for (int dx = -1; dx <= 1; dx++) {
1723 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001724 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001725 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
wangyix7c157a92015-07-22 15:08:53 -07001726 fsBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001727 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001728 }
1729 }
joshualitt30ba4362014-08-21 20:18:45 -07001730 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001731 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001732 arg.appendf("%s * m[4]", surfScale);
wangyix7c157a92015-07-22 15:08:53 -07001733 fLight->emitSurfaceToLight(args.fBuilder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001734 fsBuilder->codeAppend(";\n");
1735 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
wangyix7c157a92015-07-22 15:08:53 -07001736 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
1737 fLight->emitLightColor(args.fBuilder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001738 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001739 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001740 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001741 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001742}
1743
joshualittb0a8a372014-09-23 09:50:21 -07001744void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001745 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001746 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1747 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001748}
1749
wangyixb1daa862015-08-18 11:29:31 -07001750void GrGLLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001751 const GrProcessor& proc) {
1752 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001753 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001754 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001755 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1756 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001757 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001758 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001759}
1760
1761///////////////////////////////////////////////////////////////////////////////
1762
1763///////////////////////////////////////////////////////////////////////////////
1764
joshualitteb2a6762014-12-04 11:35:33 -08001765GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1766 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001767}
1768
joshualitt15988992014-10-09 15:04:05 -07001769void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001770 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001771 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001772 kFloat_GrSLType, kDefault_GrSLPrecision,
1773 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001774
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001775 static const GrGLShaderVar gLightArgs[] = {
1776 GrGLShaderVar("normal", kVec3f_GrSLType),
1777 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1778 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1779 };
1780 SkString lightBody;
1781 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1782 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001783 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1784 "light",
1785 SK_ARRAY_COUNT(gLightArgs),
1786 gLightArgs,
1787 lightBody.c_str(),
1788 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001789}
1790
wangyixb1daa862015-08-18 11:29:31 -07001791void GrGLDiffuseLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001792 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001793 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001794 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001795 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001796}
1797
1798///////////////////////////////////////////////////////////////////////////////
1799
joshualitt5f10b5c2015-07-09 10:24:35 -07001800GrSpecularLightingEffect::GrSpecularLightingEffect(GrProcessorDataManager* procDataManager,
1801 GrTexture* texture,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001802 const SkLight* light,
1803 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001804 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001805 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001806 SkScalar shininess,
1807 BoundaryMode boundaryMode)
joshualitt5f10b5c2015-07-09 10:24:35 -07001808 : INHERITED(procDataManager, texture, light, surfaceScale, matrix, boundaryMode),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001809 fKS(ks),
1810 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001811 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001812}
1813
bsalomon0e08fc12014-10-15 08:19:04 -07001814bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001815 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001816 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001817 this->ks() == s.ks() &&
1818 this->shininess() == s.shininess();
1819}
1820
wangyix4b3050b2015-08-04 07:59:37 -07001821void GrSpecularLightingEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001822 GrProcessorKeyBuilder* b) const {
1823 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1824}
1825
wangyixb1daa862015-08-18 11:29:31 -07001826GrGLFragmentProcessor* GrSpecularLightingEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -08001827 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1828}
1829
joshualittb0a8a372014-09-23 09:50:21 -07001830GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001831
joshualitt0067ff52015-07-08 14:26:19 -07001832GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
1833 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1834 SkScalar ks = d->fRandom->nextUScalar1();
1835 SkScalar shininess = d->fRandom->nextUScalar1();
1836 SkAutoTUnref<SkLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001837 SkMatrix matrix;
1838 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001839 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001840 }
joshualitt0067ff52015-07-08 14:26:19 -07001841 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
joshualitt5f10b5c2015-07-09 10:24:35 -07001842 return GrSpecularLightingEffect::Create(d->fProcDataManager,
1843 d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001844 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001845}
1846
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001847///////////////////////////////////////////////////////////////////////////////
1848
joshualitteb2a6762014-12-04 11:35:33 -08001849GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1850 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001851}
1852
joshualitt15988992014-10-09 15:04:05 -07001853void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001854 const char* ks;
1855 const char* shininess;
1856
joshualitt30ba4362014-08-21 20:18:45 -07001857 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001858 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001859 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
senorblancod0d37ca2015-04-02 04:54:56 -07001860 kFloat_GrSLType,
1861 kDefault_GrSLPrecision,
1862 "Shininess",
1863 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001864
1865 static const GrGLShaderVar gLightArgs[] = {
1866 GrGLShaderVar("normal", kVec3f_GrSLType),
1867 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1868 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1869 };
1870 SkString lightBody;
1871 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1872 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001873 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1874 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001875 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1876 "light",
1877 SK_ARRAY_COUNT(gLightArgs),
1878 gLightArgs,
1879 lightBody.c_str(),
1880 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001881}
1882
wangyixb1daa862015-08-18 11:29:31 -07001883void GrGLSpecularLightingEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001884 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001885 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001886 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001887 pdman.set1f(fKSUni, spec.ks());
1888 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001889}
1890
1891///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001892void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001893 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001894 kVec3f_GrSLType, kDefault_GrSLPrecision,
1895 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001896}
1897
robertphillips3d32d762015-07-13 13:16:44 -07001898void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001899 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001900}
1901
robertphillips3d32d762015-07-13 13:16:44 -07001902void GrGLLight::setData(const GrGLProgramDataManager& pdman, const SkLight* light) const {
1903 setUniformPoint3(pdman, fColorUni,
1904 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001905}
1906
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001907///////////////////////////////////////////////////////////////////////////////
1908
kkinnunen7510b222014-07-30 00:04:16 -07001909void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001910 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001911 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001912 SkASSERT(light->type() == SkLight::kDistant_LightType);
1913 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001914 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001915}
1916
joshualitt15988992014-10-09 15:04:05 -07001917void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001918 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001919 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1920 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001921 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001922 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001923}
1924
1925///////////////////////////////////////////////////////////////////////////////
1926
kkinnunen7510b222014-07-30 00:04:16 -07001927void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001928 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001929 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001930 SkASSERT(light->type() == SkLight::kPoint_LightType);
1931 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001932 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001933}
1934
joshualitt15988992014-10-09 15:04:05 -07001935void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001936 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001937 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1938 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001939 "LightLocation", &loc);
egdaniel29bee0f2015-04-29 11:54:42 -07001940 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001941 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1942 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001943}
1944
1945///////////////////////////////////////////////////////////////////////////////
1946
kkinnunen7510b222014-07-30 00:04:16 -07001947void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001948 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001949 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001950 SkASSERT(light->type() == SkLight::kSpot_LightType);
1951 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001952 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1953 pdman.set1f(fExponentUni, spotLight->specularExponent());
1954 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1955 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1956 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1957 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001958}
1959
joshualitt15988992014-10-09 15:04:05 -07001960void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001961 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001962 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001963 kVec3f_GrSLType, kDefault_GrSLPrecision,
1964 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001965
egdaniel29bee0f2015-04-29 11:54:42 -07001966 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001967 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1968 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001969}
1970
joshualitt15988992014-10-09 15:04:05 -07001971void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001972 const char *surfaceToLight) {
1973
1974 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1975
1976 const char* exponent;
1977 const char* cosInner;
1978 const char* cosOuter;
1979 const char* coneScale;
1980 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001981 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001982 kFloat_GrSLType, kDefault_GrSLPrecision,
1983 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001984 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001985 kFloat_GrSLType, kDefault_GrSLPrecision,
1986 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001987 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001988 kFloat_GrSLType, kDefault_GrSLPrecision,
1989 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001990 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001991 kFloat_GrSLType, kDefault_GrSLPrecision,
1992 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001993 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001994 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001995
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001996 static const GrGLShaderVar gLightColorArgs[] = {
1997 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1998 };
1999 SkString lightColorBody;
2000 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2001 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2002 lightColorBody.appendf("\t\treturn vec3(0);\n");
2003 lightColorBody.appendf("\t}\n");
2004 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2005 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2006 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2007 color, cosOuter, coneScale);
2008 lightColorBody.appendf("\t}\n");
2009 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel29bee0f2015-04-29 11:54:42 -07002010 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07002011 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00002012 "lightColor",
2013 SK_ARRAY_COUNT(gLightColorArgs),
2014 gLightColorArgs,
2015 lightColorBody.c_str(),
2016 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002017
joshualitt30ba4362014-08-21 20:18:45 -07002018 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002019}
2020
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002021#endif
2022
djsollen@google.com08337772012-06-26 14:33:13 +00002023SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2024 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2025 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002026SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END