blob: 72dcf64c5879faf45195ac58dd38cddaa5d0347c [file] [log] [blame]
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLightingImageFilter.h"
9#include "SkBitmap.h"
10#include "SkColorPriv.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
tomhudson@google.com300f5622012-07-20 14:15:22 +000015#include "SkTypes.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016
17#if SK_SUPPORT_GPU
joshualitteb2a6762014-12-04 11:35:33 -080018#include "GrFragmentProcessor.h"
19#include "GrInvariantOutput.h"
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000020#include "effects/GrSingleTextureEffect.h"
joshualittb0a8a372014-09-23 09:50:21 -070021#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070022#include "gl/builders/GrGLProgramBuilder.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000023
24class GrGLDiffuseLightingEffect;
25class GrGLSpecularLightingEffect;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000026
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000027// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070028typedef GrGLProgramDataManager::UniformHandle UniformHandle;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000029#endif
bsalomon@google.com032b2212012-07-16 13:36:18 +000030
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000031namespace {
32
33const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
34const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000035const SkScalar gOneHalf = 0.5f;
36const SkScalar gOneQuarter = 0.25f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000037
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000038#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070039void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
40 const SkPoint3& point) {
bsalomon@google.comb9119a62012-07-25 17:55:26 +000041 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
kkinnunen7510b222014-07-30 00:04:16 -070042 pdman.set3fv(uni, 1, &point.fX);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000043}
44
joshualittb0a8a372014-09-23 09:50:21 -070045void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
46 const SkPoint3& point) {
kkinnunen7510b222014-07-30 00:04:16 -070047 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000048}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000049#endif
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +000050
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000051// Shift matrix components to the left, as we advance pixels to the right.
52inline void shiftMatrixLeft(int m[9]) {
53 m[0] = m[1];
54 m[3] = m[4];
55 m[6] = m[7];
56 m[1] = m[2];
57 m[4] = m[5];
58 m[7] = m[8];
59}
60
61class DiffuseLightingType {
62public:
63 DiffuseLightingType(SkScalar kd)
64 : fKD(kd) {}
joshualittb0a8a372014-09-23 09:50:21 -070065 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
66 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000067 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
68 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
69 SkPoint3 color(lightColor * colorScale);
70 return SkPackARGB32(255,
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000071 SkClampMax(SkScalarRoundToInt(color.fX), 255),
72 SkClampMax(SkScalarRoundToInt(color.fY), 255),
73 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000074 }
75private:
76 SkScalar fKD;
77};
78
79class SpecularLightingType {
80public:
81 SpecularLightingType(SkScalar ks, SkScalar shininess)
82 : fKS(ks), fShininess(shininess) {}
joshualittb0a8a372014-09-23 09:50:21 -070083 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
84 const SkPoint3& lightColor) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000085 SkPoint3 halfDir(surfaceTolight);
86 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
87 halfDir.normalize();
88 SkScalar colorScale = SkScalarMul(fKS,
89 SkScalarPow(normal.dot(halfDir), fShininess));
90 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
91 SkPoint3 color(lightColor * colorScale);
senorblanco@chromium.orgb9c95972014-03-19 19:44:41 +000092 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
93 SkClampMax(SkScalarRoundToInt(color.fX), 255),
94 SkClampMax(SkScalarRoundToInt(color.fY), 255),
95 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +000096 }
97private:
98 SkScalar fKS;
99 SkScalar fShininess;
100};
101
102inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
103 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
104}
105
106inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
107 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
108 SkScalarMul(-y, surfaceScale),
109 SK_Scalar1);
110 vector.normalize();
111 return vector;
112}
113
114inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
116 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
117 surfaceScale);
118}
119
120inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
122 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
123 surfaceScale);
124}
125
126inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
128 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
129 surfaceScale);
130}
131
132inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
134 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
135 surfaceScale);
136}
137
138
139inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
141 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
142 surfaceScale);
143}
144
145inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
147 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
148 surfaceScale);
149}
150
151inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
153 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
154 surfaceScale);
155}
156
157inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
159 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
160 surfaceScale);
161}
162
163inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
165 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
166 surfaceScale);
167}
168
joshualittb0a8a372014-09-23 09:50:21 -0700169template <class LightingType, class LightType> void lightBitmap(
170 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
171 SkScalar surfaceScale, const SkIRect& bounds) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000172 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000173 const LightType* l = static_cast<const LightType*>(light);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000174 int left = bounds.left(), right = bounds.right();
175 int bottom = bounds.bottom();
176 int y = bounds.top();
177 SkPMColor* dptr = dst->getAddr32(0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000178 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000179 int x = left;
180 const SkPMColor* row1 = src.getAddr32(x, y);
181 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000182 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000183 m[4] = SkGetPackedA32(*row1++);
184 m[5] = SkGetPackedA32(*row1++);
185 m[7] = SkGetPackedA32(*row2++);
186 m[8] = SkGetPackedA32(*row2++);
187 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700188 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
189 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000190 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000191 {
192 shiftMatrixLeft(m);
193 m[5] = SkGetPackedA32(*row1++);
194 m[8] = SkGetPackedA32(*row2++);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000195 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700196 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
197 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000198 }
199 shiftMatrixLeft(m);
200 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700201 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
202 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000203 }
204
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000205 for (++y; y < bottom - 1; ++y) {
206 int x = left;
207 const SkPMColor* row0 = src.getAddr32(x, y - 1);
208 const SkPMColor* row1 = src.getAddr32(x, y);
209 const SkPMColor* row2 = src.getAddr32(x, y + 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000210 int m[9];
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000211 m[1] = SkGetPackedA32(*row0++);
212 m[2] = SkGetPackedA32(*row0++);
213 m[4] = SkGetPackedA32(*row1++);
214 m[5] = SkGetPackedA32(*row1++);
215 m[7] = SkGetPackedA32(*row2++);
216 m[8] = SkGetPackedA32(*row2++);
217 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700218 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
219 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000220 for (++x; x < right - 1; ++x) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000221 shiftMatrixLeft(m);
222 m[2] = SkGetPackedA32(*row0++);
223 m[5] = SkGetPackedA32(*row1++);
224 m[8] = SkGetPackedA32(*row2++);
225 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700226 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
227 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000228 }
229 shiftMatrixLeft(m);
230 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700231 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
232 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000233 }
234
235 {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000236 int x = left;
237 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
238 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000239 int m[9];
240 m[1] = SkGetPackedA32(*row0++);
241 m[2] = SkGetPackedA32(*row0++);
242 m[4] = SkGetPackedA32(*row1++);
243 m[5] = SkGetPackedA32(*row1++);
244 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700245 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
246 l->lightColor(surfaceToLight));
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000247 for (++x; x < right - 1; ++x)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000248 {
249 shiftMatrixLeft(m);
250 m[2] = SkGetPackedA32(*row0++);
251 m[5] = SkGetPackedA32(*row1++);
252 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700253 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
254 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000255 }
256 shiftMatrixLeft(m);
257 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
joshualittb0a8a372014-09-23 09:50:21 -0700258 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
259 l->lightColor(surfaceToLight));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000260 }
261}
262
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000263SkPoint3 readPoint3(SkReadBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000264 SkPoint3 point;
265 point.fX = buffer.readScalar();
266 point.fY = buffer.readScalar();
267 point.fZ = buffer.readScalar();
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000268 buffer.validate(SkScalarIsFinite(point.fX) &&
269 SkScalarIsFinite(point.fY) &&
270 SkScalarIsFinite(point.fZ));
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000271 return point;
272};
273
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000274void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000275 buffer.writeScalar(point.fX);
276 buffer.writeScalar(point.fY);
277 buffer.writeScalar(point.fZ);
278};
279
280class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
281public:
reed9fa60da2014-08-21 07:59:51 -0700282 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
senorblanco24e06d52015-03-18 12:11:33 -0700283 const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700284
robertphillipsf3f5bad2014-12-19 13:49:15 -0800285 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000286 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000287 SkScalar kd() const { return fKD; }
288
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000289protected:
reed9fa60da2014-08-21 07:59:51 -0700290 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700291 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
mtklein36352bf2015-03-25 18:17:31 -0700292 void flatten(SkWriteBuffer& buffer) const override;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000293 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
mtklein36352bf2015-03-25 18:17:31 -0700294 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000295#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700296 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
mtklein36352bf2015-03-25 18:17:31 -0700297 const SkIRect& bounds) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000298#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000299
300private:
reed9fa60da2014-08-21 07:59:51 -0700301 friend class SkLightingImageFilter;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000302 typedef SkLightingImageFilter INHERITED;
303 SkScalar fKD;
304};
305
306class SkSpecularLightingImageFilter : public SkLightingImageFilter {
307public:
reed9fa60da2014-08-21 07:59:51 -0700308 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700309 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*);
reed9fa60da2014-08-21 07:59:51 -0700310
robertphillipsf3f5bad2014-12-19 13:49:15 -0800311 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000312 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
313
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000314 SkScalar ks() const { return fKS; }
315 SkScalar shininess() const { return fShininess; }
316
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000317protected:
reed9fa60da2014-08-21 07:59:51 -0700318 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
senorblanco24e06d52015-03-18 12:11:33 -0700319 SkScalar shininess, SkImageFilter* input, const CropRect*);
mtklein36352bf2015-03-25 18:17:31 -0700320 void flatten(SkWriteBuffer& buffer) const override;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000321 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
mtklein36352bf2015-03-25 18:17:31 -0700322 SkBitmap* result, SkIPoint* offset) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000323#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -0700324 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
mtklein36352bf2015-03-25 18:17:31 -0700325 const SkIRect& bounds) const override;
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000326#endif
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000327
328private:
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000329 SkScalar fKS;
330 SkScalar fShininess;
reed9fa60da2014-08-21 07:59:51 -0700331 friend class SkLightingImageFilter;
332 typedef SkLightingImageFilter INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000333};
334
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000335#if SK_SUPPORT_GPU
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000336
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000337class GrLightingEffect : public GrSingleTextureEffect {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000338public:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000339 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000340 virtual ~GrLightingEffect();
341
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000342 const SkLight* light() const { return fLight; }
343 SkScalar surfaceScale() const { return fSurfaceScale; }
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000344 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
bsalomon@google.com371e1052013-01-11 21:08:55 +0000345
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000346protected:
mtklein36352bf2015-03-25 18:17:31 -0700347 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000348
mtklein36352bf2015-03-25 18:17:31 -0700349 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700350 // lighting shaders are complicated. We just throw up our hands.
joshualitt56995b52014-12-11 15:44:02 -0800351 inout->mulByUnknownFourComponents();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700352 }
353
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000354private:
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000355 typedef GrSingleTextureEffect INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000356 const SkLight* fLight;
357 SkScalar fSurfaceScale;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000358 SkMatrix fFilterMatrix;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000359};
360
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000361class GrDiffuseLightingEffect : public GrLightingEffect {
362public:
joshualittb0a8a372014-09-23 09:50:21 -0700363 static GrFragmentProcessor* Create(GrTexture* texture,
364 const SkLight* light,
365 SkScalar surfaceScale,
366 const SkMatrix& matrix,
367 SkScalar kd) {
bsalomon55fad7a2014-07-08 07:34:20 -0700368 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
369 light,
370 surfaceScale,
371 matrix,
372 kd));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000373 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000374
mtklein36352bf2015-03-25 18:17:31 -0700375 const char* name() const override { return "DiffuseLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000376
mtklein36352bf2015-03-25 18:17:31 -0700377 void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000378
mtklein36352bf2015-03-25 18:17:31 -0700379 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800380
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000381 SkScalar kd() const { return fKD; }
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000382
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000383private:
mtklein36352bf2015-03-25 18:17:31 -0700384 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000385
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000386 GrDiffuseLightingEffect(GrTexture* texture,
387 const SkLight* light,
388 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000389 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000390 SkScalar kd);
391
joshualittb0a8a372014-09-23 09:50:21 -0700392 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000393 typedef GrLightingEffect INHERITED;
394 SkScalar fKD;
395};
396
397class GrSpecularLightingEffect : public GrLightingEffect {
398public:
joshualittb0a8a372014-09-23 09:50:21 -0700399 static GrFragmentProcessor* Create(GrTexture* texture,
400 const SkLight* light,
401 SkScalar surfaceScale,
402 const SkMatrix& matrix,
403 SkScalar ks,
404 SkScalar shininess) {
bsalomon55fad7a2014-07-08 07:34:20 -0700405 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
406 light,
407 surfaceScale,
408 matrix,
409 ks,
410 shininess));
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000411 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000412
mtklein36352bf2015-03-25 18:17:31 -0700413 const char* name() const override { return "SpecularLighting"; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000414
mtklein36352bf2015-03-25 18:17:31 -0700415 void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800416
mtklein36352bf2015-03-25 18:17:31 -0700417 GrGLFragmentProcessor* createGLInstance() const override;
joshualitteb2a6762014-12-04 11:35:33 -0800418
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000419 SkScalar ks() const { return fKS; }
420 SkScalar shininess() const { return fShininess; }
421
422private:
mtklein36352bf2015-03-25 18:17:31 -0700423 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000424
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000425 GrSpecularLightingEffect(GrTexture* texture,
426 const SkLight* light,
427 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000428 const SkMatrix& matrix,
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000429 SkScalar ks,
430 SkScalar shininess);
431
joshualittb0a8a372014-09-23 09:50:21 -0700432 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000433 typedef GrLightingEffect INHERITED;
434 SkScalar fKS;
435 SkScalar fShininess;
436};
437
438///////////////////////////////////////////////////////////////////////////////
439
440class GrGLLight {
441public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000442 virtual ~GrGLLight() {}
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000443
444 /**
445 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
446 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
447 */
joshualitt15988992014-10-09 15:04:05 -0700448 void emitLightColorUniform(GrGLFPBuilder*);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000449
skia.committer@gmail.come862d162012-10-31 02:01:18 +0000450 /**
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000451 * These two functions are called from GrGLLightingEffect's emitCode() function.
452 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
453 * the light. The expression will be used in the FS. emitLightColor writes an expression into
454 * the FS that is the color of the light. Either function may add functions and/or uniforms to
455 * the FS. The default of emitLightColor appends the name of the constant light color uniform
456 * and so this function only needs to be overridden if the light color varies spatially.
457 */
joshualitt15988992014-10-09 15:04:05 -0700458 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
459 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000460
461 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
462 // INHERITED::setData().
kkinnunen7510b222014-07-30 00:04:16 -0700463 virtual void setData(const GrGLProgramDataManager&,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000464 const SkLight* light) const;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000465
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000466protected:
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000467 /**
468 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
469 * function.
470 */
471 UniformHandle lightColorUni() const { return fColorUni; }
472
473private:
bsalomon@google.com032b2212012-07-16 13:36:18 +0000474 UniformHandle fColorUni;
bsalomon@google.comae5ef112012-10-29 14:53:53 +0000475
476 typedef SkRefCnt INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000477};
478
479///////////////////////////////////////////////////////////////////////////////
480
481class GrGLDistantLight : public GrGLLight {
482public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000483 virtual ~GrGLDistantLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700484 virtual void setData(const GrGLProgramDataManager&,
mtklein36352bf2015-03-25 18:17:31 -0700485 const SkLight* light) const override;
486 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000487
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000488private:
489 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000490 UniformHandle fDirectionUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000491};
492
493///////////////////////////////////////////////////////////////////////////////
494
495class GrGLPointLight : public GrGLLight {
496public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000497 virtual ~GrGLPointLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700498 virtual void setData(const GrGLProgramDataManager&,
mtklein36352bf2015-03-25 18:17:31 -0700499 const SkLight* light) const override;
500 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000501
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000502private:
503 typedef GrGLLight INHERITED;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000504 UniformHandle fLocationUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000505};
506
507///////////////////////////////////////////////////////////////////////////////
508
509class GrGLSpotLight : public GrGLLight {
510public:
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000511 virtual ~GrGLSpotLight() {}
kkinnunen7510b222014-07-30 00:04:16 -0700512 virtual void setData(const GrGLProgramDataManager&,
mtklein36352bf2015-03-25 18:17:31 -0700513 const SkLight* light) const override;
514 void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override;
515 void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override;
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000516
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000517private:
518 typedef GrGLLight INHERITED;
519
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000520 SkString fLightColorFunc;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000521 UniformHandle fLocationUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000522 UniformHandle fExponentUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000523 UniformHandle fCosOuterConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000524 UniformHandle fCosInnerConeAngleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000525 UniformHandle fConeScaleUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000526 UniformHandle fSUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000527};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000528#else
529
530class GrGLLight;
531
532#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000533
534};
535
536///////////////////////////////////////////////////////////////////////////////
537
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000538class SkLight : public SkRefCnt {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000539public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +0000540 SK_DECLARE_INST_COUNT(SkLight)
541
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000542 enum LightType {
543 kDistant_LightType,
544 kPoint_LightType,
545 kSpot_LightType,
546 };
547 virtual LightType type() const = 0;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000548 const SkPoint3& color() const { return fColor; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000549 virtual GrGLLight* createGLLight() const = 0;
550 virtual bool isEqual(const SkLight& other) const {
551 return fColor == other.fColor;
552 }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000553 // Called to know whether the generated GrGLLight will require access to the fragment position.
554 virtual bool requiresFragmentPosition() const = 0;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000555 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000556
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000557 // Defined below SkLight's subclasses.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000558 void flattenLight(SkWriteBuffer& buffer) const;
559 static SkLight* UnflattenLight(SkReadBuffer& buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000560
djsollen@google.com08337772012-06-26 14:33:13 +0000561protected:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000562 SkLight(SkColor color)
563 : fColor(SkIntToScalar(SkColorGetR(color)),
564 SkIntToScalar(SkColorGetG(color)),
565 SkIntToScalar(SkColorGetB(color))) {}
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000566 SkLight(const SkPoint3& color)
567 : fColor(color) {}
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000568 SkLight(SkReadBuffer& buffer) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000569 fColor = readPoint3(buffer);
570 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000571
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000572 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000573
djsollen@google.com08337772012-06-26 14:33:13 +0000574
575private:
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000576 typedef SkRefCnt INHERITED;
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000577 SkPoint3 fColor;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000578};
579
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000580///////////////////////////////////////////////////////////////////////////////
581
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000582class SkDistantLight : public SkLight {
583public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000584 SkDistantLight(const SkPoint3& direction, SkColor color)
585 : INHERITED(color), fDirection(direction) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000586 }
djsollen@google.com08337772012-06-26 14:33:13 +0000587
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000588 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
589 return fDirection;
590 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000591 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700592 LightType type() const override { return kDistant_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000593 const SkPoint3& direction() const { return fDirection; }
mtklein36352bf2015-03-25 18:17:31 -0700594 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000595#if SK_SUPPORT_GPU
596 return SkNEW(GrGLDistantLight);
597#else
598 SkDEBUGFAIL("Should not call in GPU-less build");
599 return NULL;
600#endif
601 }
mtklein36352bf2015-03-25 18:17:31 -0700602 bool requiresFragmentPosition() const override { return false; }
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000603
mtklein36352bf2015-03-25 18:17:31 -0700604 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org6730cbb2012-07-11 16:35:00 +0000605 if (other.type() != kDistant_LightType) {
606 return false;
607 }
608
609 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
610 return INHERITED::isEqual(other) &&
611 fDirection == o.fDirection;
612 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000613
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000614 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000615 fDirection = readPoint3(buffer);
616 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000617
djsollen@google.com08337772012-06-26 14:33:13 +0000618protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000619 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
620 : INHERITED(color), fDirection(direction) {
621 }
mtklein36352bf2015-03-25 18:17:31 -0700622 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000623 return new SkDistantLight(direction(), color());
624 }
mtklein36352bf2015-03-25 18:17:31 -0700625 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000626 writePoint3(fDirection, buffer);
627 }
628
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000629private:
djsollen@google.com08337772012-06-26 14:33:13 +0000630 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000631 SkPoint3 fDirection;
632};
633
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000634///////////////////////////////////////////////////////////////////////////////
635
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000636class SkPointLight : public SkLight {
637public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000638 SkPointLight(const SkPoint3& location, SkColor color)
639 : INHERITED(color), fLocation(location) {}
djsollen@google.com08337772012-06-26 14:33:13 +0000640
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000641 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
642 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
643 fLocation.fY - SkIntToScalar(y),
644 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
645 direction.normalize();
646 return direction;
647 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000648 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
mtklein36352bf2015-03-25 18:17:31 -0700649 LightType type() const override { return kPoint_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000650 const SkPoint3& location() const { return fLocation; }
mtklein36352bf2015-03-25 18:17:31 -0700651 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000652#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000653 return SkNEW(GrGLPointLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000654#else
655 SkDEBUGFAIL("Should not call in GPU-less build");
656 return NULL;
657#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000658 }
mtklein36352bf2015-03-25 18:17:31 -0700659 bool requiresFragmentPosition() const override { return true; }
660 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000661 if (other.type() != kPoint_LightType) {
662 return false;
663 }
664 const SkPointLight& o = static_cast<const SkPointLight&>(other);
665 return INHERITED::isEqual(other) &&
666 fLocation == o.fLocation;
667 }
mtklein36352bf2015-03-25 18:17:31 -0700668 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000669 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
670 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000671 // Use X scale and Y scale on Z and average the result
672 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
673 matrix.mapVectors(&locationZ, 1);
674 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000675 return new SkPointLight(location, color());
676 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000677
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000678 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000679 fLocation = readPoint3(buffer);
680 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000681
682protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000683 SkPointLight(const SkPoint3& location, const SkPoint3& color)
684 : INHERITED(color), fLocation(location) {}
mtklein36352bf2015-03-25 18:17:31 -0700685 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000686 writePoint3(fLocation, buffer);
687 }
688
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000689private:
djsollen@google.com08337772012-06-26 14:33:13 +0000690 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000691 SkPoint3 fLocation;
692};
693
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000694///////////////////////////////////////////////////////////////////////////////
695
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000696class SkSpotLight : public SkLight {
697public:
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000698 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
699 : INHERITED(color),
700 fLocation(location),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000701 fTarget(target),
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000702 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000703 {
704 fS = target - location;
705 fS.normalize();
706 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000707 const SkScalar antiAliasThreshold = 0.016f;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000708 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
709 fConeScale = SkScalarInvert(antiAliasThreshold);
710 }
djsollen@google.com08337772012-06-26 14:33:13 +0000711
mtklein36352bf2015-03-25 18:17:31 -0700712 SkLight* transform(const SkMatrix& matrix) const override {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000713 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
714 matrix.mapPoints(&location2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000715 // Use X scale and Y scale on Z and average the result
716 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
717 matrix.mapVectors(&locationZ, 1);
718 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000719 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
720 matrix.mapPoints(&target2, 1);
commit-bot@chromium.org1037d922014-03-13 19:45:41 +0000721 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
722 matrix.mapVectors(&targetZ, 1);
723 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
724 SkPoint3 s = target - location;
725 s.normalize();
726 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000727 }
728
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000729 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
730 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
731 fLocation.fY - SkIntToScalar(y),
732 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
733 direction.normalize();
734 return direction;
735 };
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000736 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000737 SkScalar cosAngle = -surfaceToLight.dot(fS);
738 if (cosAngle < fCosOuterConeAngle) {
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000739 return SkPoint3(0, 0, 0);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000740 }
741 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
742 if (cosAngle < fCosInnerConeAngle) {
743 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000744 return color() * SkScalarMul(scale, fConeScale);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000745 }
senorblanco@chromium.orgbdb1ec42012-07-09 14:29:51 +0000746 return color() * scale;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000747 }
mtklein36352bf2015-03-25 18:17:31 -0700748 GrGLLight* createGLLight() const override {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000749#if SK_SUPPORT_GPU
tomhudson@google.com300f5622012-07-20 14:15:22 +0000750 return SkNEW(GrGLSpotLight);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000751#else
752 SkDEBUGFAIL("Should not call in GPU-less build");
753 return NULL;
754#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000755 }
mtklein36352bf2015-03-25 18:17:31 -0700756 bool requiresFragmentPosition() const override { return true; }
757 LightType type() const override { return kSpot_LightType; }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000758 const SkPoint3& location() const { return fLocation; }
759 const SkPoint3& target() const { return fTarget; }
760 SkScalar specularExponent() const { return fSpecularExponent; }
761 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
762 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
763 SkScalar coneScale() const { return fConeScale; }
senorblanco@chromium.orgeb311842012-07-11 20:49:26 +0000764 const SkPoint3& s() const { return fS; }
djsollen@google.com08337772012-06-26 14:33:13 +0000765
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000766 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
djsollen@google.com08337772012-06-26 14:33:13 +0000767 fLocation = readPoint3(buffer);
768 fTarget = readPoint3(buffer);
769 fSpecularExponent = buffer.readScalar();
770 fCosOuterConeAngle = buffer.readScalar();
771 fCosInnerConeAngle = buffer.readScalar();
772 fConeScale = buffer.readScalar();
773 fS = readPoint3(buffer);
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000774 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
775 SkScalarIsFinite(fCosOuterConeAngle) &&
776 SkScalarIsFinite(fCosInnerConeAngle) &&
777 SkScalarIsFinite(fConeScale));
djsollen@google.com08337772012-06-26 14:33:13 +0000778 }
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000779protected:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000780 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
781 : INHERITED(color),
782 fLocation(location),
783 fTarget(target),
784 fSpecularExponent(specularExponent),
785 fCosOuterConeAngle(cosOuterConeAngle),
786 fCosInnerConeAngle(cosInnerConeAngle),
787 fConeScale(coneScale),
788 fS(s)
789 {
790 }
mtklein36352bf2015-03-25 18:17:31 -0700791 void onFlattenLight(SkWriteBuffer& buffer) const override {
djsollen@google.com08337772012-06-26 14:33:13 +0000792 writePoint3(fLocation, buffer);
793 writePoint3(fTarget, buffer);
794 buffer.writeScalar(fSpecularExponent);
795 buffer.writeScalar(fCosOuterConeAngle);
796 buffer.writeScalar(fCosInnerConeAngle);
797 buffer.writeScalar(fConeScale);
798 writePoint3(fS, buffer);
799 }
800
mtklein36352bf2015-03-25 18:17:31 -0700801 bool isEqual(const SkLight& other) const override {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000802 if (other.type() != kSpot_LightType) {
803 return false;
804 }
805
806 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
807 return INHERITED::isEqual(other) &&
808 fLocation == o.fLocation &&
809 fTarget == o.fTarget &&
810 fSpecularExponent == o.fSpecularExponent &&
811 fCosOuterConeAngle == o.fCosOuterConeAngle;
812 }
813
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000814private:
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000815 static const SkScalar kSpecularExponentMin;
816 static const SkScalar kSpecularExponentMax;
817
djsollen@google.com08337772012-06-26 14:33:13 +0000818 typedef SkLight INHERITED;
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000819 SkPoint3 fLocation;
820 SkPoint3 fTarget;
821 SkScalar fSpecularExponent;
822 SkScalar fCosOuterConeAngle;
823 SkScalar fCosInnerConeAngle;
824 SkScalar fConeScale;
825 SkPoint3 fS;
826};
827
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000828// According to the spec, the specular term should be in the range [1, 128] :
829// http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000830const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
831const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000832
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000833///////////////////////////////////////////////////////////////////////////////
834
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000835void SkLight::flattenLight(SkWriteBuffer& buffer) const {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000836 // Write type first, then baseclass, then subclass.
837 buffer.writeInt(this->type());
838 writePoint3(fColor, buffer);
839 this->onFlattenLight(buffer);
840}
841
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000842/*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000843 // Read type first.
844 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
845 switch (type) {
846 // Each of these constructors must first call SkLight's, so we'll read the baseclass
847 // then subclass, same order as flattenLight.
848 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
849 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
850 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
851 default:
852 SkDEBUGFAIL("Unknown LightType.");
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000853 buffer.validate(false);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000854 return NULL;
855 }
856}
857///////////////////////////////////////////////////////////////////////////////
858
senorblanco9ea3d572014-07-08 09:16:22 -0700859SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700860 SkImageFilter* input, const CropRect* cropRect)
861 : INHERITED(1, &input, cropRect)
reed9fa60da2014-08-21 07:59:51 -0700862 , fLight(SkRef(light))
863 , fSurfaceScale(surfaceScale / 255)
864{}
865
866SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
867 SkColor lightColor,
868 SkScalar surfaceScale,
869 SkScalar kd,
870 SkImageFilter* input,
871 const CropRect* cropRect) {
872 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
873 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000874}
875
reed9fa60da2014-08-21 07:59:51 -0700876SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
877 SkColor lightColor,
878 SkScalar surfaceScale,
879 SkScalar kd,
880 SkImageFilter* input,
881 const CropRect* cropRect) {
882 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
883 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000884}
885
reed9fa60da2014-08-21 07:59:51 -0700886SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
887 const SkPoint3& target,
888 SkScalar specularExponent,
889 SkScalar cutoffAngle,
890 SkColor lightColor,
891 SkScalar surfaceScale,
892 SkScalar kd,
893 SkImageFilter* input,
894 const CropRect* cropRect) {
895 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
896 cutoffAngle, lightColor)));
897 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000898}
899
reed9fa60da2014-08-21 07:59:51 -0700900SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
901 SkColor lightColor,
902 SkScalar surfaceScale,
903 SkScalar ks,
904 SkScalar shine,
905 SkImageFilter* input,
906 const CropRect* cropRect) {
907 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
908 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000909}
910
reed9fa60da2014-08-21 07:59:51 -0700911SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
912 SkColor lightColor,
913 SkScalar surfaceScale,
914 SkScalar ks,
915 SkScalar shine,
916 SkImageFilter* input,
917 const CropRect* cropRect) {
918 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
919 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000920}
921
reed9fa60da2014-08-21 07:59:51 -0700922SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
923 const SkPoint3& target,
924 SkScalar specularExponent,
925 SkScalar cutoffAngle,
926 SkColor lightColor,
927 SkScalar surfaceScale,
928 SkScalar ks,
929 SkScalar shine,
930 SkImageFilter* input,
931 const CropRect* cropRect) {
932 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
933 cutoffAngle, lightColor)));
934 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000935}
936
reed9fa60da2014-08-21 07:59:51 -0700937SkLightingImageFilter::~SkLightingImageFilter() {}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000938
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000939void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000940 this->INHERITED::flatten(buffer);
commit-bot@chromium.org790c3f42013-10-14 16:28:56 +0000941 fLight->flattenLight(buffer);
reed9fa60da2014-08-21 07:59:51 -0700942 buffer.writeScalar(fSurfaceScale * 255);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000943}
944
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000945///////////////////////////////////////////////////////////////////////////////
946
reed9fa60da2014-08-21 07:59:51 -0700947SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -0700948 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -0700949 if (NULL == light) {
950 return NULL;
951 }
952 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
953 return NULL;
954 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000955 // According to the spec, kd can be any non-negative number :
956 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
reed9fa60da2014-08-21 07:59:51 -0700957 if (kd < 0) {
958 return NULL;
959 }
senorblanco24e06d52015-03-18 12:11:33 -0700960 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -0700961}
962
senorblanco24e06d52015-03-18 12:11:33 -0700963SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect)
964 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -0700965 fKD(kd)
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000966{
967}
968
reed9fa60da2014-08-21 07:59:51 -0700969SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
970 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
971 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
972 SkScalar surfaceScale = buffer.readScalar();
973 SkScalar kd = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -0700974 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -0700975}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000976
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000977void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000978 this->INHERITED::flatten(buffer);
979 buffer.writeScalar(fKD);
980}
981
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000982bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
983 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000984 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000985 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000986 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000987 SkImageFilter* input = getInput(0);
988 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000989 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000990 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +0000991 return false;
992 }
993
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000994 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000995 return false;
996 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000997 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000998 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +0000999 return false;
1000 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001001
1002 if (bounds.width() < 2 || bounds.height() < 2) {
1003 return false;
1004 }
1005
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001006 SkAutoLockPixels alp(src);
1007 if (!src.getPixels()) {
1008 return false;
1009 }
1010
reed84825042014-09-02 12:50:45 -07001011 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001012 return false;
1013 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001014
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001015 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001016
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001017 DiffuseLightingType lightingType(fKD);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001018 offset->fX = bounds.left();
1019 offset->fY = bounds.top();
1020 bounds.offset(-srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001021 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001022 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001023 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001024 break;
1025 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001026 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001027 break;
1028 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001029 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001030 break;
1031 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001032
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001033 return true;
1034}
1035
robertphillipsf3f5bad2014-12-19 13:49:15 -08001036#ifndef SK_IGNORE_TO_STRING
1037void SkDiffuseLightingImageFilter::toString(SkString* str) const {
1038 str->appendf("SkDiffuseLightingImageFilter: (");
1039 str->appendf("kD: %f\n", fKD);
1040 str->append(")");
1041}
1042#endif
1043
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001044#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001045bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1046 GrTexture* texture,
1047 const SkMatrix& matrix,
1048 const SkIRect&) const {
1049 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001050 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001051 *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001052 }
1053 return true;
1054}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001055#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001056
1057///////////////////////////////////////////////////////////////////////////////
1058
reed9fa60da2014-08-21 07:59:51 -07001059SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
senorblanco24e06d52015-03-18 12:11:33 -07001060 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
reed9fa60da2014-08-21 07:59:51 -07001061 if (NULL == light) {
1062 return NULL;
1063 }
1064 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1065 return NULL;
1066 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +00001067 // According to the spec, ks can be any non-negative number :
1068 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
reed9fa60da2014-08-21 07:59:51 -07001069 if (ks < 0) {
1070 return NULL;
1071 }
1072 return SkNEW_ARGS(SkSpecularLightingImageFilter,
senorblanco24e06d52015-03-18 12:11:33 -07001073 (light, surfaceScale, ks, shininess, input, cropRect));
reed9fa60da2014-08-21 07:59:51 -07001074}
1075
senorblanco24e06d52015-03-18 12:11:33 -07001076SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
1077 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
reed9fa60da2014-08-21 07:59:51 -07001078 fKS(ks),
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001079 fShininess(shininess)
1080{
1081}
1082
reed9fa60da2014-08-21 07:59:51 -07001083SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1084 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1085 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1086 SkScalar surfaceScale = buffer.readScalar();
1087 SkScalar ks = buffer.readScalar();
1088 SkScalar shine = buffer.readScalar();
senorblanco24e06d52015-03-18 12:11:33 -07001089 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -07001090}
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001091
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00001092void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001093 this->INHERITED::flatten(buffer);
1094 buffer.writeScalar(fKS);
1095 buffer.writeScalar(fShininess);
1096}
1097
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001098bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1099 const SkBitmap& source,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001100 const Context& ctx,
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001101 SkBitmap* dst,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001102 SkIPoint* offset) const {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001103 SkImageFilter* input = getInput(0);
1104 SkBitmap src = source;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001105 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001106 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
commit-bot@chromium.orga8aef8b2013-10-23 15:33:44 +00001107 return false;
1108 }
1109
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00001110 if (src.colorType() != kN32_SkColorType) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001111 return false;
1112 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001113
1114 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001115 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001116 return false;
1117 }
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001118
1119 if (bounds.width() < 2 || bounds.height() < 2) {
1120 return false;
1121 }
1122
senorblanco@chromium.org11825292014-03-14 17:44:41 +00001123 SkAutoLockPixels alp(src);
1124 if (!src.getPixels()) {
1125 return false;
1126 }
1127
reed84825042014-09-02 12:50:45 -07001128 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00001129 return false;
1130 }
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001131
1132 SpecularLightingType lightingType(fKS, fShininess);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001133 offset->fX = bounds.left();
1134 offset->fY = bounds.top();
1135 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001136 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001137 switch (transformedLight->type()) {
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001138 case SkLight::kDistant_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001139 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001140 break;
1141 case SkLight::kPoint_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001142 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001143 break;
1144 case SkLight::kSpot_LightType:
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001145 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
senorblanco@chromium.orgf49b4292012-06-22 21:01:23 +00001146 break;
1147 }
1148 return true;
1149}
1150
robertphillipsf3f5bad2014-12-19 13:49:15 -08001151#ifndef SK_IGNORE_TO_STRING
1152void SkSpecularLightingImageFilter::toString(SkString* str) const {
1153 str->appendf("SkSpecularLightingImageFilter: (");
1154 str->appendf("kS: %f shininess: %f", fKS, fShininess);
1155 str->append(")");
1156}
1157#endif
1158
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001159#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -07001160bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1161 GrTexture* texture,
1162 const SkMatrix& matrix,
1163 const SkIRect&) const {
1164 if (fp) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001165 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
joshualittb0a8a372014-09-23 09:50:21 -07001166 *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001167 }
1168 return true;
1169}
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +00001170#endif
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001171
1172///////////////////////////////////////////////////////////////////////////////
1173
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001174#if SK_SUPPORT_GPU
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001175
1176namespace {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001177SkPoint3 random_point3(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001178 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1179 SkScalarToFloat(random->nextSScalar1()),
1180 SkScalarToFloat(random->nextSScalar1()));
1181}
1182
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +00001183SkLight* create_random_light(SkRandom* random) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001184 int type = random->nextULessThan(3);
1185 switch (type) {
1186 case 0: {
1187 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1188 }
1189 case 1: {
1190 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1191 }
1192 case 2: {
1193 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1194 random_point3(random),
1195 random->nextUScalar1(),
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001196 random->nextUScalar1(),
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001197 random->nextU()));
1198 }
1199 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +00001200 SkFAIL("Unexpected value.");
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001201 return NULL;
1202 }
1203}
1204
1205}
1206
joshualittb0a8a372014-09-23 09:50:21 -07001207class GrGLLightingEffect : public GrGLFragmentProcessor {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001208public:
joshualitteb2a6762014-12-04 11:35:33 -08001209 GrGLLightingEffect(const GrProcessor&);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001210 virtual ~GrGLLightingEffect();
1211
joshualitt15988992014-10-09 15:04:05 -07001212 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -07001213 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001214 const char* outputColor,
1215 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001216 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -07001217 const TextureSamplerArray&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001218
joshualittb0a8a372014-09-23 09:50:21 -07001219 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001220
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001221 /**
1222 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1223 */
mtklein36352bf2015-03-25 18:17:31 -07001224 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001225
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001226protected:
joshualitt15988992014-10-09 15:04:05 -07001227 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001228
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001229private:
joshualittb0a8a372014-09-23 09:50:21 -07001230 typedef GrGLFragmentProcessor INHERITED;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001231
bsalomon@google.com17fc6512012-11-02 21:45:01 +00001232 UniformHandle fImageIncrementUni;
1233 UniformHandle fSurfaceScaleUni;
1234 GrGLLight* fLight;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001235};
1236
1237///////////////////////////////////////////////////////////////////////////////
1238
1239class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1240public:
joshualitteb2a6762014-12-04 11:35:33 -08001241 GrGLDiffuseLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001242 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1243 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001244
1245private:
1246 typedef GrGLLightingEffect INHERITED;
1247
bsalomon@google.com032b2212012-07-16 13:36:18 +00001248 UniformHandle fKDUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001249};
1250
1251///////////////////////////////////////////////////////////////////////////////
1252
1253class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1254public:
joshualitteb2a6762014-12-04 11:35:33 -08001255 GrGLSpecularLightingEffect(const GrProcessor&);
mtklein36352bf2015-03-25 18:17:31 -07001256 void emitLightFunc(GrGLFPBuilder*, SkString* funcName) override;
1257 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001258
1259private:
1260 typedef GrGLLightingEffect INHERITED;
1261
bsalomon@google.com032b2212012-07-16 13:36:18 +00001262 UniformHandle fKSUni;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001263 UniformHandle fShininessUni;
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001264};
1265
1266///////////////////////////////////////////////////////////////////////////////
1267
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001268GrLightingEffect::GrLightingEffect(GrTexture* texture,
1269 const SkLight* light,
1270 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001271 const SkMatrix& matrix)
bsalomon6267f812014-08-29 15:05:53 -07001272 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
tomhudson@google.comd0c1a062012-07-12 17:23:52 +00001273 , fLight(light)
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001274 , fSurfaceScale(surfaceScale)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001275 , fFilterMatrix(matrix) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001276 fLight->ref();
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +00001277 if (light->requiresFragmentPosition()) {
1278 this->setWillReadFragmentPosition();
1279 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001280}
1281
1282GrLightingEffect::~GrLightingEffect() {
1283 fLight->unref();
1284}
1285
bsalomon0e08fc12014-10-15 08:19:04 -07001286bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001287 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
bsalomon420d7e92014-10-16 09:18:09 -07001288 return fLight->isEqual(*s.fLight) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001289 fSurfaceScale == s.fSurfaceScale;
1290}
1291
1292///////////////////////////////////////////////////////////////////////////////
1293
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001294GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1295 const SkLight* light,
1296 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001297 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001298 SkScalar kd)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001299 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
joshualitteb2a6762014-12-04 11:35:33 -08001300 this->initClassID<GrDiffuseLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001301}
1302
bsalomon0e08fc12014-10-15 08:19:04 -07001303bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001304 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001305 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001306 this->kd() == s.kd();
1307}
1308
joshualitteb2a6762014-12-04 11:35:33 -08001309void GrDiffuseLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1310 GrProcessorKeyBuilder* b) const {
1311 GrGLDiffuseLightingEffect::GenKey(*this, caps, b);
1312}
1313
1314GrGLFragmentProcessor* GrDiffuseLightingEffect::createGLInstance() const {
1315 return SkNEW_ARGS(GrGLDiffuseLightingEffect, (*this));
1316}
1317
joshualittb0a8a372014-09-23 09:50:21 -07001318GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001319
joshualittb0a8a372014-09-23 09:50:21 -07001320GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
bsalomon83d081a2014-07-08 09:56:10 -07001321 GrContext* context,
1322 const GrDrawTargetCaps&,
1323 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001324 SkScalar surfaceScale = random->nextSScalar1();
1325 SkScalar kd = random->nextUScalar1();
1326 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001327 SkMatrix matrix;
1328 for (int i = 0; i < 9; i++) {
1329 matrix[i] = random->nextUScalar1();
1330 }
joshualittb0a8a372014-09-23 09:50:21 -07001331 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001332 light, surfaceScale, matrix, kd);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001333}
1334
1335
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001336///////////////////////////////////////////////////////////////////////////////
1337
joshualitteb2a6762014-12-04 11:35:33 -08001338GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) {
joshualittb0a8a372014-09-23 09:50:21 -07001339 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001340 fLight = m.light()->createGLLight();
1341}
1342
1343GrGLLightingEffect::~GrGLLightingEffect() {
1344 delete fLight;
1345}
1346
joshualitt15988992014-10-09 15:04:05 -07001347void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -07001348 const GrFragmentProcessor&,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001349 const char* outputColor,
1350 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +00001351 const TransformedCoordsArray& coords,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001352 const TextureSamplerArray& samplers) {
joshualitt30ba4362014-08-21 20:18:45 -07001353 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001354 kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001355 "ImageIncrement");
joshualitt30ba4362014-08-21 20:18:45 -07001356 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001357 kFloat_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.com777c3aa2012-07-25 20:58:20 +00001358 "SurfaceScale");
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001359 fLight->emitLightColorUniform(builder);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001360 SkString lightFunc;
1361 this->emitLightFunc(builder, &lightFunc);
1362 static const GrGLShaderVar gSobelArgs[] = {
1363 GrGLShaderVar("a", kFloat_GrSLType),
1364 GrGLShaderVar("b", kFloat_GrSLType),
1365 GrGLShaderVar("c", kFloat_GrSLType),
1366 GrGLShaderVar("d", kFloat_GrSLType),
1367 GrGLShaderVar("e", kFloat_GrSLType),
1368 GrGLShaderVar("f", kFloat_GrSLType),
1369 GrGLShaderVar("scale", kFloat_GrSLType),
1370 };
1371 SkString sobelFuncName;
joshualitt15988992014-10-09 15:04:05 -07001372 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001373 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1374
1375 fsBuilder->emitFunction(kFloat_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001376 "sobel",
1377 SK_ARRAY_COUNT(gSobelArgs),
1378 gSobelArgs,
1379 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1380 &sobelFuncName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001381 static const GrGLShaderVar gPointToNormalArgs[] = {
1382 GrGLShaderVar("x", kFloat_GrSLType),
1383 GrGLShaderVar("y", kFloat_GrSLType),
1384 GrGLShaderVar("scale", kFloat_GrSLType),
1385 };
1386 SkString pointToNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001387 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001388 "pointToNormal",
1389 SK_ARRAY_COUNT(gPointToNormalArgs),
1390 gPointToNormalArgs,
1391 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1392 &pointToNormalName);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001393
1394 static const GrGLShaderVar gInteriorNormalArgs[] = {
1395 GrGLShaderVar("m", kFloat_GrSLType, 9),
1396 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1397 };
1398 SkString interiorNormalBody;
1399 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1400 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1401 "\t surfaceScale);\n",
1402 pointToNormalName.c_str(),
1403 sobelFuncName.c_str(),
1404 sobelFuncName.c_str());
1405 SkString interiorNormalName;
joshualitt30ba4362014-08-21 20:18:45 -07001406 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001407 "interiorNormal",
1408 SK_ARRAY_COUNT(gInteriorNormalArgs),
1409 gInteriorNormalArgs,
1410 interiorNormalBody.c_str(),
1411 &interiorNormalName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001412
joshualitt30ba4362014-08-21 20:18:45 -07001413 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1414 fsBuilder->codeAppend("\t\tfloat m[9];\n");
bsalomon@google.com032b2212012-07-16 13:36:18 +00001415
1416 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1417 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1418
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001419 int index = 0;
1420 for (int dy = -1; dy <= 1; dy++) {
1421 for (int dx = -1; dx <= 1; dx++) {
1422 SkString texCoords;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001423 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
joshualitt30ba4362014-08-21 20:18:45 -07001424 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1425 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1426 fsBuilder->codeAppend(".a;\n");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001427 }
1428 }
joshualitt30ba4362014-08-21 20:18:45 -07001429 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001430 SkString arg;
bsalomon@google.com032b2212012-07-16 13:36:18 +00001431 arg.appendf("%s * m[4]", surfScale);
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001432 fLight->emitSurfaceToLight(builder, arg.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001433 fsBuilder->codeAppend(";\n");
1434 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001435 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001436 fLight->emitLightColor(builder, "surfaceToLight");
joshualitt30ba4362014-08-21 20:18:45 -07001437 fsBuilder->codeAppend(");\n");
bsalomon@google.comf910d3b2013-03-07 17:06:57 +00001438 SkString modulate;
egdaniel089f8de2014-10-09 10:34:58 -07001439 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
joshualitt30ba4362014-08-21 20:18:45 -07001440 fsBuilder->codeAppend(modulate.c_str());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001441}
1442
joshualittb0a8a372014-09-23 09:50:21 -07001443void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1444 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
1445 b->add32(proc.cast<GrLightingEffect>().light()->type());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001446}
1447
kkinnunen7510b222014-07-30 00:04:16 -07001448void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001449 const GrProcessor& proc) {
1450 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
bsalomon@google.comc7818882013-03-20 19:19:53 +00001451 GrTexture* texture = lighting.texture(0);
senorblanco@chromium.orgef5dbe12013-01-28 16:42:38 +00001452 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
kkinnunen7510b222014-07-30 00:04:16 -07001453 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1454 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001455 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
kkinnunen7510b222014-07-30 00:04:16 -07001456 fLight->setData(pdman, transformedLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001457}
1458
1459///////////////////////////////////////////////////////////////////////////////
1460
1461///////////////////////////////////////////////////////////////////////////////
1462
joshualitteb2a6762014-12-04 11:35:33 -08001463GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc)
1464 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001465}
1466
joshualitt15988992014-10-09 15:04:05 -07001467void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001468 const char* kd;
joshualitt30ba4362014-08-21 20:18:45 -07001469 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001470 kFloat_GrSLType, kDefault_GrSLPrecision,
1471 "KD", &kd);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001472
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001473 static const GrGLShaderVar gLightArgs[] = {
1474 GrGLShaderVar("normal", kVec3f_GrSLType),
1475 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1476 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1477 };
1478 SkString lightBody;
1479 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1480 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
joshualitt30ba4362014-08-21 20:18:45 -07001481 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1482 "light",
1483 SK_ARRAY_COUNT(gLightArgs),
1484 gLightArgs,
1485 lightBody.c_str(),
1486 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001487}
1488
kkinnunen7510b222014-07-30 00:04:16 -07001489void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001490 const GrProcessor& proc) {
1491 INHERITED::setData(pdman, proc);
1492 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001493 pdman.set1f(fKDUni, diffuse.kd());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001494}
1495
1496///////////////////////////////////////////////////////////////////////////////
1497
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001498GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1499 const SkLight* light,
1500 SkScalar surfaceScale,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001501 const SkMatrix& matrix,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +00001502 SkScalar ks,
1503 SkScalar shininess)
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001504 : INHERITED(texture, light, surfaceScale, matrix),
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001505 fKS(ks),
1506 fShininess(shininess) {
joshualitteb2a6762014-12-04 11:35:33 -08001507 this->initClassID<GrSpecularLightingEffect>();
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001508}
1509
bsalomon0e08fc12014-10-15 08:19:04 -07001510bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
joshualitt49586be2014-09-16 08:21:41 -07001511 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
bsalomon@google.com68b58c92013-01-17 16:50:08 +00001512 return INHERITED::onIsEqual(sBase) &&
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001513 this->ks() == s.ks() &&
1514 this->shininess() == s.shininess();
1515}
1516
joshualitteb2a6762014-12-04 11:35:33 -08001517void GrSpecularLightingEffect::getGLProcessorKey(const GrGLCaps& caps,
1518 GrProcessorKeyBuilder* b) const {
1519 GrGLSpecularLightingEffect::GenKey(*this, caps, b);
1520}
1521
1522GrGLFragmentProcessor* GrSpecularLightingEffect::createGLInstance() const {
1523 return SkNEW_ARGS(GrGLSpecularLightingEffect, (*this));
1524}
1525
joshualittb0a8a372014-09-23 09:50:21 -07001526GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001527
joshualittb0a8a372014-09-23 09:50:21 -07001528GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1529 GrContext* context,
1530 const GrDrawTargetCaps&,
1531 GrTexture* textures[]) {
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001532 SkScalar surfaceScale = random->nextSScalar1();
1533 SkScalar ks = random->nextUScalar1();
1534 SkScalar shininess = random->nextUScalar1();
1535 SkAutoTUnref<SkLight> light(create_random_light(random));
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001536 SkMatrix matrix;
1537 for (int i = 0; i < 9; i++) {
1538 matrix[i] = random->nextUScalar1();
1539 }
joshualittb0a8a372014-09-23 09:50:21 -07001540 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001541 light, surfaceScale, matrix, ks, shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001542}
1543
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001544///////////////////////////////////////////////////////////////////////////////
1545
joshualitteb2a6762014-12-04 11:35:33 -08001546GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc)
1547 : INHERITED(proc) {
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001548}
1549
joshualitt15988992014-10-09 15:04:05 -07001550void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001551 const char* ks;
1552 const char* shininess;
1553
joshualitt30ba4362014-08-21 20:18:45 -07001554 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001555 kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks);
joshualitt30ba4362014-08-21 20:18:45 -07001556 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001557 kFloat_GrSLType, kDefault_GrSLPrecision, "Shininess", &shininess);
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001558
1559 static const GrGLShaderVar gLightArgs[] = {
1560 GrGLShaderVar("normal", kVec3f_GrSLType),
1561 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1562 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1563 };
1564 SkString lightBody;
1565 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1566 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
senorblanco@chromium.org7b734e02012-10-29 19:47:06 +00001567 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1568 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
joshualitt30ba4362014-08-21 20:18:45 -07001569 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1570 "light",
1571 SK_ARRAY_COUNT(gLightArgs),
1572 gLightArgs,
1573 lightBody.c_str(),
1574 funcName);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001575}
1576
kkinnunen7510b222014-07-30 00:04:16 -07001577void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001578 const GrProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -07001579 INHERITED::setData(pdman, effect);
1580 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
kkinnunen7510b222014-07-30 00:04:16 -07001581 pdman.set1f(fKSUni, spec.ks());
1582 pdman.set1f(fShininessUni, spec.shininess());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001583}
1584
1585///////////////////////////////////////////////////////////////////////////////
joshualitt15988992014-10-09 15:04:05 -07001586void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
joshualitt30ba4362014-08-21 20:18:45 -07001587 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001588 kVec3f_GrSLType, kDefault_GrSLPrecision,
1589 "LightColor");
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001590}
1591
joshualitt15988992014-10-09 15:04:05 -07001592void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001593 const char *surfaceToLight) {
joshualittb0a8a372014-09-23 09:50:21 -07001594 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001595}
1596
kkinnunen7510b222014-07-30 00:04:16 -07001597void GrGLLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001598 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001599 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001600}
1601
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001602///////////////////////////////////////////////////////////////////////////////
1603
kkinnunen7510b222014-07-30 00:04:16 -07001604void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001605 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001606 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001607 SkASSERT(light->type() == SkLight::kDistant_LightType);
1608 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001609 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001610}
1611
joshualitt15988992014-10-09 15:04:05 -07001612void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001613 const char* dir;
bsalomon422f56f2014-12-09 10:18:12 -08001614 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1615 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001616 "LightDirection", &dir);
joshualitt30ba4362014-08-21 20:18:45 -07001617 builder->getFragmentShaderBuilder()->codeAppend(dir);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001618}
1619
1620///////////////////////////////////////////////////////////////////////////////
1621
kkinnunen7510b222014-07-30 00:04:16 -07001622void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001623 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001624 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001625 SkASSERT(light->type() == SkLight::kPoint_LightType);
1626 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001627 setUniformPoint3(pdman, fLocationUni, pointLight->location());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001628}
1629
joshualitt15988992014-10-09 15:04:05 -07001630void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001631 const char* loc;
bsalomon422f56f2014-12-09 10:18:12 -08001632 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1633 kVec3f_GrSLType, kDefault_GrSLPrecision,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001634 "LightLocation", &loc);
joshualitt15988992014-10-09 15:04:05 -07001635 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001636 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1637 loc, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001638}
1639
1640///////////////////////////////////////////////////////////////////////////////
1641
kkinnunen7510b222014-07-30 00:04:16 -07001642void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001643 const SkLight* light) const {
kkinnunen7510b222014-07-30 00:04:16 -07001644 INHERITED::setData(pdman, light);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001645 SkASSERT(light->type() == SkLight::kSpot_LightType);
1646 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
kkinnunen7510b222014-07-30 00:04:16 -07001647 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1648 pdman.set1f(fExponentUni, spotLight->specularExponent());
1649 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1650 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1651 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1652 setUniformNormal3(pdman, fSUni, spotLight->s());
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001653}
1654
joshualitt15988992014-10-09 15:04:05 -07001655void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001656 const char* location;
joshualitt30ba4362014-08-21 20:18:45 -07001657 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001658 kVec3f_GrSLType, kDefault_GrSLPrecision,
1659 "LightLocation", &location);
joshualitt30ba4362014-08-21 20:18:45 -07001660
joshualitt15988992014-10-09 15:04:05 -07001661 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001662 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1663 location, fsBuilder->fragmentPosition(), z);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001664}
1665
joshualitt15988992014-10-09 15:04:05 -07001666void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001667 const char *surfaceToLight) {
1668
1669 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1670
1671 const char* exponent;
1672 const char* cosInner;
1673 const char* cosOuter;
1674 const char* coneScale;
1675 const char* s;
joshualitt30ba4362014-08-21 20:18:45 -07001676 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001677 kFloat_GrSLType, kDefault_GrSLPrecision,
1678 "Exponent", &exponent);
joshualitt30ba4362014-08-21 20:18:45 -07001679 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001680 kFloat_GrSLType, kDefault_GrSLPrecision,
1681 "CosInnerConeAngle", &cosInner);
joshualitt30ba4362014-08-21 20:18:45 -07001682 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001683 kFloat_GrSLType, kDefault_GrSLPrecision,
1684 "CosOuterConeAngle", &cosOuter);
joshualitt30ba4362014-08-21 20:18:45 -07001685 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001686 kFloat_GrSLType, kDefault_GrSLPrecision,
1687 "ConeScale", &coneScale);
joshualitt30ba4362014-08-21 20:18:45 -07001688 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001689 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s);
bsalomon@google.comae5ef112012-10-29 14:53:53 +00001690
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +00001691 static const GrGLShaderVar gLightColorArgs[] = {
1692 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1693 };
1694 SkString lightColorBody;
1695 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1696 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1697 lightColorBody.appendf("\t\treturn vec3(0);\n");
1698 lightColorBody.appendf("\t}\n");
1699 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1700 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1701 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1702 color, cosOuter, coneScale);
1703 lightColorBody.appendf("\t}\n");
1704 lightColorBody.appendf("\treturn %s;\n", color);
joshualitt15988992014-10-09 15:04:05 -07001705 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001706 fsBuilder->emitFunction(kVec3f_GrSLType,
commit-bot@chromium.org74a3a212013-08-30 19:43:59 +00001707 "lightColor",
1708 SK_ARRAY_COUNT(gLightColorArgs),
1709 gLightColorArgs,
1710 lightColorBody.c_str(),
1711 &fLightColorFunc);
skia.committer@gmail.come862d162012-10-31 02:01:18 +00001712
joshualitt30ba4362014-08-21 20:18:45 -07001713 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00001714}
1715
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001716#endif
1717
djsollen@google.com08337772012-06-26 14:33:13 +00001718SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1719 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1720 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
djsollen@google.com08337772012-06-26 14:33:13 +00001721SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END