blob: f701b4c8945952f619404479d11d226574b51bc9 [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"
senorblanco1d3ff432015-10-20 10:17:34 -070011#include "SkDevice.h"
robertphillips3d32d762015-07-13 13:16:44 -070012#include "SkPoint3.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000014#include "SkTypes.h"
robertphillips3d32d762015-07-13 13:16:44 -070015#include "SkWriteBuffer.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
kkinnunencabe20c2015-06-01 01:37:26 -070018#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070019#include "GrDrawContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080020#include "GrFragmentProcessor.h"
21#include "GrInvariantOutput.h"
kkinnunencabe20c2015-06-01 01:37:26 -070022#include "GrPaint.h"
robertphillips1de87df2016-01-14 06:03:29 -080023#include "SkGr.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000024#include "effects/GrSingleTextureEffect.h"
egdaniel64c47282015-11-13 06:54:19 -080025#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080026#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080028#include "glsl/GrGLSLUniformHandler.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000029
30class GrGLDiffuseLightingEffect;
31class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000032
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000033// For brevity
egdaniel018fb622015-10-28 07:26:40 -070034typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000035#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000036
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037namespace {
38
reed80ea19c2015-05-12 10:37:34 -070039const SkScalar gOneThird = SkIntToScalar(1) / 3;
40const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000041const SkScalar gOneHalf = 0.5f;
42const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000043
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000044#if SK_SUPPORT_GPU
egdaniel018fb622015-10-28 07:26:40 -070045void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070046 const SkPoint3& point) {
egdaniel018fb622015-10-28 07:26:40 -070047 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
kkinnunen7510b222014-07-30 00:04:16 -070048 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000049}
50
egdaniel018fb622015-10-28 07:26:40 -070051void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
joshualittb0a8a372014-09-23 09:50:21 -070052 const SkPoint3& point) {
robertphillips3d32d762015-07-13 13:16:44 -070053 setUniformPoint3(pdman, uni, point);
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000054}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000055#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000056
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000057// Shift matrix components to the left, as we advance pixels to the right.
58inline void shiftMatrixLeft(int m[9]) {
59 m[0] = m[1];
60 m[3] = m[4];
61 m[6] = m[7];
62 m[1] = m[2];
63 m[4] = m[5];
64 m[7] = m[8];
65}
66
jvanverth992c7612015-07-17 07:22:30 -070067static inline void fast_normalize(SkPoint3* vector) {
68 // add a tiny bit so we don't have to worry about divide-by-zero
69 SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
70 SkScalar scale = sk_float_rsqrt(magSq);
71 vector->fX *= scale;
72 vector->fY *= scale;
73 vector->fZ *= scale;
74}
75
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000076class DiffuseLightingType {
77public:
78 DiffuseLightingType(SkScalar kd)
79 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070080 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
81 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000082 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
83 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -070084 SkPoint3 color = lightColor.makeScale(colorScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000086 SkClampMax(SkScalarRoundToInt(color.fX), 255),
87 SkClampMax(SkScalarRoundToInt(color.fY), 255),
88 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000089 }
90private:
91 SkScalar fKD;
92};
93
robertphillips3d32d762015-07-13 13:16:44 -070094static SkScalar max_component(const SkPoint3& p) {
95 return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
96}
97
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000098class SpecularLightingType {
99public:
100 SpecularLightingType(SkScalar ks, SkScalar shininess)
101 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -0700102 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
103 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000104 SkPoint3 halfDir(surfaceTolight);
105 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
jvanverth992c7612015-07-17 07:22:30 -0700106 fast_normalize(&halfDir);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000107 SkScalar colorScale = SkScalarMul(fKS,
108 SkScalarPow(normal.dot(halfDir), fShininess));
109 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
robertphillips3d32d762015-07-13 13:16:44 -0700110 SkPoint3 color = lightColor.makeScale(colorScale);
111 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +0000112 SkClampMax(SkScalarRoundToInt(color.fX), 255),
113 SkClampMax(SkScalarRoundToInt(color.fY), 255),
114 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000115 }
116private:
117 SkScalar fKS;
118 SkScalar fShininess;
119};
120
121inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
122 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
123}
124
125inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
robertphillips3d32d762015-07-13 13:16:44 -0700126 SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
127 SkScalarMul(-y, surfaceScale),
128 SK_Scalar1);
jvanverth992c7612015-07-17 07:22:30 -0700129 fast_normalize(&vector);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000130 return vector;
131}
132
133inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
134 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
135 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
136 surfaceScale);
137}
138
139inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
141 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
142 surfaceScale);
143}
144
145inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
147 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
148 surfaceScale);
149}
150
151inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
153 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
154 surfaceScale);
155}
156
157
158inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
159 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
160 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
161 surfaceScale);
162}
163
164inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
165 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
166 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
167 surfaceScale);
168}
169
170inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
171 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
172 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
173 surfaceScale);
174}
175
176inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
177 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
178 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
179 surfaceScale);
180}
181
182inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
183 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
184 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
185 surfaceScale);
186}
187
robertphillips2f0dbc72015-08-20 05:15:06 -0700188template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType,
189 const SkImageFilterLight* light,
190 const SkBitmap& src,
191 SkBitmap* dst,
192 SkScalar surfaceScale,
193 const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000194 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000195 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000196 int left = bounds.left(), right = bounds.right();
197 int bottom = bounds.bottom();
198 int y = bounds.top();
199 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000200 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000201 int x = left;
202 const SkPMColor* row1 = src.getAddr32(x, y);
203 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000204 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000205 m[4] = SkGetPackedA32(*row1++);
206 m[5] = SkGetPackedA32(*row1++);
207 m[7] = SkGetPackedA32(*row2++);
208 m[8] = SkGetPackedA32(*row2++);
209 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700210 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
211 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000212 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000213 {
214 shiftMatrixLeft(m);
215 m[5] = SkGetPackedA32(*row1++);
216 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000217 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700218 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
219 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000220 }
221 shiftMatrixLeft(m);
222 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700223 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
224 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000225 }
226
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000227 for (++y; y < bottom - 1; ++y) {
228 int x = left;
229 const SkPMColor* row0 = src.getAddr32(x, y - 1);
230 const SkPMColor* row1 = src.getAddr32(x, y);
231 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000232 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 m[1] = SkGetPackedA32(*row0++);
234 m[2] = SkGetPackedA32(*row0++);
235 m[4] = SkGetPackedA32(*row1++);
236 m[5] = SkGetPackedA32(*row1++);
237 m[7] = SkGetPackedA32(*row2++);
238 m[8] = SkGetPackedA32(*row2++);
239 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700240 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
241 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000242 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000243 shiftMatrixLeft(m);
244 m[2] = SkGetPackedA32(*row0++);
245 m[5] = SkGetPackedA32(*row1++);
246 m[8] = SkGetPackedA32(*row2++);
247 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700248 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
249 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000250 }
251 shiftMatrixLeft(m);
252 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700253 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
254 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000255 }
256
257 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000258 int x = left;
259 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
260 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000261 int m[9];
262 m[1] = SkGetPackedA32(*row0++);
263 m[2] = SkGetPackedA32(*row0++);
264 m[4] = SkGetPackedA32(*row1++);
265 m[5] = SkGetPackedA32(*row1++);
266 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700267 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
268 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000269 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000270 {
271 shiftMatrixLeft(m);
272 m[2] = SkGetPackedA32(*row0++);
273 m[5] = SkGetPackedA32(*row1++);
274 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700275 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
276 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000277 }
278 shiftMatrixLeft(m);
279 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700280 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
281 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000282 }
283}
284
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000285SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 SkPoint3 point;
287 point.fX = buffer.readScalar();
288 point.fY = buffer.readScalar();
289 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000290 buffer.validate(SkScalarIsFinite(point.fX) &&
291 SkScalarIsFinite(point.fY) &&
292 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000293 return point;
294};
295
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000296void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000297 buffer.writeScalar(point.fX);
298 buffer.writeScalar(point.fY);
299 buffer.writeScalar(point.fZ);
300};
301
senorblancod0d37ca2015-04-02 04:54:56 -0700302enum BoundaryMode {
303 kTopLeft_BoundaryMode,
304 kTop_BoundaryMode,
305 kTopRight_BoundaryMode,
306 kLeft_BoundaryMode,
307 kInterior_BoundaryMode,
308 kRight_BoundaryMode,
309 kBottomLeft_BoundaryMode,
310 kBottom_BoundaryMode,
311 kBottomRight_BoundaryMode,
312
313 kBoundaryModeCount,
314};
315
316class SkLightingImageFilterInternal : public SkLightingImageFilter {
317protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700318 SkLightingImageFilterInternal(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -0700319 SkScalar surfaceScale,
320 SkImageFilter* input,
321 const CropRect* cropRect)
322 : INHERITED(light, surfaceScale, input, cropRect) {}
323
324#if SK_SUPPORT_GPU
325 bool canFilterImageGPU() const override { return true; }
326 bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&,
327 SkBitmap* result, SkIPoint* offset) const override;
bsalomon4a339522015-10-06 08:40:50 -0700328 virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*,
senorblancod0d37ca2015-04-02 04:54:56 -0700329 const SkMatrix&,
330 const SkIRect& bounds,
331 BoundaryMode boundaryMode) const = 0;
332#endif
333private:
334#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700335 void drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700336 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700337 const SkMatrix& matrix,
338 const GrClip& clip,
339 const SkRect& dstRect,
340 BoundaryMode boundaryMode,
341 const SkIRect& bounds) const;
342#endif
343 typedef SkLightingImageFilter INHERITED;
344};
345
346#if SK_SUPPORT_GPU
robertphillipsea461502015-05-26 11:38:03 -0700347void SkLightingImageFilterInternal::drawRect(GrDrawContext* drawContext,
senorblancod0d37ca2015-04-02 04:54:56 -0700348 GrTexture* src,
senorblancod0d37ca2015-04-02 04:54:56 -0700349 const SkMatrix& matrix,
350 const GrClip& clip,
351 const SkRect& dstRect,
352 BoundaryMode boundaryMode,
353 const SkIRect& bounds) const {
354 SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
senorblancod0d37ca2015-04-02 04:54:56 -0700355 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700356 GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
bsalomonac856c92015-08-27 06:30:17 -0700357 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800358 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomona2e69fc2015-11-05 10:41:43 -0800359 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
senorblancod0d37ca2015-04-02 04:54:56 -0700360}
361
362bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy,
363 const SkBitmap& src,
364 const Context& ctx,
365 SkBitmap* result,
366 SkIPoint* offset) const {
367 SkBitmap input = src;
368 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco9a70b6e2015-10-16 11:35:14 -0700369 if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) {
senorblancod0d37ca2015-04-02 04:54:56 -0700370 return false;
371 }
372 SkIRect bounds;
373 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
374 return false;
375 }
376 SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()),
377 SkIntToScalar(bounds.height()));
378 GrTexture* srcTexture = input.getTexture();
379 GrContext* context = srcTexture->getContext();
380
381 GrSurfaceDesc desc;
382 desc.fFlags = kRenderTarget_GrSurfaceFlag,
383 desc.fWidth = bounds.width();
384 desc.fHeight = bounds.height();
385 desc.fConfig = kRGBA_8888_GrPixelConfig;
386
reed4e23cda2016-01-11 10:56:59 -0800387 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
senorblancod0d37ca2015-04-02 04:54:56 -0700388 if (!dst) {
389 return false;
390 }
391
392 // setup new clip
393 GrClip clip(dstRect);
394
395 offset->fX = bounds.left();
396 offset->fY = bounds.top();
397 SkMatrix matrix(ctx.ctm());
398 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
399 bounds.offset(-srcOffset);
400 SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1);
401 SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
402 SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
403 SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
404 SkRect interior = dstRect.makeInset(1, 1);
405 SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
406 SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
407 SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
408 SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
robertphillipsea461502015-05-26 11:38:03 -0700409
robertphillips2e1e51f2015-10-15 08:01:48 -0700410 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700411 if (!drawContext) {
412 return false;
413 }
414
robertphillips2e1e51f2015-10-15 08:01:48 -0700415 this->drawRect(drawContext, srcTexture, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds);
416 this->drawRect(drawContext, srcTexture, matrix, clip, top, kTop_BoundaryMode, bounds);
417 this->drawRect(drawContext, srcTexture, matrix, clip, topRight, kTopRight_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700418 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700419 this->drawRect(drawContext, srcTexture, matrix, clip, left, kLeft_BoundaryMode, bounds);
420 this->drawRect(drawContext, srcTexture, matrix, clip, interior, kInterior_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700421 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700422 this->drawRect(drawContext, srcTexture, matrix, clip, right, kRight_BoundaryMode, bounds);
423 this->drawRect(drawContext, srcTexture, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode,
senorblancod0d37ca2015-04-02 04:54:56 -0700424 bounds);
robertphillips2e1e51f2015-10-15 08:01:48 -0700425 this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds);
426 this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight,
robertphillipsea461502015-05-26 11:38:03 -0700427 kBottomRight_BoundaryMode, bounds);
robertphillips1de87df2016-01-14 06:03:29 -0800428 GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
senorblancod0d37ca2015-04-02 04:54:56 -0700429 return true;
430}
431#endif
432
433class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000434public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700435 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
436 SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700437 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700438
robertphillipsf3f5bad2014-12-19 13:49:15 -0800439 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000440 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000441 SkScalar kd() const { return fKD; }
442
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000443protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700444 SkDiffuseLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700445 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700446 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700447 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
448 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000449#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700450 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
451 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000452#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000453
454private:
reed9fa60da2014-08-21 07:59:51 -0700455 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700456 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000457 SkScalar fKD;
458};
459
senorblancod0d37ca2015-04-02 04:54:56 -0700460class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000461public:
robertphillips2f0dbc72015-08-20 05:15:06 -0700462 static SkImageFilter* Create(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700463 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700464
robertphillipsf3f5bad2014-12-19 13:49:15 -0800465 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000466 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
467
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000468 SkScalar ks() const { return fKS; }
469 SkScalar shininess() const { return fShininess; }
470
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000471protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700472 SkSpecularLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700473 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700474 void flatten(SkWriteBuffer& buffer) const override;
senorblancod0d37ca2015-04-02 04:54:56 -0700475 bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
476 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000477#if SK_SUPPORT_GPU
bsalomon4a339522015-10-06 08:40:50 -0700478 GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, const SkIRect& bounds,
479 BoundaryMode) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000480#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000481
482private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000483 SkScalar fKS;
484 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700485 friend class SkLightingImageFilter;
senorblancod0d37ca2015-04-02 04:54:56 -0700486 typedef SkLightingImageFilterInternal INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000487};
488
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000489#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000490
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000491class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000492public:
bsalomon4a339522015-10-06 08:40:50 -0700493 GrLightingEffect(GrTexture* texture, const SkImageFilterLight* light, SkScalar surfaceScale,
494 const SkMatrix& matrix, BoundaryMode boundaryMode);
robertphillipse004bfc2015-11-16 09:06:59 -0800495 ~GrLightingEffect() override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000496
robertphillips2f0dbc72015-08-20 05:15:06 -0700497 const SkImageFilterLight* light() const { return fLight; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000498 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000499 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
senorblancod0d37ca2015-04-02 04:54:56 -0700500 BoundaryMode boundaryMode() const { return fBoundaryMode; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000501
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000502protected:
mtklein36352bf2015-03-25 18:17:31 -0700503 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000504
mtklein36352bf2015-03-25 18:17:31 -0700505 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700506 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800507 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700508 }
509
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000510private:
robertphillips2f0dbc72015-08-20 05:15:06 -0700511 const SkImageFilterLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000512 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000513 SkMatrix fFilterMatrix;
senorblancod0d37ca2015-04-02 04:54:56 -0700514 BoundaryMode fBoundaryMode;
robertphillips2f0dbc72015-08-20 05:15:06 -0700515
516 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000517};
518
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000519class GrDiffuseLightingEffect : public GrLightingEffect {
520public:
bsalomon4a339522015-10-06 08:40:50 -0700521 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700522 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700523 SkScalar surfaceScale,
524 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700525 SkScalar kd,
526 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700527 return new GrDiffuseLightingEffect(texture, light, surfaceScale, matrix, kd, boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000528 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000529
mtklein36352bf2015-03-25 18:17:31 -0700530 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000531
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000532 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000533
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000534private:
egdaniel57d3b032015-11-13 11:57:27 -0800535 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700536
egdaniel57d3b032015-11-13 11:57:27 -0800537 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700538
mtklein36352bf2015-03-25 18:17:31 -0700539 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000540
bsalomon4a339522015-10-06 08:40:50 -0700541 GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700542 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000543 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000544 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -0700545 SkScalar kd,
546 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000547
joshualittb0a8a372014-09-23 09:50:21 -0700548 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000549 typedef GrLightingEffect INHERITED;
550 SkScalar fKD;
551};
552
553class GrSpecularLightingEffect : public GrLightingEffect {
554public:
bsalomon4a339522015-10-06 08:40:50 -0700555 static GrFragmentProcessor* Create(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700556 const SkImageFilterLight* light,
joshualittb0a8a372014-09-23 09:50:21 -0700557 SkScalar surfaceScale,
558 const SkMatrix& matrix,
559 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700560 SkScalar shininess,
561 BoundaryMode boundaryMode) {
bsalomon4a339522015-10-06 08:40:50 -0700562 return new GrSpecularLightingEffect(texture, light, surfaceScale, matrix, ks, shininess,
563 boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000564 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000565
mtklein36352bf2015-03-25 18:17:31 -0700566 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000567
egdaniel57d3b032015-11-13 11:57:27 -0800568 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800569
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000570 SkScalar ks() const { return fKS; }
571 SkScalar shininess() const { return fShininess; }
572
573private:
egdaniel57d3b032015-11-13 11:57:27 -0800574 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700575
mtklein36352bf2015-03-25 18:17:31 -0700576 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000577
bsalomon4a339522015-10-06 08:40:50 -0700578 GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -0700579 const SkImageFilterLight* light,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000580 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000581 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000582 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -0700583 SkScalar shininess,
584 BoundaryMode boundaryMode);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000585
joshualittb0a8a372014-09-23 09:50:21 -0700586 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000587 typedef GrLightingEffect INHERITED;
588 SkScalar fKS;
589 SkScalar fShininess;
590};
591
592///////////////////////////////////////////////////////////////////////////////
593
594class GrGLLight {
595public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000596 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000597
598 /**
599 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
600 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
601 */
egdaniel7ea439b2015-12-03 09:20:44 -0800602 void emitLightColorUniform(GrGLSLUniformHandler*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000603
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000604 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000605 * These two functions are called from GrGLLightingEffect's emitCode() function.
606 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
607 * the light. The expression will be used in the FS. emitLightColor writes an expression into
608 * the FS that is the color of the light. Either function may add functions and/or uniforms to
609 * the FS. The default of emitLightColor appends the name of the constant light color uniform
610 * and so this function only needs to be overridden if the light color varies spatially.
611 */
egdaniel7ea439b2015-12-03 09:20:44 -0800612 virtual void emitSurfaceToLight(GrGLSLUniformHandler*,
613 GrGLSLFragmentBuilder*,
614 const char* z) = 0;
615 virtual void emitLightColor(GrGLSLUniformHandler*,
egdaniel4ca2e602015-11-18 08:01:26 -0800616 GrGLSLFragmentBuilder*,
617 const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000618
619 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
620 // INHERITED::setData().
egdaniel018fb622015-10-28 07:26:40 -0700621 virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000622
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000623protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000624 /**
625 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
626 * function.
627 */
628 UniformHandle lightColorUni() const { return fColorUni; }
629
630private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000631 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000632
633 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000634};
635
636///////////////////////////////////////////////////////////////////////////////
637
638class GrGLDistantLight : public GrGLLight {
639public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000640 virtual ~GrGLDistantLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700641 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800642 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000643
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000644private:
645 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000646 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000647};
648
649///////////////////////////////////////////////////////////////////////////////
650
651class GrGLPointLight : public GrGLLight {
652public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000653 virtual ~GrGLPointLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700654 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800655 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000656
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000657private:
658 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000659 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000660};
661
662///////////////////////////////////////////////////////////////////////////////
663
664class GrGLSpotLight : public GrGLLight {
665public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000666 virtual ~GrGLSpotLight() {}
egdaniel018fb622015-10-28 07:26:40 -0700667 void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
egdaniel7ea439b2015-12-03 09:20:44 -0800668 void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override;
669 void emitLightColor(GrGLSLUniformHandler*,
egdaniel4ca2e602015-11-18 08:01:26 -0800670 GrGLSLFragmentBuilder*,
671 const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000672
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000673private:
674 typedef GrGLLight INHERITED;
675
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000676 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000677 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000678 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000679 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000680 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000681 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000682 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000683};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000684#else
685
686class GrGLLight;
687
688#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000689
690};
691
692///////////////////////////////////////////////////////////////////////////////
693
robertphillips2f0dbc72015-08-20 05:15:06 -0700694class SkImageFilterLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000695public:
caryclark0bccd872015-10-20 10:04:03 -0700696
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000697
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000698 enum LightType {
699 kDistant_LightType,
700 kPoint_LightType,
701 kSpot_LightType,
702 };
703 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000704 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000705 virtual GrGLLight* createGLLight() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700706 virtual bool isEqual(const SkImageFilterLight& other) const {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000707 return fColor == other.fColor;
708 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000709 // Called to know whether the generated GrGLLight will require access to the fragment position.
710 virtual bool requiresFragmentPosition() const = 0;
robertphillips2f0dbc72015-08-20 05:15:06 -0700711 virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000712
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000713 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000714 void flattenLight(SkWriteBuffer& buffer) const;
robertphillips2f0dbc72015-08-20 05:15:06 -0700715 static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000716
djsollen@google.com08337772012-06-26 14:33:13 +0000717protected:
robertphillips2f0dbc72015-08-20 05:15:06 -0700718 SkImageFilterLight(SkColor color) {
robertphillips3d32d762015-07-13 13:16:44 -0700719 fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
720 SkIntToScalar(SkColorGetG(color)),
721 SkIntToScalar(SkColorGetB(color)));
722 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700723 SkImageFilterLight(const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000724 : fColor(color) {}
robertphillips2f0dbc72015-08-20 05:15:06 -0700725 SkImageFilterLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000726 fColor = readPoint3(buffer);
727 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000728
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000729 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000730
djsollen@google.com08337772012-06-26 14:33:13 +0000731
732private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000733 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000734 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000735};
736
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000737///////////////////////////////////////////////////////////////////////////////
738
robertphillips2f0dbc72015-08-20 05:15:06 -0700739class SkDistantLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000740public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000741 SkDistantLight(const SkPoint3& direction, SkColor color)
742 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000743 }
djsollen@google.com08337772012-06-26 14:33:13 +0000744
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000745 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
746 return fDirection;
747 };
robertphillips3d32d762015-07-13 13:16:44 -0700748 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700749 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000750 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700751 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000752#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700753 return new GrGLDistantLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000754#else
755 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700756 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000757#endif
758 }
mtklein36352bf2015-03-25 18:17:31 -0700759 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000760
robertphillips2f0dbc72015-08-20 05:15:06 -0700761 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000762 if (other.type() != kDistant_LightType) {
763 return false;
764 }
765
766 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
767 return INHERITED::isEqual(other) &&
768 fDirection == o.fDirection;
769 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000770
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000771 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000772 fDirection = readPoint3(buffer);
773 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000774
djsollen@google.com08337772012-06-26 14:33:13 +0000775protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000776 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
777 : INHERITED(color), fDirection(direction) {
778 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700779 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000780 return new SkDistantLight(direction(), color());
781 }
mtklein36352bf2015-03-25 18:17:31 -0700782 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000783 writePoint3(fDirection, buffer);
784 }
785
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000786private:
787 SkPoint3 fDirection;
robertphillips2f0dbc72015-08-20 05:15:06 -0700788
789 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000790};
791
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000792///////////////////////////////////////////////////////////////////////////////
793
robertphillips2f0dbc72015-08-20 05:15:06 -0700794class SkPointLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000795public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000796 SkPointLight(const SkPoint3& location, SkColor color)
797 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000798
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000799 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700800 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
801 fLocation.fY - SkIntToScalar(y),
802 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
803 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700804 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000805 return direction;
806 };
robertphillips3d32d762015-07-13 13:16:44 -0700807 const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
mtklein36352bf2015-03-25 18:17:31 -0700808 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000809 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700810 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000811#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700812 return new GrGLPointLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000813#else
814 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700815 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000816#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000817 }
mtklein36352bf2015-03-25 18:17:31 -0700818 bool requiresFragmentPosition() const override { return true; }
robertphillips2f0dbc72015-08-20 05:15:06 -0700819 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000820 if (other.type() != kPoint_LightType) {
821 return false;
822 }
823 const SkPointLight& o = static_cast<const SkPointLight&>(other);
824 return INHERITED::isEqual(other) &&
825 fLocation == o.fLocation;
826 }
robertphillips2f0dbc72015-08-20 05:15:06 -0700827 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000828 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
829 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000830 // Use X scale and Y scale on Z and average the result
831 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
832 matrix.mapVectors(&locationZ, 1);
caryclark0bccd872015-10-20 10:04:03 -0700833 SkPoint3 location = SkPoint3::Make(location2.fX,
834 location2.fY,
robertphillips3d32d762015-07-13 13:16:44 -0700835 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000836 return new SkPointLight(location, color());
837 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000838
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000839 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000840 fLocation = readPoint3(buffer);
841 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000842
843protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000844 SkPointLight(const SkPoint3& location, const SkPoint3& color)
845 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700846 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000847 writePoint3(fLocation, buffer);
848 }
849
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000850private:
851 SkPoint3 fLocation;
robertphillips2f0dbc72015-08-20 05:15:06 -0700852
853 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000854};
855
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000856///////////////////////////////////////////////////////////////////////////////
857
robertphillips2f0dbc72015-08-20 05:15:06 -0700858class SkSpotLight : public SkImageFilterLight {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000859public:
senorblancod0d37ca2015-04-02 04:54:56 -0700860 SkSpotLight(const SkPoint3& location,
861 const SkPoint3& target,
862 SkScalar specularExponent,
863 SkScalar cutoffAngle,
864 SkColor color)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000865 : INHERITED(color),
866 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000867 fTarget(target),
caryclark0bccd872015-10-20 10:04:03 -0700868 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000869 {
870 fS = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700871 fast_normalize(&fS);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000872 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000873 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000874 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
875 fConeScale = SkScalarInvert(antiAliasThreshold);
876 }
djsollen@google.com08337772012-06-26 14:33:13 +0000877
robertphillips2f0dbc72015-08-20 05:15:06 -0700878 SkImageFilterLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000879 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
880 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000881 // Use X scale and Y scale on Z and average the result
882 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
883 matrix.mapVectors(&locationZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700884 SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
885 SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000886 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
887 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000888 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
889 matrix.mapVectors(&targetZ, 1);
robertphillips3d32d762015-07-13 13:16:44 -0700890 SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
891 SkScalarAve(targetZ.fX, targetZ.fY));
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000892 SkPoint3 s = target - location;
jvanverth992c7612015-07-17 07:22:30 -0700893 fast_normalize(&s);
senorblancod0d37ca2015-04-02 04:54:56 -0700894 return new SkSpotLight(location,
895 target,
896 fSpecularExponent,
897 fCosOuterConeAngle,
898 fCosInnerConeAngle,
899 fConeScale,
900 s,
901 color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000902 }
903
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000904 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
robertphillips3d32d762015-07-13 13:16:44 -0700905 SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
906 fLocation.fY - SkIntToScalar(y),
907 fLocation.fZ - SkScalarMul(SkIntToScalar(z),
908 surfaceScale));
jvanverth992c7612015-07-17 07:22:30 -0700909 fast_normalize(&direction);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000910 return direction;
911 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000912 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000913 SkScalar cosAngle = -surfaceToLight.dot(fS);
robertphillips3d32d762015-07-13 13:16:44 -0700914 SkScalar scale = 0;
915 if (cosAngle >= fCosOuterConeAngle) {
916 scale = SkScalarPow(cosAngle, fSpecularExponent);
917 if (cosAngle < fCosInnerConeAngle) {
918 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
919 scale *= fConeScale;
920 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000921 }
robertphillips3d32d762015-07-13 13:16:44 -0700922 return this->color().makeScale(scale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000923 }
mtklein36352bf2015-03-25 18:17:31 -0700924 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000925#if SK_SUPPORT_GPU
halcanary385fe4d2015-08-26 13:07:48 -0700926 return new GrGLSpotLight;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000927#else
928 SkDEBUGFAIL("Should not call in GPU-less build");
halcanary96fcdcc2015-08-27 07:41:13 -0700929 return nullptr;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000930#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000931 }
mtklein36352bf2015-03-25 18:17:31 -0700932 bool requiresFragmentPosition() const override { return true; }
933 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000934 const SkPoint3& location() const { return fLocation; }
935 const SkPoint3& target() const { return fTarget; }
936 SkScalar specularExponent() const { return fSpecularExponent; }
937 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
938 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
939 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000940 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000941
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000942 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000943 fLocation = readPoint3(buffer);
944 fTarget = readPoint3(buffer);
945 fSpecularExponent = buffer.readScalar();
946 fCosOuterConeAngle = buffer.readScalar();
947 fCosInnerConeAngle = buffer.readScalar();
948 fConeScale = buffer.readScalar();
949 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000950 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
951 SkScalarIsFinite(fCosOuterConeAngle) &&
952 SkScalarIsFinite(fCosInnerConeAngle) &&
953 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000954 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000955protected:
senorblancod0d37ca2015-04-02 04:54:56 -0700956 SkSpotLight(const SkPoint3& location,
957 const SkPoint3& target,
958 SkScalar specularExponent,
959 SkScalar cosOuterConeAngle,
960 SkScalar cosInnerConeAngle,
961 SkScalar coneScale,
962 const SkPoint3& s,
963 const SkPoint3& color)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000964 : INHERITED(color),
965 fLocation(location),
966 fTarget(target),
967 fSpecularExponent(specularExponent),
968 fCosOuterConeAngle(cosOuterConeAngle),
969 fCosInnerConeAngle(cosInnerConeAngle),
970 fConeScale(coneScale),
971 fS(s)
972 {
973 }
mtklein36352bf2015-03-25 18:17:31 -0700974 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000975 writePoint3(fLocation, buffer);
976 writePoint3(fTarget, buffer);
977 buffer.writeScalar(fSpecularExponent);
978 buffer.writeScalar(fCosOuterConeAngle);
979 buffer.writeScalar(fCosInnerConeAngle);
980 buffer.writeScalar(fConeScale);
981 writePoint3(fS, buffer);
982 }
983
robertphillips2f0dbc72015-08-20 05:15:06 -0700984 bool isEqual(const SkImageFilterLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000985 if (other.type() != kSpot_LightType) {
986 return false;
987 }
988
989 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
990 return INHERITED::isEqual(other) &&
991 fLocation == o.fLocation &&
992 fTarget == o.fTarget &&
993 fSpecularExponent == o.fSpecularExponent &&
994 fCosOuterConeAngle == o.fCosOuterConeAngle;
995 }
996
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000997private:
caryclark0bccd872015-10-20 10:04:03 -0700998 static const SkScalar kSpecularExponentMin;
999 static const SkScalar kSpecularExponentMax;
1000
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001001 SkPoint3 fLocation;
1002 SkPoint3 fTarget;
1003 SkScalar fSpecularExponent;
1004 SkScalar fCosOuterConeAngle;
1005 SkScalar fCosInnerConeAngle;
1006 SkScalar fConeScale;
1007 SkPoint3 fS;
robertphillips2f0dbc72015-08-20 05:15:06 -07001008
1009 typedef SkImageFilterLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001010};
1011
caryclark0bccd872015-10-20 10:04:03 -07001012// According to the spec, the specular term should be in the range [1, 128] :
1013// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
1014const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
1015const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
1016
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001017///////////////////////////////////////////////////////////////////////////////
1018
robertphillips2f0dbc72015-08-20 05:15:06 -07001019void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001020 // Write type first, then baseclass, then subclass.
1021 buffer.writeInt(this->type());
1022 writePoint3(fColor, buffer);
1023 this->onFlattenLight(buffer);
1024}
1025
robertphillips2f0dbc72015-08-20 05:15:06 -07001026/*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001027 // Read type first.
robertphillips2f0dbc72015-08-20 05:15:06 -07001028 const SkImageFilterLight::LightType type = (SkImageFilterLight::LightType)buffer.readInt();
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001029 switch (type) {
1030 // Each of these constructors must first call SkLight's, so we'll read the baseclass
1031 // then subclass, same order as flattenLight.
halcanary385fe4d2015-08-26 13:07:48 -07001032 case SkImageFilterLight::kDistant_LightType:
1033 return new SkDistantLight(buffer);
1034 case SkImageFilterLight::kPoint_LightType:
1035 return new SkPointLight(buffer);
1036 case SkImageFilterLight::kSpot_LightType:
1037 return new SkSpotLight(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001038 default:
1039 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001040 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -07001041 return nullptr;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001042 }
1043}
1044///////////////////////////////////////////////////////////////////////////////
1045
robertphillips2f0dbc72015-08-20 05:15:06 -07001046SkLightingImageFilter::SkLightingImageFilter(SkImageFilterLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001047 SkImageFilter* input, const CropRect* cropRect)
1048 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -07001049 , fLight(SkRef(light))
1050 , fSurfaceScale(surfaceScale / 255)
1051{}
1052
1053SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
1054 SkColor lightColor,
1055 SkScalar surfaceScale,
1056 SkScalar kd,
1057 SkImageFilter* input,
1058 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001059 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001060 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001061}
1062
reed9fa60da2014-08-21 07:59:51 -07001063SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
1064 SkColor lightColor,
1065 SkScalar surfaceScale,
1066 SkScalar kd,
1067 SkImageFilter* input,
1068 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001069 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001070 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001071}
1072
reed9fa60da2014-08-21 07:59:51 -07001073SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
1074 const SkPoint3& target,
1075 SkScalar specularExponent,
1076 SkScalar cutoffAngle,
1077 SkColor lightColor,
1078 SkScalar surfaceScale,
1079 SkScalar kd,
1080 SkImageFilter* input,
1081 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001082 SkAutoTUnref<SkImageFilterLight> light(
1083 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001084 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001085}
1086
reed9fa60da2014-08-21 07:59:51 -07001087SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
1088 SkColor lightColor,
1089 SkScalar surfaceScale,
1090 SkScalar ks,
1091 SkScalar shine,
1092 SkImageFilter* input,
1093 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001094 SkAutoTUnref<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001095 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001096}
1097
reed9fa60da2014-08-21 07:59:51 -07001098SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
1099 SkColor lightColor,
1100 SkScalar surfaceScale,
1101 SkScalar ks,
1102 SkScalar shine,
1103 SkImageFilter* input,
1104 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001105 SkAutoTUnref<SkImageFilterLight> light(new SkPointLight(location, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001106 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001107}
1108
reed9fa60da2014-08-21 07:59:51 -07001109SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
1110 const SkPoint3& target,
1111 SkScalar specularExponent,
1112 SkScalar cutoffAngle,
1113 SkColor lightColor,
1114 SkScalar surfaceScale,
1115 SkScalar ks,
1116 SkScalar shine,
1117 SkImageFilter* input,
1118 const CropRect* cropRect) {
halcanary385fe4d2015-08-26 13:07:48 -07001119 SkAutoTUnref<SkImageFilterLight> light(
1120 new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor));
reed9fa60da2014-08-21 07:59:51 -07001121 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001122}
1123
reed9fa60da2014-08-21 07:59:51 -07001124SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001125
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001126void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001127 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +00001128 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -07001129 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001130}
1131
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001132///////////////////////////////////////////////////////////////////////////////
1133
robertphillips2f0dbc72015-08-20 05:15:06 -07001134SkImageFilter* SkDiffuseLightingImageFilter::Create(SkImageFilterLight* light,
1135 SkScalar surfaceScale,
1136 SkScalar kd,
1137 SkImageFilter* input,
1138 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001139 if (nullptr == light) {
1140 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001141 }
1142 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001143 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001144 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001145 // According to the spec, kd can be any non-negative number :
1146 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -07001147 if (kd < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001148 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001149 }
halcanary385fe4d2015-08-26 13:07:48 -07001150 return new SkDiffuseLightingImageFilter(light, surfaceScale, kd, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001151}
1152
robertphillips2f0dbc72015-08-20 05:15:06 -07001153SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001154 SkScalar surfaceScale,
1155 SkScalar kd,
1156 SkImageFilter* input,
1157 const CropRect* cropRect)
1158 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001159 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001160{
1161}
1162
reed9fa60da2014-08-21 07:59:51 -07001163SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1164 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001165 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001166 SkScalar surfaceScale = buffer.readScalar();
1167 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001168 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001169}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001170
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001171void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001172 this->INHERITED::flatten(buffer);
1173 buffer.writeScalar(fKD);
1174}
1175
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001176bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1177 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001178 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001179 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001180 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001181 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001182 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001183 if (!this->filterInput(0, 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
senorblanco1d3ff432015-10-20 10:17:34 -07001204 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1205 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001206 return false;
1207 }
senorblanco1d3ff432015-10-20 10:17:34 -07001208 *dst = device->accessBitmap(false);
1209 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001210
senorblanco7b7ecfc2015-08-26 14:26:40 -07001211 SkMatrix matrix(ctx.ctm());
1212 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1213 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001214
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001215 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001216 offset->fX = bounds.left();
1217 offset->fY = bounds.top();
1218 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001219 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001220 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001221 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType,
1222 transformedLight,
1223 src,
1224 dst,
1225 surfaceScale(),
1226 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001227 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001228 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001229 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType,
1230 transformedLight,
1231 src,
1232 dst,
1233 surfaceScale(),
1234 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001235 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001236 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001237 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType,
1238 transformedLight,
1239 src,
1240 dst,
1241 surfaceScale(),
1242 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001243 break;
1244 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001245
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001246 return true;
1247}
1248
robertphillipsf3f5bad2014-12-19 13:49:15 -08001249#ifndef SK_IGNORE_TO_STRING
1250void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1251 str->appendf("SkDiffuseLightingImageFilter: (");
1252 str->appendf("kD: %f\n", fKD);
1253 str->append(")");
1254}
1255#endif
1256
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001257#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001258GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001259 GrTexture* texture,
1260 const SkMatrix& matrix,
1261 const SkIRect&,
1262 BoundaryMode boundaryMode
senorblancod0d37ca2015-04-02 04:54:56 -07001263) const {
joshualitt5f10b5c2015-07-09 10:24:35 -07001264 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001265 return GrDiffuseLightingEffect::Create(texture, this->light(), scale, matrix, this->kd(),
1266 boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001267}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001268#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001269
1270///////////////////////////////////////////////////////////////////////////////
1271
robertphillips2f0dbc72015-08-20 05:15:06 -07001272SkImageFilter* SkSpecularLightingImageFilter::Create(SkImageFilterLight* light,
1273 SkScalar surfaceScale,
1274 SkScalar ks,
1275 SkScalar shininess,
1276 SkImageFilter* input,
1277 const CropRect* cropRect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001278 if (nullptr == light) {
1279 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001280 }
1281 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001282 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001283 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001284 // According to the spec, ks can be any non-negative number :
1285 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001286 if (ks < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -07001287 return nullptr;
reed9fa60da2014-08-21 07:59:51 -07001288 }
halcanary385fe4d2015-08-26 13:07:48 -07001289 return new SkSpecularLightingImageFilter(light, surfaceScale, ks, shininess, input, cropRect);
reed9fa60da2014-08-21 07:59:51 -07001290}
1291
robertphillips2f0dbc72015-08-20 05:15:06 -07001292SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkImageFilterLight* light,
senorblancod0d37ca2015-04-02 04:54:56 -07001293 SkScalar surfaceScale,
1294 SkScalar ks,
1295 SkScalar shininess,
1296 SkImageFilter* input,
1297 const CropRect* cropRect)
1298 : INHERITED(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001299 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001300 fShininess(shininess)
1301{
1302}
1303
reed9fa60da2014-08-21 07:59:51 -07001304SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1305 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
robertphillips2f0dbc72015-08-20 05:15:06 -07001306 SkAutoTUnref<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
reed9fa60da2014-08-21 07:59:51 -07001307 SkScalar surfaceScale = buffer.readScalar();
1308 SkScalar ks = buffer.readScalar();
1309 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001310 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001311}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001312
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001313void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001314 this->INHERITED::flatten(buffer);
1315 buffer.writeScalar(fKS);
1316 buffer.writeScalar(fShininess);
1317}
1318
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001319bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1320 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001321 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001322 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001323 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001324 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001325 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblancob9519f82015-10-15 12:15:13 -07001326 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001327 return false;
1328 }
1329
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001330 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001331 return false;
1332 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001333
1334 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001335 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001336 return false;
1337 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001338
1339 if (bounds.width() < 2 || bounds.height() < 2) {
1340 return false;
1341 }
1342
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001343 SkAutoLockPixels alp(src);
1344 if (!src.getPixels()) {
1345 return false;
1346 }
1347
senorblanco1d3ff432015-10-20 10:17:34 -07001348 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
1349 if (!device) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001350 return false;
1351 }
senorblanco1d3ff432015-10-20 10:17:34 -07001352 *dst = device->accessBitmap(false);
1353 SkAutoLockPixels alp_dst(*dst);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001354
1355 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001356 offset->fX = bounds.left();
1357 offset->fY = bounds.top();
senorblanco7b7ecfc2015-08-26 14:26:40 -07001358 SkMatrix matrix(ctx.ctm());
1359 matrix.postTranslate(SkIntToScalar(-srcOffset.x()), SkIntToScalar(-srcOffset.y()));
1360 SkAutoTUnref<SkImageFilterLight> transformedLight(light()->transform(matrix));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001361 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001362 switch (transformedLight->type()) {
robertphillips2f0dbc72015-08-20 05:15:06 -07001363 case SkImageFilterLight::kDistant_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001364 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType,
1365 transformedLight,
1366 src,
1367 dst,
1368 surfaceScale(),
1369 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001370 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001371 case SkImageFilterLight::kPoint_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001372 lightBitmap<SpecularLightingType, SkPointLight>(lightingType,
1373 transformedLight,
1374 src,
1375 dst,
1376 surfaceScale(),
1377 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001378 break;
robertphillips2f0dbc72015-08-20 05:15:06 -07001379 case SkImageFilterLight::kSpot_LightType:
senorblancod0d37ca2015-04-02 04:54:56 -07001380 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType,
1381 transformedLight,
1382 src,
1383 dst,
1384 surfaceScale(),
1385 bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001386 break;
1387 }
1388 return true;
1389}
1390
robertphillipsf3f5bad2014-12-19 13:49:15 -08001391#ifndef SK_IGNORE_TO_STRING
1392void SkSpecularLightingImageFilter::toString(SkString* str) const {
1393 str->appendf("SkSpecularLightingImageFilter: (");
1394 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1395 str->append(")");
1396}
1397#endif
1398
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001399#if SK_SUPPORT_GPU
senorblancod0d37ca2015-04-02 04:54:56 -07001400GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
joshualitt5f10b5c2015-07-09 10:24:35 -07001401 GrTexture* texture,
1402 const SkMatrix& matrix,
1403 const SkIRect&,
1404 BoundaryMode boundaryMode) const {
1405 SkScalar scale = SkScalarMul(this->surfaceScale(), SkIntToScalar(255));
bsalomon4a339522015-10-06 08:40:50 -07001406 return GrSpecularLightingEffect::Create(texture, this->light(), scale, matrix, this->ks(),
1407 this->shininess(), boundaryMode);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001408}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001409#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001410
1411///////////////////////////////////////////////////////////////////////////////
1412
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001413#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001414
1415namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001416SkPoint3 random_point3(SkRandom* random) {
robertphillips3d32d762015-07-13 13:16:44 -07001417 return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1418 SkScalarToFloat(random->nextSScalar1()),
1419 SkScalarToFloat(random->nextSScalar1()));
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001420}
1421
robertphillips2f0dbc72015-08-20 05:15:06 -07001422SkImageFilterLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001423 int type = random->nextULessThan(3);
1424 switch (type) {
1425 case 0: {
halcanary385fe4d2015-08-26 13:07:48 -07001426 return new SkDistantLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001427 }
1428 case 1: {
halcanary385fe4d2015-08-26 13:07:48 -07001429 return new SkPointLight(random_point3(random), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001430 }
1431 case 2: {
halcanary385fe4d2015-08-26 13:07:48 -07001432 return new SkSpotLight(random_point3(random), random_point3(random),
1433 random->nextUScalar1(), random->nextUScalar1(), random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001434 }
1435 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001436 SkFAIL("Unexpected value.");
halcanary96fcdcc2015-08-27 07:41:13 -07001437 return nullptr;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001438 }
1439}
1440
senorblancod0d37ca2015-04-02 04:54:56 -07001441SkString emitNormalFunc(BoundaryMode mode,
1442 const char* pointToNormalName,
1443 const char* sobelFuncName) {
1444 SkString result;
1445 switch (mode) {
1446 case kTopLeft_BoundaryMode:
1447 result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], 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, gTwoThirds,
1451 sobelFuncName, gTwoThirds);
1452 break;
1453 case kTop_BoundaryMode:
1454 result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n"
1455 "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n"
1456 "\t surfaceScale);\n",
1457 pointToNormalName, sobelFuncName, gOneThird,
1458 sobelFuncName, gOneHalf);
1459 break;
1460 case kTopRight_BoundaryMode:
1461 result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n"
1462 "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n"
1463 "\t surfaceScale);\n",
1464 pointToNormalName, sobelFuncName, gTwoThirds,
1465 sobelFuncName, gTwoThirds);
1466 break;
1467 case kLeft_BoundaryMode:
1468 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n"
1469 "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n"
1470 "\t surfaceScale);\n",
1471 pointToNormalName, sobelFuncName, gOneHalf,
1472 sobelFuncName, gOneThird);
1473 break;
1474 case kInterior_BoundaryMode:
1475 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n"
1476 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n"
1477 "\t surfaceScale);\n",
1478 pointToNormalName, sobelFuncName, gOneQuarter,
1479 sobelFuncName, gOneQuarter);
1480 break;
1481 case kRight_BoundaryMode:
1482 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n"
1483 "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n"
1484 "\t surfaceScale);\n",
1485 pointToNormalName, sobelFuncName, gOneHalf,
1486 sobelFuncName, gOneThird);
1487 break;
1488 case kBottomLeft_BoundaryMode:
1489 result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n"
1490 "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n"
1491 "\t surfaceScale);\n",
1492 pointToNormalName, sobelFuncName, gTwoThirds,
1493 sobelFuncName, gTwoThirds);
1494 break;
1495 case kBottom_BoundaryMode:
1496 result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n"
1497 "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n"
1498 "\t surfaceScale);\n",
1499 pointToNormalName, sobelFuncName, gOneThird,
1500 sobelFuncName, gOneHalf);
1501 break;
1502 case kBottomRight_BoundaryMode:
1503 result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n"
1504 "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n"
1505 "\t surfaceScale);\n",
1506 pointToNormalName, sobelFuncName, gTwoThirds,
1507 sobelFuncName, gTwoThirds);
1508 break;
1509 default:
1510 SkASSERT(false);
1511 break;
1512 }
1513 return result;
1514}
1515
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001516}
1517
egdaniel64c47282015-11-13 06:54:19 -08001518class GrGLLightingEffect : public GrGLSLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001519public:
joshualitteb2a6762014-12-04 11:35:33 -08001520 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001521 virtual ~GrGLLightingEffect();
1522
wangyix7c157a92015-07-22 15:08:53 -07001523 void emitCode(EmitArgs&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001524
jvanverthcfc18862015-04-28 08:48:20 -07001525 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001526
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001527protected:
wangyixb1daa862015-08-18 11:29:31 -07001528 /**
1529 * Subclasses of GrGLLightingEffect must call INHERITED::onSetData();
1530 */
egdaniel018fb622015-10-28 07:26:40 -07001531 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001532
egdaniel7ea439b2015-12-03 09:20:44 -08001533 virtual void emitLightFunc(GrGLSLUniformHandler*,
1534 GrGLSLFragmentBuilder*,
1535 SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001536
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001537private:
egdaniel64c47282015-11-13 06:54:19 -08001538 typedef GrGLSLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001539
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001540 UniformHandle fImageIncrementUni;
1541 UniformHandle fSurfaceScaleUni;
1542 GrGLLight* fLight;
senorblancod0d37ca2015-04-02 04:54:56 -07001543 BoundaryMode fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001544};
1545
1546///////////////////////////////////////////////////////////////////////////////
1547
1548class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1549public:
joshualitteb2a6762014-12-04 11:35:33 -08001550 GrGLDiffuseLightingEffect(const GrProcessor&);
egdaniel7ea439b2015-12-03 09:20:44 -08001551 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001552
1553protected:
egdaniel018fb622015-10-28 07:26:40 -07001554 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001555
1556private:
1557 typedef GrGLLightingEffect INHERITED;
1558
bsalomon@google.com032b2212012-07-16 13:36:18 +00001559 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001560};
1561
1562///////////////////////////////////////////////////////////////////////////////
1563
1564class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1565public:
joshualitteb2a6762014-12-04 11:35:33 -08001566 GrGLSpecularLightingEffect(const GrProcessor&);
egdaniel7ea439b2015-12-03 09:20:44 -08001567 void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override;
wangyixb1daa862015-08-18 11:29:31 -07001568
1569protected:
egdaniel018fb622015-10-28 07:26:40 -07001570 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001571
1572private:
1573 typedef GrGLLightingEffect INHERITED;
1574
bsalomon@google.com032b2212012-07-16 13:36:18 +00001575 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001576 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001577};
1578
1579///////////////////////////////////////////////////////////////////////////////
1580
bsalomon4a339522015-10-06 08:40:50 -07001581GrLightingEffect::GrLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001582 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001583 SkScalar surfaceScale,
senorblancod0d37ca2015-04-02 04:54:56 -07001584 const SkMatrix& matrix,
1585 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001586 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001587 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001588 , fSurfaceScale(surfaceScale)
senorblancod0d37ca2015-04-02 04:54:56 -07001589 , fFilterMatrix(matrix)
1590 , fBoundaryMode(boundaryMode) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001591 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001592 if (light->requiresFragmentPosition()) {
1593 this->setWillReadFragmentPosition();
1594 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001595}
1596
1597GrLightingEffect::~GrLightingEffect() {
1598 fLight->unref();
1599}
1600
bsalomon0e08fc12014-10-15 08:19:04 -07001601bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001602 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001603 return fLight->isEqual(*s.fLight) &&
senorblancod0d37ca2015-04-02 04:54:56 -07001604 fSurfaceScale == s.fSurfaceScale &&
1605 fBoundaryMode == s.fBoundaryMode;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001606}
1607
1608///////////////////////////////////////////////////////////////////////////////
1609
bsalomon4a339522015-10-06 08:40:50 -07001610GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001611 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001612 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001613 const SkMatrix& matrix,
senorblancod0d37ca2015-04-02 04:54:56 -07001614 SkScalar kd,
1615 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001616 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001617 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001618}
1619
bsalomon0e08fc12014-10-15 08:19:04 -07001620bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001621 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001622 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001623 this->kd() == s.kd();
1624}
1625
egdaniel57d3b032015-11-13 11:57:27 -08001626void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1627 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001628 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1629}
1630
egdaniel57d3b032015-11-13 11:57:27 -08001631GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001632 return new GrGLDiffuseLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001633}
1634
joshualittb0a8a372014-09-23 09:50:21 -07001635GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001636
bsalomonc21b09e2015-08-28 18:46:56 -07001637const GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001638 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1639 SkScalar kd = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001640 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001641 SkMatrix matrix;
1642 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001643 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001644 }
joshualitt0067ff52015-07-08 14:26:19 -07001645 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001646 return GrDiffuseLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001647 light, surfaceScale, matrix, kd, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001648}
1649
1650
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001651///////////////////////////////////////////////////////////////////////////////
1652
joshualitteb2a6762014-12-04 11:35:33 -08001653GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001654 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001655 fLight = m.light()->createGLLight();
senorblancod0d37ca2015-04-02 04:54:56 -07001656 fBoundaryMode = m.boundaryMode();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001657}
1658
1659GrGLLightingEffect::~GrGLLightingEffect() {
1660 delete fLight;
1661}
1662
wangyix7c157a92015-07-22 15:08:53 -07001663void GrGLLightingEffect::emitCode(EmitArgs& args) {
egdaniel7ea439b2015-12-03 09:20:44 -08001664 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1665 fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1666 kVec2f_GrSLType, kDefault_GrSLPrecision,
1667 "ImageIncrement");
1668 fSurfaceScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1669 kFloat_GrSLType, kDefault_GrSLPrecision,
1670 "SurfaceScale");
1671 fLight->emitLightColorUniform(uniformHandler);
egdaniel4ca2e602015-11-18 08:01:26 -08001672 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001673 SkString lightFunc;
egdaniel7ea439b2015-12-03 09:20:44 -08001674 this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc);
egdaniel0d3f0612015-10-21 10:45:48 -07001675 static const GrGLSLShaderVar gSobelArgs[] = {
1676 GrGLSLShaderVar("a", kFloat_GrSLType),
1677 GrGLSLShaderVar("b", kFloat_GrSLType),
1678 GrGLSLShaderVar("c", kFloat_GrSLType),
1679 GrGLSLShaderVar("d", kFloat_GrSLType),
1680 GrGLSLShaderVar("e", kFloat_GrSLType),
1681 GrGLSLShaderVar("f", kFloat_GrSLType),
1682 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001683 };
1684 SkString sobelFuncName;
egdaniel4ca2e602015-11-18 08:01:26 -08001685 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
joshualitt30ba4362014-08-21 20:18:45 -07001686
egdaniel4ca2e602015-11-18 08:01:26 -08001687 fragBuilder->emitFunction(kFloat_GrSLType,
1688 "sobel",
1689 SK_ARRAY_COUNT(gSobelArgs),
1690 gSobelArgs,
1691 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1692 &sobelFuncName);
egdaniel0d3f0612015-10-21 10:45:48 -07001693 static const GrGLSLShaderVar gPointToNormalArgs[] = {
1694 GrGLSLShaderVar("x", kFloat_GrSLType),
1695 GrGLSLShaderVar("y", kFloat_GrSLType),
1696 GrGLSLShaderVar("scale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001697 };
1698 SkString pointToNormalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001699 fragBuilder->emitFunction(kVec3f_GrSLType,
1700 "pointToNormal",
1701 SK_ARRAY_COUNT(gPointToNormalArgs),
1702 gPointToNormalArgs,
1703 "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n",
1704 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001705
egdaniel0d3f0612015-10-21 10:45:48 -07001706 static const GrGLSLShaderVar gInteriorNormalArgs[] = {
1707 GrGLSLShaderVar("m", kFloat_GrSLType, 9),
1708 GrGLSLShaderVar("surfaceScale", kFloat_GrSLType),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001709 };
senorblancod0d37ca2015-04-02 04:54:56 -07001710 SkString normalBody = emitNormalFunc(fBoundaryMode,
1711 pointToNormalName.c_str(),
1712 sobelFuncName.c_str());
1713 SkString normalName;
egdaniel4ca2e602015-11-18 08:01:26 -08001714 fragBuilder->emitFunction(kVec3f_GrSLType,
1715 "normal",
1716 SK_ARRAY_COUNT(gInteriorNormalArgs),
1717 gInteriorNormalArgs,
1718 normalBody.c_str(),
1719 &normalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001720
egdaniel4ca2e602015-11-18 08:01:26 -08001721 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1722 fragBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001723
egdaniel7ea439b2015-12-03 09:20:44 -08001724 const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
1725 const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
bsalomon@google.com032b2212012-07-16 13:36:18 +00001726
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001727 int index = 0;
senorblancod0d37ca2015-04-02 04:54:56 -07001728 for (int dy = 1; dy >= -1; dy--) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001729 for (int dx = -1; dx <= 1; dx++) {
1730 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001731 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
egdaniel4ca2e602015-11-18 08:01:26 -08001732 fragBuilder->codeAppendf("\t\tm[%d] = ", index++);
1733 fragBuilder->appendTextureLookup(args.fSamplers[0], texCoords.c_str());
1734 fragBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001735 }
1736 }
egdaniel4ca2e602015-11-18 08:01:26 -08001737 fragBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001738 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001739 arg.appendf("%s * m[4]", surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001740 fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001741 fragBuilder->codeAppend(";\n");
1742 fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1743 args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale);
egdaniel7ea439b2015-12-03 09:20:44 -08001744 fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight");
egdaniel4ca2e602015-11-18 08:01:26 -08001745 fragBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001746 SkString modulate;
wangyix7c157a92015-07-22 15:08:53 -07001747 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
egdaniel4ca2e602015-11-18 08:01:26 -08001748 fragBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001749}
1750
joshualittb0a8a372014-09-23 09:50:21 -07001751void GrGLLightingEffect::GenKey(const GrProcessor& proc,
jvanverthcfc18862015-04-28 08:48:20 -07001752 const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
senorblancod0d37ca2015-04-02 04:54:56 -07001753 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1754 b->add32(lighting.boundaryMode() << 2 | lighting.light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001755}
1756
egdaniel018fb622015-10-28 07:26:40 -07001757void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1758 const GrProcessor& proc) {
joshualittb0a8a372014-09-23 09:50:21 -07001759 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001760 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001761 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001762 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1763 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
robertphillips2f0dbc72015-08-20 05:15:06 -07001764 SkAutoTUnref<SkImageFilterLight> transformedLight(
1765 lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001766 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001767}
1768
1769///////////////////////////////////////////////////////////////////////////////
1770
1771///////////////////////////////////////////////////////////////////////////////
1772
joshualitteb2a6762014-12-04 11:35:33 -08001773GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1774 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001775}
1776
egdaniel7ea439b2015-12-03 09:20:44 -08001777void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001778 GrGLSLFragmentBuilder* fragBuilder,
1779 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001780 const char* kd;
egdaniel7ea439b2015-12-03 09:20:44 -08001781 fKDUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001782 kFloat_GrSLType, kDefault_GrSLPrecision,
1783 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001784
egdaniel0d3f0612015-10-21 10:45:48 -07001785 static const GrGLSLShaderVar gLightArgs[] = {
1786 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1787 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1788 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001789 };
1790 SkString lightBody;
1791 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1792 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001793 fragBuilder->emitFunction(kVec4f_GrSLType,
1794 "light",
1795 SK_ARRAY_COUNT(gLightArgs),
1796 gLightArgs,
1797 lightBody.c_str(),
1798 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001799}
1800
egdaniel018fb622015-10-28 07:26:40 -07001801void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1802 const GrProcessor& proc) {
wangyixb1daa862015-08-18 11:29:31 -07001803 INHERITED::onSetData(pdman, proc);
joshualittb0a8a372014-09-23 09:50:21 -07001804 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001805 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001806}
1807
1808///////////////////////////////////////////////////////////////////////////////
1809
bsalomon4a339522015-10-06 08:40:50 -07001810GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
robertphillips2f0dbc72015-08-20 05:15:06 -07001811 const SkImageFilterLight* light,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001812 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001813 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001814 SkScalar ks,
senorblancod0d37ca2015-04-02 04:54:56 -07001815 SkScalar shininess,
1816 BoundaryMode boundaryMode)
bsalomon4a339522015-10-06 08:40:50 -07001817 : INHERITED(texture, light, surfaceScale, matrix, boundaryMode)
robertphillips2f0dbc72015-08-20 05:15:06 -07001818 , fKS(ks)
1819 , fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001820 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001821}
1822
bsalomon0e08fc12014-10-15 08:19:04 -07001823bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001824 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001825 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001826 this->ks() == s.ks() &&
1827 this->shininess() == s.shininess();
1828}
1829
egdaniel57d3b032015-11-13 11:57:27 -08001830void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1831 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001832 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1833}
1834
egdaniel57d3b032015-11-13 11:57:27 -08001835GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001836 return new GrGLSpecularLightingEffect(*this);
joshualitteb2a6762014-12-04 11:35:33 -08001837}
1838
joshualittb0a8a372014-09-23 09:50:21 -07001839GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001840
bsalomonc21b09e2015-08-28 18:46:56 -07001841const GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001842 SkScalar surfaceScale = d->fRandom->nextSScalar1();
1843 SkScalar ks = d->fRandom->nextUScalar1();
1844 SkScalar shininess = d->fRandom->nextUScalar1();
robertphillips2f0dbc72015-08-20 05:15:06 -07001845 SkAutoTUnref<SkImageFilterLight> light(create_random_light(d->fRandom));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001846 SkMatrix matrix;
1847 for (int i = 0; i < 9; i++) {
joshualitt0067ff52015-07-08 14:26:19 -07001848 matrix[i] = d->fRandom->nextUScalar1();
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001849 }
joshualitt0067ff52015-07-08 14:26:19 -07001850 BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
bsalomon4a339522015-10-06 08:40:50 -07001851 return GrSpecularLightingEffect::Create(d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblancod0d37ca2015-04-02 04:54:56 -07001852 light, surfaceScale, matrix, ks, shininess, mode);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001853}
1854
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001855///////////////////////////////////////////////////////////////////////////////
1856
joshualitteb2a6762014-12-04 11:35:33 -08001857GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1858 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001859}
1860
egdaniel7ea439b2015-12-03 09:20:44 -08001861void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001862 GrGLSLFragmentBuilder* fragBuilder,
1863 SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001864 const char* ks;
1865 const char* shininess;
1866
egdaniel7ea439b2015-12-03 09:20:44 -08001867 fKSUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1868 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
1869 fShininessUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1870 kFloat_GrSLType,
1871 kDefault_GrSLPrecision,
1872 "Shininess",
1873 &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001874
egdaniel0d3f0612015-10-21 10:45:48 -07001875 static const GrGLSLShaderVar gLightArgs[] = {
1876 GrGLSLShaderVar("normal", kVec3f_GrSLType),
1877 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType),
1878 GrGLSLShaderVar("lightColor", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001879 };
1880 SkString lightBody;
1881 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1882 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001883 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1884 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
egdaniel4ca2e602015-11-18 08:01:26 -08001885 fragBuilder->emitFunction(kVec4f_GrSLType,
1886 "light",
1887 SK_ARRAY_COUNT(gLightArgs),
1888 gLightArgs,
1889 lightBody.c_str(),
1890 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001891}
1892
egdaniel018fb622015-10-28 07:26:40 -07001893void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1894 const GrProcessor& effect) {
wangyixb1daa862015-08-18 11:29:31 -07001895 INHERITED::onSetData(pdman, effect);
joshualitt49586be2014-09-16 08:21:41 -07001896 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001897 pdman.set1f(fKSUni, spec.ks());
1898 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001899}
1900
1901///////////////////////////////////////////////////////////////////////////////
egdaniel7ea439b2015-12-03 09:20:44 -08001902void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) {
1903 fColorUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1904 kVec3f_GrSLType, kDefault_GrSLPrecision,
1905 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001906}
1907
egdaniel7ea439b2015-12-03 09:20:44 -08001908void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001909 GrGLSLFragmentBuilder* fragBuilder,
1910 const char *surfaceToLight) {
egdaniel7ea439b2015-12-03 09:20:44 -08001911 fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001912}
1913
egdaniel018fb622015-10-28 07:26:40 -07001914void GrGLLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001915 const SkImageFilterLight* light) const {
robertphillips3d32d762015-07-13 13:16:44 -07001916 setUniformPoint3(pdman, fColorUni,
1917 light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001918}
1919
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001920///////////////////////////////////////////////////////////////////////////////
1921
egdaniel018fb622015-10-28 07:26:40 -07001922void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001923 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001924 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001925 SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001926 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001927 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001928}
1929
egdaniel7ea439b2015-12-03 09:20:44 -08001930void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001931 GrGLSLFragmentBuilder* fragBuilder,
1932 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001933 const char* dir;
egdaniel7ea439b2015-12-03 09:20:44 -08001934 fDirectionUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1935 kVec3f_GrSLType, kDefault_GrSLPrecision,
1936 "LightDirection", &dir);
egdaniel4ca2e602015-11-18 08:01:26 -08001937 fragBuilder->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001938}
1939
1940///////////////////////////////////////////////////////////////////////////////
1941
egdaniel018fb622015-10-28 07:26:40 -07001942void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001943 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001944 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001945 SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001946 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001947 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001948}
1949
egdaniel7ea439b2015-12-03 09:20:44 -08001950void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001951 GrGLSLFragmentBuilder* fragBuilder,
1952 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001953 const char* loc;
egdaniel7ea439b2015-12-03 09:20:44 -08001954 fLocationUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1955 kVec3f_GrSLType, kDefault_GrSLPrecision,
1956 "LightLocation", &loc);
egdaniel4ca2e602015-11-18 08:01:26 -08001957 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1958 loc, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001959}
1960
1961///////////////////////////////////////////////////////////////////////////////
1962
egdaniel018fb622015-10-28 07:26:40 -07001963void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman,
robertphillips2f0dbc72015-08-20 05:15:06 -07001964 const SkImageFilterLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001965 INHERITED::setData(pdman, light);
robertphillips2f0dbc72015-08-20 05:15:06 -07001966 SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001967 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001968 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1969 pdman.set1f(fExponentUni, spotLight->specularExponent());
1970 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1971 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1972 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1973 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001974}
1975
egdaniel7ea439b2015-12-03 09:20:44 -08001976void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001977 GrGLSLFragmentBuilder* fragBuilder,
1978 const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001979 const char* location;
egdaniel7ea439b2015-12-03 09:20:44 -08001980 fLocationUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
1981 kVec3f_GrSLType, kDefault_GrSLPrecision,
1982 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001983
egdaniel4ca2e602015-11-18 08:01:26 -08001984 fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1985 location, fragBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001986}
1987
egdaniel7ea439b2015-12-03 09:20:44 -08001988void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -08001989 GrGLSLFragmentBuilder* fragBuilder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001990 const char *surfaceToLight) {
1991
egdaniel7ea439b2015-12-03 09:20:44 -08001992 const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001993
1994 const char* exponent;
1995 const char* cosInner;
1996 const char* cosOuter;
1997 const char* coneScale;
1998 const char* s;
egdaniel7ea439b2015-12-03 09:20:44 -08001999 fExponentUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
2000 kFloat_GrSLType, kDefault_GrSLPrecision,
2001 "Exponent", &exponent);
2002 fCosInnerConeAngleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
2003 kFloat_GrSLType, kDefault_GrSLPrecision,
2004 "CosInnerConeAngle", &cosInner);
2005 fCosOuterConeAngleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
2006 kFloat_GrSLType, kDefault_GrSLPrecision,
2007 "CosOuterConeAngle", &cosOuter);
2008 fConeScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
2009 kFloat_GrSLType, kDefault_GrSLPrecision,
2010 "ConeScale", &coneScale);
2011 fSUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
2012 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00002013
egdaniel0d3f0612015-10-21 10:45:48 -07002014 static const GrGLSLShaderVar gLightColorArgs[] = {
2015 GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType)
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00002016 };
2017 SkString lightColorBody;
2018 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
2019 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
2020 lightColorBody.appendf("\t\treturn vec3(0);\n");
2021 lightColorBody.appendf("\t}\n");
2022 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
2023 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
2024 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
2025 color, cosOuter, coneScale);
2026 lightColorBody.appendf("\t}\n");
caryclark0bccd872015-10-20 10:04:03 -07002027 lightColorBody.appendf("\treturn %s;\n", color);
egdaniel4ca2e602015-11-18 08:01:26 -08002028 fragBuilder->emitFunction(kVec3f_GrSLType,
2029 "lightColor",
2030 SK_ARRAY_COUNT(gLightColorArgs),
2031 gLightColorArgs,
2032 lightColorBody.c_str(),
2033 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00002034
egdaniel4ca2e602015-11-18 08:01:26 -08002035 fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00002036}
2037
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002038#endif
2039
djsollen@google.com08337772012-06-26 14:33:13 +00002040SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
2041 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
2042 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00002043SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END